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 + -
显示快捷键?