Version 2, last updated by Luke S at 17 Jan 01:37 UTC
Enemy Entity Design Ideas
Just some idea to simplify enemy entity coding. If you got any feedback please
#define DEATHLENGTH 480
#include <enemy>
/* Public Function */
// None
/* Local variable */
new HitCount;
new RandomDelay = 2000;
new LeapCount = 2000;
/* Display Object */
new body[EntityGraphic] = { NULLOBJECT, 0, 24, 0 }; // Display Object, Offset x, Offset y, Offset z
new head[EntityGraphic] = { NULLOBJECT, 0, 0, 1 }; // Display Object, Offset x, Offset y, Offset z
new object:shadow = NULLOBJECT;
/* Collisions Settings */
new hitzone[3][RECT] = {
{ 4, 28, 24, 24 }, // Body
{ -16, 16, 64, 56 }, // Attack Alert
{ 4, 28, 24, 16 }, // jumping body
};
START_SETUP
_speed_ = 50;
_damage_ = 50;
_health_ = _maxhealth_ = 100;
dw = dh = 32;
SetStateGraphic( STANDING, "enemy_bones01.png", "front_0", "side_0", "back_0", "side_0" );
SetStateGraphic( MOVING, "enemy_bones01.png", "front", "side", "back", "side" );
SetStateGraphic( LEAPING, "enemy_bones01.png", "stomp", "stomp", "stomp", "stomp" );
END_SETUP
/* Function */
public Init(...)
{
EnemyInit();
/* Retrive Display Objects */
body[egOBJ] = object:EntityGetNumber("object-id");
head[egOBJ] = ObjectCreate( "enemy_bones01.png:head_front", SPRITE, dx, dy, 4, 0, 0, WHITE );
shadow = ObjectCreate( "", CIRCLE, dx, dy+32, 2, 16, 8, 0x000000DD );
ShowObjects( head[egOBJ], body[egOBJ], shadow );
}
main()
{
if ( _state_ == GONE || GameState() != 1 )
return;
if ( StateChanged() )
{
ResetObjects( head[egOBJ], body[egOBJ] );
}
new q = (_state_ == LEAPING ? 2 : 0);
CollisionSet(SELF, 0, TYPE_ENEMY, dx + hitzone[q][rX], dy + hitzone[q][rY], hitzone[q][rW], hitzone[q][rH] );
CollisionSet(SELF, 1, TYPE_ENEMY, dx + hitzone[1][rX], dy + hitzone[1][rY], hitzone[1][rW], hitzone[1][rH] );
switch( _state_ )
{
case STANDING:
Stand();
case MOVING:
Move();
case LEAPING:
Leap();
case HIT:
Hurt();
case DYING:
HandleDying();
case SPECIALSTATE:
Special();
case DEAD:
{
HideObjects( head[egOBJ], body[egOBJ], shadow );
CollisionSet(SELF, -1, 0);
SetState(GONE);
return;
}
}
UpdateEntityGraphics( head );
UpdateEntityGraphics( body );
ObjectPosition( shadow, dx+4, dy+48, 2, 24, 8);
}
public Close()
{
CollisionSet(SELF, -1, 0);
ObjectDelete(shadow);
ObjectDelete(head[egOBJ]);
}
/* Local Function */
SetHeadDir(head_direction)
{
head_direction %= 8;
switch ( head_direction )
{
case 1:
ReplaceEntityGraphics( head, "enemy_bones01.png:head_side", false );
case 2:
ReplaceEntityGraphics( head, "enemy_bones01.png:head_front", false );
case 3:
ReplaceEntityGraphics( head, "enemy_bones01.png:head_side", true );
default:
ReplaceEntityGraphics( head, "enemy_bones01.png:head_front", false );
}
}
/* States */
STATEFUNCTION Move()
{
ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
SetHeadDir(_dir_);
if ( !random(30) ) // Change Direction
{
RandomizeMovement();
SetState(STANDING);
}
else
{
EntityMove( MASK_ENEMYSOLID2 );
}
}
STATEFUNCTION Leap()
{
ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
EntityMove( MASK_ENEMYSOLID2 );
if ( Countdown(LeapCount) ) // Check the hit counter
{
SetState(STANDING);
RandomizeMovement();
CheckHealth();
}
}
STATEFUNCTION Stand()
{
ReplaceEntityGraphics( body, STATE_GRAPHIC, STATE_FLIP );
if ( !random(8) ) // 1 in 8 change to look around
{
new head_direction = _dir_;
if ( random(2) )
head_direction+=2;
else
head_direction-=2;
SetHeadDir(head_direction);
}
if ( !random(60) ) // Start Moving Again
{
_angle_ = Dir2Angle(random(8));
SetState(MOVING);
}
}
STATEFUNCTION Hurt()
{
CollisionSet(SELF, -1, 0);
EntityMove(MASK_ENEMYSOLID2);
new q = (HitCount % 100) / 20;
ColourEntityGraphics(body, hit_colours[q]);
ColourEntityGraphics(head, hit_colours[q]);
EntityMove( MASK_ENEMYSOLID2 );
if ( Countdown(HitCount) ) // Check the hit counter
{
SetState(MOVING);
RandomizeMovement();
CheckHealth();
}
}
STATEFUNCTION Special()
{
switch ( current_effect )
{
case STUNNED:
{
StunnedEffect( effect_count );
ReplaceEntityGraphics( body, "enemy_bones01.png:front_0", false );
}
case FROZEN:
{
ReplaceEntityGraphics( body, "enemy_bones01.png:front_0", false );
ColourEntityGraphics( body, 0x0000FFFF);
}
case SHOCKED:
{
}
case BURNING:
{
}
default:
{
SetState(STANDING);
return;
}
}
if ( Countdown(effect_count) ) //Reset State
{
SetState(STANDING);
}
}
/* Public Functions */
PUBLICFUNCTIONHIT
{
if ( _state_ == HIT || _state_ == DYING || _state_ == GONE )
return;
strcopy( _attacker_, attacker );
if ( attack&APLAYER == APLAYER )
{
EntityPublicFunction( _attacker_, "Hurt", "nnn", ASWORD, _damage_, angle );
}
else if ( _state_ != HIT)
{
if ( rect == 1 )
{
_angle_ = fatan2(fixed:(x-dx), fixed:(y-dy), degrees);
SetState(LEAPING);
LeapCount = 2000;
}
else
{
AudioPlaySound( "enemy_hurt.wav", dx, dy );
_state_ = HIT;
_health_ -= damage;
HitCount = 1000;
//_angle_ = fatan2(fixed:(dx-x), fixed:(dy-y), degrees);
Hurt();
}
}
CheckHealth();
}