⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tank.cpp.svn-base

📁 坦克大战游戏完整全套源代码
💻 SVN-BASE
📖 第 1 页 / 共 2 页
字号:
#pragma warning(disable: 4996)

#include <cstdio>
#include <hge.h>

#include "tank.h"
#include "weapon.h"
#include "cannonBall.h"
#include "bullet.h"
#include "explosive.h"
#include "cooldownIcon.h"
#include "common/graphicEntity.h"
#include "common/entityManager.h"
#include "common/soundManager.h"

#define Pi Pi()

Tank::Tank(cAni::iAnimResManager &arm, hgeFont *font) :
    Entity(),
    fDirection(0.f), fSpeed(100.f), mMoveStatus(0), mAttackStatus(0), fGunDirection(0.f),
    mBarbette(NULL), mCannon(NULL), mGunBarbette(NULL), mGun(NULL),
    collisionEntity(*this),
    controlEntity(*this),
    graphicEntity(*this, arm, font),
    viewerEntity(*this),
    radarEntity(*this),
    targetEntity(*this),
    gunAttacheeEntity(*this),
    cannonAttacheeEntity(*this),
    bShowAim(false),
    bAmphibious(false),
    state(TS_Alive)
{
    fHealth = 100;
    fArmor = 100;
    turnDirection = 0;
    fCurSpeed = 0;
}

Tank::~Tank()
{
    if (mCannon)
        delete mCannon;
    if (mGun)
        delete mGun;
    if (mBarbette)
        delete mBarbette;
    if (mGunBarbette)
        delete mGunBarbette;
}

void Tank::Fire() // 主炮 开火
{
    if (mCannon == NULL || !mCannon->isReadyToFire())
        return;

    mCannon->fire();
    
    SoundManager::getSingleton().play("data/se/tk_expb.WAV", pos);

    CannonBall *pBall = new CannonBall(this->graphicEntity.animResManager);
    EntityManager::getSingleton().attach(pBall);
    assert(pBall != NULL);

    ((iCollisionEntity*)pBall->getEntityInterface(EII_CollisionEntity))->addIgnoredEntities(*(iCollisionEntity*)this->getEntityInterface(EII_CollisionEntity));
    float rad = (mBarbette ? mBarbette->getDirection() : this->getDirection()) / 180.f * Pi;
    float off = (((float)rand() / RAND_MAX) - 0.5f) * atan(mCannon->getWeapon().fDefinition);
    rad += off;
    pBall->orientation = rad;
    Point2f dir0 = Point2f(cosf(rad), sinf(rad));
    float fShootRange = mCannon->getWeapon().fShootRange;
    if (mBarbette)
    {
        float attackDistance = (mBarbette->getAttackPos() - pos).Length();
        if (attackDistance <= fShootRange)
            fShootRange = attackDistance;
    }
    Point2f dir = dir0 * fShootRange;
    pBall->setPostion(pos/* + dir0 * getSize() * 1.5*/, pos + dir);
    pBall->cannon = (const Cannon *)&mCannon->getWeapon();
    pBall->speed = mCannon->getWeapon().fMuzzleVelocity;
}

void Tank::Shoot()// 机枪 开火
{
    if (mGun == NULL || !mGun->isReadyToFire())
        return;

    mGun->fire();
    SoundManager::getSingleton().play("data/se/tk_fire.WAV", pos, 0.2f);

    Bullet *pBall = new Bullet(this->graphicEntity.animResManager);
    EntityManager::getSingleton().attach(pBall);
    assert(pBall != NULL);

    ((iCollisionEntity*)pBall->getEntityInterface(EII_CollisionEntity))->addIgnoredEntities(*(iCollisionEntity*)this->getEntityInterface(EII_CollisionEntity));
    float rad = (mGunBarbette ? mGunBarbette->getDirection() : this->getDirection()) / 180.f * Pi;
    float off = (((float)rand() / RAND_MAX) - 0.5f) * atan(mGun->getWeapon().fDefinition);
    rad += off;
    pBall->orientation = rad;
    Point2f dir0 = Point2f(cosf(rad), sinf(rad));

    float fShootRange = mGun->getWeapon().fShootRange;
    if (mGunBarbette)
    {
        float attackDistance = (mGunBarbette->getAttackPos() - pos).Length();
        if (attackDistance <= fShootRange)
            fShootRange = attackDistance;
    }
    Point2f dir = dir0 * fShootRange;
    pBall->setPostion(pos/* + dir0 * getSize() * 1.5*/, pos + dir);
    pBall->gun = (const Gun *)&mGun->getWeapon();
    pBall->speed = mCannon->getWeapon().fMuzzleVelocity;
}

void Tank::step(float gameTime, float deltaTime)
{
    switch(state)
    {
    case TS_Alive:
        {
            // cool down
            if (this->mCannon)
                this->mCannon->step(gameTime, deltaTime);
            if (this->mGun)
                this->mGun->step(gameTime, deltaTime);

            assert(fDirection >= 0 && fDirection <= 360);
            float rad = fDirection / 180.f * Pi;
            float speed = fSpeed;
            if (this->mMoveStatus & MS_HalfEnginePower)
                speed *= 0.5f;

            // speed up and down
            const float fEpsilon = 100.f * deltaTime;
            const float fHalfEpsilon = fEpsilon * 0.5f;
            if (mMoveStatus & (MS_UP|MS_DOWN))
            {
                if (fCurSpeed < speed - fHalfEpsilon)
                {
                    fCurSpeed += fEpsilon;
                    if (fCurSpeed > speed - fEpsilon)
                    {
                        fCurSpeed = speed;
                    }
                }
                else if (fCurSpeed > speed + fHalfEpsilon)
                {
                    fCurSpeed -= fEpsilon;
                    if (fCurSpeed < speed + fEpsilon)
                    {
                        fCurSpeed = speed;
                    }
                }
            }
            else
            {
                fCurSpeed -= fEpsilon;
                if (fCurSpeed < fEpsilon)
                    fCurSpeed = 0;
            }

            const Point2f dir = Point2f(cosf(rad), sinf(rad)) * (deltaTime);
            Point2f newPos = pos;
            if ((mMoveStatus & (MS_UP|MS_DOWN)) == MS_UP)
            {
                newPos += dir * fCurSpeed;
            }
            else if ((mMoveStatus & (MS_UP|MS_DOWN)) == MS_DOWN)
            {
                newPos -= dir * fCurSpeed;
            }
            if (setTurnDirection)
            {
                float diffDir = fabs(turnDirection - fDirection);
                diffDir -= int(diffDir / 360) * 360.f;
                if (diffDir > 1.f)
                {
                    float radTD = turnDirection / 180.f * Pi;
                    Point2f dir2(cos(radTD), sin(radTD));
                    float d = dir ^ dir2;
                    if (d < 0)
                    {
                        this->AddMoveStatus(MS_LEFT);
                        this->RemoveMoveStatus(MS_RIGHT);
                    }
                    else if (d > 0)
                    {
                        this->AddMoveStatus(MS_RIGHT);
                        this->RemoveMoveStatus(MS_LEFT);
                    }
                }
                else
                {
                    setTurnDirection = false;
                    this->RemoveMoveStatus(MS_RIGHT);
                    this->RemoveMoveStatus(MS_LEFT);
                }
            }

            if ((mMoveStatus & (MS_LEFT|MS_RIGHT)) == MS_LEFT)
            {
                fDirection -= 50 * deltaTime;
                if (fDirection < 0)
                    fDirection += 360;
            }
            else if ((mMoveStatus & (MS_LEFT|MS_RIGHT)) == MS_RIGHT)
            {
                fDirection += 50 * deltaTime;
                if (fDirection >= 360)
                    fDirection -= 360;
            }

            if (mAttackStatus & AS_Cannon)
                Fire();
            if (mAttackStatus & AS_Gun)
                Shoot();

            if (mBarbette)
            {
                mBarbette->step(gameTime, deltaTime);
            }
            if (mGunBarbette)
            {
                mGunBarbette->step(gameTime, deltaTime);
            }
            collisionEntity.getBody().Reset(pos, getDirection() / 180.f * Pi, 1);
            Point2f vel = (newPos - pos) / deltaTime;
            collisionEntity.getBody().setVelocity(vel);
            collisionEntity.getBody().Update(deltaTime);
            // pos = (newPos); // here may touch the obstacles, and not move to the exact newPos
            if (mBarbette)
                mBarbette->setCenterPos(pos);
            if (mGunBarbette)
                mGunBarbette->setCenterPos(pos);
        }
        break;
    case TS_Dead:
        if (graphicEntity.checkExplodeSmokeEnd(gameTime))
        {
            active = false;
        }
        break;
    }
}

void Tank::damage(float fDamage, int nPenetrability)
{
    if (fDamage <= 1e-2f)
        return;

    assert(fDamage >= 0 && fDamage < 1e10);
    assert(nPenetrability >= 0 && nPenetrability <= 100);
    const float actualDamage = fDamage * fDamage / (fDamage + fArmor);
    assert(actualDamage >= 0 && actualDamage < 1e10);
    float fPenetrability = 0.01f * nPenetrability;
    if (fPenetrability > 1.f)
        fPenetrability = 1.f;
    const float armorDamage = actualDamage * (1.f - fPenetrability);
    float restDamage = actualDamage - armorDamage;
    if (fArmor >= armorDamage)
        fArmor -= armorDamage;
    else
    {
        restDamage += armorDamage - fArmor;
        fArmor = 0;
    }
    fHealth -= restDamage;
    if (fHealth <= 0)
    {
        fHealth = 0;
        
        state = TS_Dead;
        graphicEntity.playSmoke();
        // this->active = false;
    }
}

void Tank::ControlEntity::onControllerCommand(int command, const void *pData)
{
    switch(command)
    {
    case TCI_TurnLeft:
        if (getTank().setTurnDirection)
        {
            getTank().RemoveMoveStatus(MS_LEFT);
            getTank().RemoveMoveStatus(MS_RIGHT);
            getTank().setTurnDirection = false;
        }

        pData ? getTank().AddMoveStatus(MS_LEFT) : getTank().RemoveMoveStatus(MS_LEFT);
        break;
    case TCI_TurnRight:
        if (getTank().setTurnDirection)
        {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -