enemy.cpp
来自「一个symbian 冒险游戏代码」· C++ 代码 · 共 1,167 行 · 第 1/4 页
CPP
1,167 行
#include "Enemy.h"
#include "Map.h"
#include "GameApp.h"
#include "ImageResample.h"
#include <io/InputStream.h>
#include <io/OutputStream.h>
#include <lang/Exception.h>
#include <string.h>
#include <stdlib.h>
#include <config.h>
using namespace io;
using namespace lang;
static const char* const TYPE_NAMES[] =
{
"NONE",
"GHOUL",
"OGRE",
"HELLBEAST",
"COUNT"
};
Enemy::Enemy() :
MapObject( "Enemy" ),
m_time( 0 ),
m_dirChangeTime( 0 ),
m_attackDamage( 0 ),
m_attackSkill( 0 ),
m_aggression( 0 ),
m_cowardness( 0 ),
m_collisionCount( 0 ),
m_state( BODY_IDLE ),
m_type( ENEMY_NONE ),
m_behavior( BEHAVIOR_PATROL ),
m_attackRange( Fixf(75) ),
m_attackAngle( Fixf(0.7) ),
m_attackTime( Fixf(0) ),
m_backUpTime( Fixf(0) ),
m_waitTime( Fixf(0) ),
m_sinceRunningTime( Fixf(0) ),
m_attackCounter( 0 ),
m_attackHitCounter( 0 ),
m_hitPointMarker( -1 ),
m_combatGreen( true )
{
m_animationSwitchBoard[ BODY_IDLE ] = ANIM_IDLE;
m_animationSwitchBoard[ BODY_RUN ] = ANIM_RUN;
m_animationSwitchBoard[ BODY_ATTACK ] = ANIM_ATTACK;
m_animationSwitchBoard[ BODY_BACKUP ] = ANIM_RUN;
m_animationSwitchBoard[ BODY_HIT ] = ANIM_HIT;
m_animationSwitchBoard[ BODY_DEATH ] = ANIM_DEATH;
m_animationSwitchBoard[ BODY_DEAD ] = ANIM_DEATH;
}
Enemy::~Enemy()
{
}
void Enemy::read( io::InputStream* in )
{
MapObject::read( in );
char* begin = (char*) &Enemy_storeStart;
char* end = (char*) &Enemy_storeEnd;
in->read( begin, end-begin );
}
void Enemy::write( io::OutputStream* out )
{
MapObject::write( out );
char* begin = (char*) &Enemy_storeStart;
char* end = (char*) &Enemy_storeEnd;
out->write( begin, end-begin );
}
void Enemy::update( Fix dt )
{
if ( m_hitPointMarker < 0 ) m_hitPointMarker = m_hitpoints.toInt();
m_time += dt;
if ( m_time < Fix(0) )
m_time = Fix(0);
if ( ( BODY_DEATH != m_state ) && ( BODY_DEAD != m_state ) )
{
switch ( m_behavior )
{
case BEHAVIOR_DISABLED:
break;
case BEHAVIOR_PATROL:
behaviorPatrol( dt );
break;
case BEHAVIOR_COMBAT:
behaviorCombat( dt );
break;
case BEHAVIOR_FLEE:
behaviorFlee( dt );
break;
}
}
switch ( state() )
{
case BODY_IDLE:
updateWait( dt );
break;
case BODY_RUN:
updateRun( dt );
break;
case BODY_ATTACK:
updateAttack( dt );
break;
case BODY_BACKUP:
updateBackUp( dt );
break;
case BODY_HIT:
updateHit( dt );
break;
case BODY_DEATH:
updateDeath( dt );
break;
case BODY_DEAD:
break;
case BODY_COUNT:
assert( false );
break;
}
}
void Enemy::setBehavior( Behavior behavior )
{
if ( behavior != m_behavior )
{
switch ( m_type )
{
case ENEMY_NONE:
case ENEMY_COUNT:
break;
case ENEMY_GHOUL:
switch ( behavior )
{
case BEHAVIOR_DISABLED:
case BEHAVIOR_PATROL:
break;
case BEHAVIOR_COMBAT:
resetStatisticsCombat();
GameApp::get()->playSound( "enemy_combat", SoundContext::CHANNEL_OTHER );
break;
case BEHAVIOR_FLEE:
resetStatisticsFlee();
GameApp::get()->playSound( "enemy_flee", SoundContext::CHANNEL_OTHER );
break;
}
break;
case ENEMY_OGRE:
switch ( behavior )
{
case BEHAVIOR_DISABLED:
case BEHAVIOR_PATROL:
break;
case BEHAVIOR_COMBAT:
resetStatisticsCombat();
GameApp::get()->playSound( "enemy_combat", SoundContext::CHANNEL_OTHER );
break;
case BEHAVIOR_FLEE:
resetStatisticsFlee();
GameApp::get()->playSound( "enemy_flee", SoundContext::CHANNEL_OTHER );
break;
}
break;
case ENEMY_HELLBEAST:
switch ( behavior )
{
case BEHAVIOR_DISABLED:
case BEHAVIOR_PATROL:
break;
case BEHAVIOR_COMBAT:
resetStatisticsCombat( false );
GameApp::get()->playSound( "enemy_combat", SoundContext::CHANNEL_OTHER );
break;
case BEHAVIOR_FLEE:
resetStatisticsFlee();
GameApp::get()->playSound( "enemy_flee", SoundContext::CHANNEL_OTHER );
break;
}
break;
}
m_behavior = behavior;
}
}
void Enemy::behaviorPatrol( Fix /*dt*/ )
{
MapObject* target = m_map->player();
FixVec2 dirv = target->position() - position();
const int distanceThreshold = m_aggression.toInt() << 1;
int distanceSqr = dirv.dot( dirv ).toInt();
if ( !target->isDead() && ( distanceSqr < ( distanceThreshold * distanceThreshold ) ) )
{
setBehavior( BEHAVIOR_COMBAT );
}
}
void Enemy::behaviorCombat( Fix dt )
{
MapObject* target = m_map->player();
FixVec2 dirv = target->position() - position();
// update direction
m_dirChangeTime -= dt;
if ( m_dirChangeTime < Fixf(0) )
{
Dir dir = getATanAsDir( dirv );
setDirection( dir );
m_dirChangeTime = Fixf(1);
}
if ( isInterruptable() )
{
// update movement
if ( m_backUpTime > Fixf(0) )
{
// back up
backUp();
}
else if ( m_waitTime > Fixf(0) )
{
// wait
wait();
}
else
{
// decide maneuver
//-------
const int aggressionFactor = m_aggression.toInt() >> 4;
const int cowardnessFactor = m_cowardness.toInt() >> 4;
int attackDistance = m_attackRange.toInt() - aggressionFactor - 5;
if ( attackDistance < 10 ) attackDistance = 10;
const int attackThreshold = attackDistance;
const int hesitationThreshold = attackDistance + ( attackDistance >> 1 ) + cowardnessFactor;
Fix runDelay = ( Fixf(200) - m_aggression ) * Fixf(0.005) + Fixf(0.25);
if ( runDelay < Fixf(0.25) ) runDelay = Fixf(0.25);
int distanceSqr = dirv.dot( dirv ).toInt();
if ( m_combatGreen && ( distanceSqr < ( hesitationThreshold * hesitationThreshold ) ) )
{
// combat green enemy passes distance threshold => hesitate
m_waitTime = ( Fixf(200) - m_aggression ) * Fixf(0.025);
if ( m_waitTime < Fixf(0) ) m_waitTime = Fixf(0);
m_combatGreen = false;
}
else if ( distanceSqr > ( attackThreshold * attackThreshold ) )
{
// target far
if ( ( m_state == BODY_RUN ) || ( m_time > runDelay ) )
{
// run delay exceeded => run toward target
run();
}
else
{
// run delay
wait();
}
}
else
{
// target near => consider attack
//-------
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?