📄 tank.cpp.svn-base
字号:
#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 + -