📄 tbadguy.cpp
字号:
// Copyright 2002 Kenneth Guy,
//
// TBadGuy.cpp
/** \file TBadGuy.cpp
implementation of class TBadGuy */
#include "TBadGuy.h"
#include "TPlayersShip.h"
#include "TBullet.h"
#include "CGame.h"
#include "TGamePanics.h"
#include "TMapLineType.h"
#include "TPathLineType.h"
/** Constructor */
TBadGuy::TBadGuy() {
}
/** Initialize a new bad guy from map data
\param aType type of map line data, see #TMapLineType
\param aArgs[0] sprite number of bad guy
\param aArgs[1] initial X position of bad guy
\param aArgs[2] initial Y position of bad guy
\param aArgs[3] Health of bad guy
\param aArgs[4] XVel or first path command for EPathMove bad guys
\param aArgs[5] YVel
\param aArgs[6] BonusType for collectable bad guys or iId for multi part bad guys
*/
void TBadGuy::Init(TInt16 aType,const TInt16 aArgs[]) {
SetSpriteNo(aArgs[0]);
iX=aArgs[1];
iY=aArgs[2];
iHealth=aArgs[3];
iXVel=0;
iYVel=aArgs[5];
iFlags=0;
iPath=0;
iId=0;
iCounter=0;
if(aType & EMapLineObjectMovementMapRelative) {
iFlags |= TBadGuyFlags::EMapRelative;
}
if(aType & EMapLineObjectMovementSimple) {
iXVel=aArgs[4];
iFlags |= TBadGuyFlags::ESimpleMoves;
if(aType & EMapLineObjectMovementBounceTop)
iFlags |= TBadGuyFlags::EBounceTop;
if(aType & EMapLineObjectMovementBounceBottom)
iFlags |= TBadGuyFlags::EBounceBottom;
if(aType & EMapLineObjectMovementBounceLeft)
iFlags |= TBadGuyFlags::EBounceLeft;
if(aType & EMapLineObjectMovementBounceRight)
iFlags |= TBadGuyFlags::EBounceRight;
} else if(aType & EMapLineObjectMovementHoming) {
iXVel=aArgs[4];
iFlags |= TBadGuyFlags::ESimpleMoves;
if(aType & EMapLineObjectMovementHomingX)
iFlags |= TBadGuyFlags::EHomingX;
if(aType & EMapLineObjectMovementHomingY)
iFlags |= TBadGuyFlags::EHomingY;
} else if(aType & EMapLineObjectMovementPath) {
iPath=aArgs[4];
iXVel=0;
iFlags |= TBadGuyFlags::EPathMove;
}
if(aType & EMapLineObjectBadGuy) {
iScore=20;
iFlags |= TBadGuyFlags::EKillsPlayer;
iId=aArgs[6];
// negative health means that this item can't be destroyed
// (or is destroyed by shooting something else)
if(iHealth < 0) {
iHealth=-iHealth;
iFlags |= TBadGuyFlags::EInvunerable;
}
} else if(aType & EMapLineObjectCollectable) {
iFlags |= TBadGuyFlags::ETransparent;
// gives player health, bullets don't effect it,
// simple movement,
if(aArgs[6]==0)
iFlags |= TBadGuyFlags::EHealthBonus;
else if(aArgs[6]==1)
iFlags |= TBadGuyFlags::ELifeBonus;
else if(aArgs[6]==2)
iFlags |= TBadGuyFlags::EWeaponBonus;
}
}
/** Move a bad guy.
This either moves the bad guy, or animates the explosion if the
bad guy is dieing.
\param aPlayerX X position of player for homing bad guys
\param aPlayerY Y position of player for homing bad guys
\param aPaths path data for path following bad guys
\param aGame used to add new lives/ bad guys etc
If the bad guy ends up outside the screen area the bad guy
is cleared.
For simple bad guys this just works out the new position
from the current X,Y, velocitys and for homing the players position.
For path following bad guys is executes all the path commands from
iPath that are settings type commands (set health/ set sprite no etc.)
then executes one movement type command (move to X,Y etc).
A simple path would be:
\verbatim
EPathLineMoveTo,1,270,0, // move to 270,0
EPathLineSetVelocity,1,2,2, // iXVel=2 iYVel=2
EPathLineMoveStepTo,1,30,0, // move to 30,0 in steps of iXVel
EPathLineMoveStepTo,1,30,90, // move to 30,90 in steps of iYVel
EPathLineSetClearFlags,1, TBadGuyFlags::EHomingX | // set homing flags
TBadGuyFlags::EHomingY, 0,
EPathLineMoveSimple,0,0,0, // repeat homing forever (next offset=0)
\endverbatim
An animated bouncing bad guy would be:
\verbatim
// path offset 64
// set up velocity and bouncing
EPathLineSetVelocity,1,1,1,
EPathLineSetClearFlags,1, TBadGuyFlags::EBounceTop |
TBadGuyFlags::EBounceBottom |
TBadGuyFlags::EBounceLeft |
TBadGuyFlags::EBounceRight, 0,
// loop bouncing and changing sprites
EPathLineSetSprite,1,16,0, // set sprite to 16
EPathLineMoveSimple,1,0,0, // move a bit
EPathLineMoveSimple,1,0,0,
EPathLineSetSprite,1,31,0, // set sprite to 31
EPathLineMoveSimple,1,0,0, // move a bit
EPathLineMoveSimple,1,0,0,
EPathLineSetSprite,1,32,0, // etc.
EPathLineMoveSimple,1,0,0,
EPathLineMoveSimple,1,0,0,
EPathLineSetSprite,1,33,0,
EPathLineMoveSimple,1,0,0,
EPathLineMoveSimple,1,0,0,
EPathLineMoveSimple,1,0,0, // etc.
EPathLineSetSprite,1,32,0,
EPathLineMoveSimple,1,0,0,
EPathLineSetSprite,1,31,0,
EPathLineMoveSimple,1,0,0,
EPathLineMoveSimple,-17,0,0, // move and jump back to set sprite to 16 line
\endverbatim
*/
void TBadGuy::Move(TInt aPlayerX, TInt aPlayerY,
const TInt16 *aPaths,CGame &aGame) {
// something that is dieing no movement just an explosion
if(iHealth <= 0) {
iHealth--;
TInt16 spriteno= -(iHealth/2);
spriteno+= aGame.FirstExplosionSprite();
if(spriteno>aGame.LastExplosionSprite())
ClearSprite();
else
SetSpriteNo(spriteno);
// things that just keep going in one direction, maybe bounce and maybe home
} else if(iFlags & TBadGuyFlags::ESimpleMoves) {
SimpleMove(aPlayerX,aPlayerY);
// things that follow a path
} else if(iFlags & TBadGuyFlags::EPathMove) {
PathMove(aPlayerX,aPlayerY,aPaths,aGame);
}
// if moving relative to the map then add the map velocity
if(iFlags & TBadGuyFlags::EMapRelative) {
iX+=aGame.MapSpeed();
}
// if the bad guy ends up off the sides of the offscreen map
if(iY<-24 || iY>200 || iX<0 || iX>336) {
ClearSprite();
}
}
/** Bad Guys that follow paths.
\param aPlayerX players position for homing bad commands
\param aPlayerY players position for homing bad commands
\param aPaths path commands
\param aGame for adding bad guys and points
see Move() and #TPathLineType for details of path commands.
*/
void TBadGuy::PathMove(TInt16 aPlayerX, TInt16 aPlayerY,
const TInt16 *aPaths, CGame &aGame) {
TBool foundMove=EFalse;
// continue processing path commands until we hit a move command
while(foundMove==EFalse) {
// casting it to TPathLineType enum means we get warnings if
// the switch statement doesn't handle one of the enum values.
switch((TPathLineType) (aPaths[iPath*4])) {
case EPathLineEnd:
// do nothing except exit, really only a marker for level generation tool
foundMove=ETrue;
break;
case EPathLineStart: // really only a marker for level generation tool
iPath+=aPaths[(iPath*4)+1];
break;
case EPathLineClone:
{
// other bad guy continues on path from arg 2
// this bad guy continues on path from arg 1
TInt oldpath=iPath+aPaths[(iPath*4)+1];
// set iPath for cloned bad guy
iPath+=aPaths[(iPath*4)+2];
aGame.AddBadGuy(*this);
// now set iPath back for this bad guy
iPath=oldpath;
}
break;
//movement
case EPathLineMoveBy:
iX+=aPaths[(iPath*4)+2];
iY+=aPaths[(iPath*4)+3];
iPath+=aPaths[(iPath*4)+1];
foundMove=ETrue;
break;
case EPathLineMoveTo:
iX=aPaths[(iPath*4)+2];
iY=aPaths[(iPath*4)+3];
iPath+=aPaths[(iPath*4)+1];
foundMove=ETrue;
break;
case EPathLineMoveStepTo: {
if(iX < aPaths[(iPath*4)+2]) {
iX += iXVel;
// check we don't overshoot
if(iX > aPaths[(iPath*4)+2])
iX=aPaths[(iPath*4)+2];
} else if(iX > aPaths[(iPath*4)+2]) {
iX -= iXVel;
// check we don't overshoot
if(iX < aPaths[(iPath*4)+2])
iX=aPaths[(iPath*4)+2];
}
if(iY < aPaths[(iPath*4)+3]) {
iY += iYVel;
// check we don't overshoot
if(iY > aPaths[(iPath*4)+3])
iY=aPaths[(iPath*4)+3];
} else if(iY > aPaths[(iPath*4)+3]) {
iY -= iYVel;
// check we don't overshoot
if(iY < aPaths[(iPath*4)+3])
iY=aPaths[(iPath*4)+3];
}
// stay on this command until we get to where we are going
if(iX == aPaths[(iPath*4)+2] &&
iY == aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+1];
}
foundMove=ETrue;
break;
}
case EPathLineMoveSimple:
SimpleMove(aPlayerX,aPlayerY);
iPath+=aPaths[(iPath*4)+1];
foundMove=ETrue;
break;
// conditionals
case EPathLineIfXVelLess:
if(iXVel < aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
} else {
iPath+=aPaths[(iPath*4)+1];
}
break;
case EPathLineIfXVelGreater:
if(iXVel > aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
} else {
iPath+=aPaths[(iPath*4)+1];
}
break;
case EPathLineIfXVelEqual:
if(iXVel == aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
} else {
iPath+=aPaths[(iPath*4)+1];
}
break;
case EPathLineIfYVelLess:
if(iYVel < aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
} else {
iPath+=aPaths[(iPath*4)+1];
}
break;
case EPathLineIfYVelGreater:
if(iYVel > aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
} else {
iPath+=aPaths[(iPath*4)+1];
}
break;
case EPathLineIfYVelEqual:
if(iYVel == aPaths[(iPath*4)+3]) {
iPath+=aPaths[(iPath*4)+2];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -