⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 monster.cpp

📁 吃豆子游戏源码
💻 CPP
字号:
/**
 *	File	:	Monster.cpp
 *  Author	:	Kevin Lynx
 *	Date	:	2007/7/31
 */

#include "stdafx.h"
#include "Monster.h"
#include "Player.h"
#include "World.h"
#include "AnimManager.h"
#include "Bullet.h"
#include "App.h"
#include "Bonus.h"

Monster::Monster( int monsterType ) :
	Sprite( monsterType, 3 )
{
}

Monster::~Monster()
{
}

bool	Monster::init( ISceneManager *smgr, IAnimatedMesh *mesh, ITexture *texture )
{
	if( !Sprite::init( smgr, mesh, texture ) )
	{
		return false;
	}

	/// init the animation
	if( mType == World::MONSTER_2 )
	{
		mAnimMgr->addState( AS_NORMAL, 0, 123, 50, true );
		mAnimMgr->addState( AS_RUN, 124, 247, 100, true );
	}
	if( mType == World::MONSTER_3 )
	{
		mAnimMgr->addState( AS_NORMAL, 0, 123, 50, true );
		mAnimMgr->addState( AS_RUN, 124, 247, 100, true );
	}
	if( mType == World::MONSTER_4 )
	{
		mAnimMgr->addState( AS_NORMAL, 0, 247, 50, true );
		mAnimMgr->addState( AS_RUN, 248, 371, 100, true );
	}
	
	mAnimMgr->setCurrentState( AS_RUN );

	initDirection();

	/// init the status
	mStatus = SpriteStatus::NORMAL;

	/// hp
	mHP = getInitHP( mType );
	/// add score
	mAddScore = getInitScore( mType );

	return true;
}

void	Monster::update( float dt )
{
	int lastStatus = mStatus;

	/// deal with the status
	if( mStatus != SpriteStatus::NORMAL )
	{
		if( SpriteStatus::update( mType ) )
		{
			mNode->setVisible( true );//normal
		}
	}
	if( lastStatus == SpriteStatus::DEAD &&
		mStatus != SpriteStatus::DEAD )
	{
		/// born, set a new position
		float x, y, z;
		y = 30;
		World::GetSingletonPtr()->getValidPos( x, z );
		this->setPosition( vector3df( x, y, z ) );
	}

	if( mStatus == SpriteStatus::DEAD )
	{
		return ;
	}
	if( mStatus == SpriteStatus::BORN_HIDE &&
		mNode->isVisible() )
	{
		mNode->setVisible( false );
	}
	if( mStatus == SpriteStatus::BORN_SHOW &&
		!mNode->isVisible() )
	{
		mNode->setVisible( true );
	}


	vector3df lastDir = mDir;

	if( mType == World::MONSTER_2 ||
		mType == World::MONSTER_4 )
	{
		ai1();
	}
	if( mType == World::MONSTER_3 )
	{
		ai2();
	}

	/// rotate the monster if the direction is different from the last dir
	if( mDir != lastDir )
	{
		rotate( mDir );
	}

	Sprite::move( dt );

	/// check whether it can fire
	if( canFire() )
	{
		BulletManager::GetSingletonPtr()->createMonsterBullet(
			mNode->getPosition(), mDir );

		mLastFireTime = App::GetSingletonPtr()->getRealTime(); 
	}
}

void	Monster::ai1()
{
	if( ( this->getArrayPos() == mLastArrayPos ||
		!World::GetSingletonPtr()->isCenterPos( mNode->getPosition() ) ) &&
		mDir != vector3df( 0, 0, 0 ) )
	{
		return ;
	}

	vector3df lastDir = mDir;

	Player *player = Player::GetSingletonPtr();
	World *world = World::GetSingletonPtr();

	int pax, paz, ax, az;

	player->getArrayPos( pax, paz );
	this->getArrayPos( ax, az );

	int h_dir = pax - ax == 0 ? 0 : ( pax - ax ) / abs( pax - ax );
	int v_dir = paz - az == 0 ? 0 : ( paz - az ) / abs( paz - az );

	if( h_dir == 0 && v_dir == 0 )
	{
		/// and now, the monster reached the player's position
		/// for further ai, i set the dir to 0, so later, 
		/// the monster's direction can be calculated again
		mDir.set( 0.0f, 0.0f, 0.0f );
		return ;
	}

	//v_dir = -v_dir; //because array +z is different from world +z
	if( v_dir == 0 )
	{
		if( world->canReach( ax + h_dir, az ) )
		{
			mDir.set( float( h_dir ), 0, 0 );
		}
		else
		{
			// donot change the direction at the monment
		}

		goto goon;
	}
	else if( h_dir == 0 )
	{
		if( world->canReach( ax, az + v_dir ) )
		{
			mDir.set( 0, 0, float( -v_dir ) );
		}
		else
		{
			// donot change the direction at the monment
		}

		goto goon;
	}
	
	if( rand() % 100 > 50 )
	{
		/// choose h_dir
		if( ax + h_dir != mLastArrayPos.X && world->canReach( ax + h_dir, az ) )
		{
			mDir.set( float( h_dir ), 0.0f, 0.0f );
		}
		else
		{
			/// choose v_dir
			if( az + v_dir != mLastArrayPos.Y && world->canReach( ax, az + v_dir ) )
			{
				mDir.set( 0.0f, 0.0f, float( -v_dir ) );//because array +z is  world -z
			}
			else if( !world->canReach( ax, az + (int)mDir.Z ) )
			{
				/// no way can be reached anymore, so just back
				mDir = -mDir;
			}
		}
	}
	else
	{
		/// choose v_dir
		if( az + v_dir != mLastArrayPos.Y && world->canReach( ax, az + v_dir ) )
		{
			mDir.set( 0.0f, 0.0f, float( -v_dir ) );//because array +z is  world -z
		}
		else
		{
			/// choose h_dir
			if( ax + h_dir != mLastArrayPos.X && world->canReach( ax + h_dir, az ) )
			{
				mDir.set( float( h_dir ), 0.0f, 0.0f );
			}
			else if( !world->canReach( ax + (int)mDir.X, az ) )
			{
				/// no way can be reached anymore, so just back
				mDir = -mDir;
			}
		}
	}

goon:
	mLastArrayPos.set( ax, az );
	mSpeed = mType == World::MONSTER_2 ? DEFAULT_MONSTER1_SPEED :
	DEFAULT_MONSTER3_SPEED ;

	if( equals( fabs( mDir.X ), 1.0f ) )
	{
		if( !world->canReach( ax + (int)mDir.X, az ) )
		{
			int outZDir;
			if( searchNewVDir( ax, az, outZDir ) )
			{
				mDir.set( 0, 0, -(float)outZDir );
			}
			else
			{
				mDir = -mDir;
			}
		}
	}
	else if( equals( fabs( mDir.Z ), 1.0f ) )
	{
		if( !world->canReach( ax, az - (int)mDir.Z ) )
		{
			//invalid, so search a new direction
			int outXDir;
			if( searchNewHDir( ax, az, outXDir ) )
			{
				mDir.set( (float)outXDir, 0, 0 );
			}
			else
			{
				//mDir.set( 0, 0, float( v_dir ) );//back
				mDir = -mDir;
			}
		}

	}

}

void	Monster::ai2()
{
	if( this->getArrayPos() == mLastArrayPos ||
		!World::GetSingletonPtr()->isCenterPos( mNode->getPosition() ) )
	{
		World *world = World::GetSingletonPtr();
		int ax, az;
		this->getArrayPos( ax, az );
		cout << ax << " " << az << " dir " << mDir.X << " " << mDir.Z << endl;
		return ;
	}

	World *world = World::GetSingletonPtr();

	int ax, az;
	this->getArrayPos( ax, az );

	int p = 0;
	vector3df v[4];
	
	v[p].set( -mDir );	//back direction, the worst solution
	
	if( world->canReach( ax + (int)mDir.X, az - (int)mDir.Z ) )
	{
		//it's right that you can go on with the current direction
		v[++p].set( mDir );
	}
	if( equals( fabs( mDir.X ), 1.0f ) )// mDir = (1,0,0) or (-1,0,0)
	{
		if( world->canReach( ax, az + 1 ) )
		{
			v[++p].set( 0, 0, -1 );
		}
		if( world->canReach( ax, az - 1 ) )
		{
			v[++p].set( 0, 0, 1 );
		}
	}
	else if( equals( fabs( mDir.Z ), 1.0f ) )//mDir = (0,0,1) or (0,0,-1)
	{
		if( world->canReach( ax + 1, az ) )
		{
			v[++p].set( 1, 0, 0 );
		}
		if( world->canReach( ax - 1, az ) )
		{
			v[++p].set( -1, 0, 0 );
		}
	}

	// get a random direction
	if( p == 0 )
	{
		mDir.set( v[0] );
	}
	else
	{
		int index = rand() % ( p ) + 1;
		mDir.set( v[index] );
	}

	// set speed
	mSpeed = DEFAULT_MONSTER2_SPEED;
	mLastArrayPos.set( ax, az );

	cout << "AI 2 is RUNNING" << endl;
}

bool	Monster::searchNewHDir( int ax, int az, int &outXDir )
{
	World *world = World::GetSingletonPtr();

	if( world->canReach( ax - 1, az ) )
	{
		outXDir = -1;
		return true;
	}
	if( world->canReach( ax + 1, az ) )
	{
		outXDir = 1;
		return true;
	}

	return false;
}

bool	Monster::searchNewVDir( int ax, int az, int &outZDir )
{
	World *world = World::GetSingletonPtr();

	if( world->canReach( ax, az - 1 ) )
	{
		outZDir = -1;
		return true;
	}
	if( world->canReach( ax, az + 1 ) )
	{
		outZDir = 1;
		return true;
	}
	return false;
}

bool	Monster::canFire()
{
	float prob;
	if( mType == World::MONSTER_2 )
	{
		prob = MF_MONSTER2;
	}
	if( mType == World::MONSTER_3 )
	{
		prob = MF_MONSTER3;
	}
	if( mType == World::MONSTER_4 )
	{
		prob = MF_MONSTER4;
	}

	if( rand() % 100 >= prob * 100 &&
		App::GetSingletonPtr()->getRealTime() - mLastFireTime > mFireDelay )
	{
		return true;
	}

	return false;
}

void	Monster::initDirection()
{
	World *world = World::GetSingletonPtr();

	int ax, az;
	this->getArrayPos( ax, az );

	if( world->canReach( ax - 1, az ) )
	{
		mDir.set( -1, 0, 0 );
	}
	else if( world->canReach( ax + 1, az ) )
	{
		mDir.set( 1, 0, 0 );
	}
	else if( world->canReach( ax, az - 1 ) )
	{
		mDir.set( 0, 0, 1 );
	}
	else if( world->canReach( ax, az + 1 ) )
	{
		mDir.set( 0, 0, -1 );
	}

	rotate( mDir );
}

void	Monster::hurt( int damage )
{
	mHP -= damage;	
	if( mHP <= 0 )
	{	
		mHP = getInitHP( mType );
		changeStatus( SpriteStatus::NORMAL, mType );
		mNode->setVisible( false );

		/// create some bonus for the player's cool killing .;D
		BonusManager::GetSingletonPtr()->createBonus( this->getPosition() ); 
	}
}

bool	Monster::isNormalStatus()
{
	return mStatus == SpriteStatus::NORMAL;
}

int		Monster::getInitHP( int type )
{
	int hp;

	switch( type )
	{
	case Sprite::ST_MONSTER_2 :
		hp = MONSTER_2_HP ;
		break;
	case Sprite::ST_MONSTER_3:
		hp = MONSTER_3_HP;
		break;
	case Sprite::ST_MONSTER_4:
		hp = MONSTER_4_HP;
		break;
	}

	return hp;
}

int		Monster::getInitScore( int type )
{
	int score;

	switch( type )
	{
	case Sprite::ST_MONSTER_2 :
		score = MONSTER_2_SCORE ;
		break;
	case Sprite::ST_MONSTER_3:
		score = MONSTER_3_SCORE;
		break;
	case Sprite::ST_MONSTER_4:
		score = MONSTER_4_SCORE;
		break;
	}

	return score;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -