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

📄 fsm_unit.cpp.svn-base

📁 自己做的小游戏
💻 SVN-BASE
字号:
/* Copyright (C) Steve Rabin, 2000. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) Steve Rabin, 2000"
 */
//////////////////////////////////////////////////////////////
//
// Filename: fsm_drone.cpp
//
// Author: Steve Rabin
// E-mail: stevera@noa.nintendo.com
// From the book "Game Programming Gems"
// From the article "Designing a General Robust AI Engine"
//
// Brief Disclaimer:
// This code is free to use for commercial use and is in the
// public domain. You may distribute, copy, modify, or use as
// is as long as this information is present. This code makes
// no guarantees written or implied and is provided solely as
// an example. Have a nice day!
//
// Purpose:
// This file is an example of a state machine that multiple
// game objects can reference. Note that no state information
// is saved within this file. State information lies solely
// inside each game object. It would be a mistake to save any
// state info within this file.
//
//////////////////////////////////////////////////////////////


#include "fsm_unit.h"
#include "fsm.h"
#include "custom_time.h"
#include "fsmmacros.h"
#include "msgroute.h"
#include "game_object.h"
#include "util.h"
#include "../gamedata/fireball.h"

#include "../gamedata/gamedata.h"
#include "../gamedata/structs.h"
#include "../gamedata/mdlmodel.h"


#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include "math.h"


bool PlayerSensed(GameObject *u, GameObject *p);
void CalcNewPos(GameObject *go);



bool UnitProcessStateMachine( GameObject* go, unsigned int state, MsgObject* msg )
{

//This is the state machine language.
//To see the keywords, look in the file "fsmmacros.h".
//You can get MS Visual Studio to highlight these words by listing them in
//a text file called "usertype.dat" put in the same directory where Msdev.exe
//is stored (like C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin).
//You'll find the "usertype.dat file in the same directory this file is in.
//Just copy it to the correct directory.

BeginStateMachine

	
	OnEnter
		SetState( STATE_Wander );	//一开始,怪物们就巡逻



	OnMsg(MSG_Damage)
		go->health -= msg->ex.damage;
		if (go->health <= 0) {
			SetState(STATE_Dead);
		}







	//----------------------------------------------------------------

	State( STATE_Wander )

		OnEnter
			go->model->SetSeq(WALK);
			go->rotY = RandomBetween(0.0f, 179.0f);		//随机设置方向
			SendDelayedMsgToCurrentState( MSG_Timeout, 10000, go->unique_id, go->unique_id, go );		//设定巡逻的时间

		OnMsg( MSG_CalcNewPos )

			go->checked = false;
			go->collide = false;

			CalcNewPos(go);

			if (go->newPos.x != go->oldPos.x || go->newPos.z != go->oldPos.z)
				go->NeedChecked = true;
			else
				go->NeedChecked = false;
					
		OnUpdate
			if (PlayerSensed(go, &player)) {		//如果发现player
				SetState(STATE_Rest);		//由于SetState()是宏,所以要加{}
			}
			
			if (go->checked) {
				if (!go->collide) {
					go->pos = go->newPos;
				} 
				else {
					SetState(STATE_Rest);
				}
			}else {
				assert( !"You must calculate new position before update!" );
			}
			
			

		OnMsg( MSG_Timeout )
			
			if (msg->state == STATE_Wander) {
				if( rand()%100 < 50 ) {
					SetState( STATE_Wander );
				} else {
					SetState( STATE_Rest );
				}
			}


//----------------------------------------------------------------

	State( STATE_Pursue )

		OnEnter
			go->model->SetSeq(WALK);
			go->rotY = GetRotY(go->pos, player.pos);		//方向朝向player(也就是player和go的连线的方向)


		OnMsg( MSG_CalcNewPos )

			go->checked = false;
			go->collide = false;

			CalcNewPos(go);

			if (go->newPos.x != go->oldPos.x || go->newPos.z != go->oldPos.z)
				go->NeedChecked = true;
			else
				go->NeedChecked = false;


		OnUpdate

			//====================================================================================================
			//
			//在这里面有很多东西可做,可以做一下人工智能方面的东西,不过我只是简单的处理了一下,让怪物朝着player跑
			//大概可以搞一个寻路的东西
			//现在这里面有很多bug,比如如果怪物碰到了树,还是会攻击,而且是直接朝树攻击,很傻
			//
			//====================================================================================================

			

			
			go->rotY = GetRotY(go->pos, player.pos);		//方向朝向player(也就是player和go的连线的方向)

			if (GetDistance(go->pos, player.pos) <= go->attackDist) {		//如果距离小于等于攻击距离,则转为攻击状态
				SetState(STATE_Attack);
				return true;
			}
			if (!PlayerSensed(go, &player)) {		//如果不再感觉得到player则转为休息状态
				//go->rotY = RandomBetween(0.0f, 179.0f);
				SetState(STATE_Rest);
				return true;
			}
			

			if (go->checked) {
				if (!go->collide) {		//如果没撞,则更新位置
					go->pos = go->newPos;
				} 
				else {
					//如果撞了则休息
					SetState(STATE_Rest);
				}
			} else {
				assert( !"You must calculate new position before update!" );
			}
			

	//----------------------------------------------------------------

	State(STATE_Rest)

		OnEnter
			go->model->SetSeq(IDLE);

			SendDelayedMsgToCurrentState( MSG_Timeout, 500, go->unique_id, go->unique_id, go );
			go->NeedChecked = false;
			go->checked = false;
			go->collide = false;

		OnUpdate
			//什么也不做,等到timeout时才进行判断


		OnMsg( MSG_Timeout )
			if (msg->state == STATE_Rest) {		//休息够了则继续巡逻
				if (GetDistance(go->pos, player.pos) <= go->attackDist)		//在攻击范围内
				{
					SetState( STATE_Attack );
				}
				else if (PlayerSensed(go, &player))		//感觉到了但不在攻击范围内
				{
					SetState( STATE_Pursue );
				}
				else
				{
					SetState( STATE_Wander );
				}
			}



	

	//----------------------------------------------------------------

	State( STATE_Attack )		//基本上跟player的attack差不多

		OnEnter
			go->model->SetSeq(ATTACK);

			go->rotY = GetRotY(go->pos, player.pos);		//将方向朝向player(也就是player和go的连线的方向)
			SendDelayedMsgToCurrentState( MSG_Timeout, go->model->GetSeqTime()-300, go->unique_id, go->unique_id, go );
			go->NeedChecked = false;	
			go->checked = false;
			go->collide = false;
			
			Vertex fbPos, fbDest;

			////////////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
			fbPos.x = go->pos.x + (go->radius+0.3 + 0.1) * sinf(go->rotY*0.0174533f);
			fbPos.z = go->pos.z + (go->radius+0.3 + 0.1) * cosf(go->rotY*0.0174533f);
			fbPos.y = go->pos.y + go->lenY * 0.5;
			fbDest = player.pos;
			fbDest.y += go->lenY * 0.5;
			FireBall fb(fbPos, fbDest, go->unique_id, go->aggressivity);
			fireBalls.push_back(fb);

		OnUpdate
			//什么也不做,等待这个动作结束

		OnMsg( MSG_Timeout )
		if (msg->state == STATE_Attack) {
			if (GetDistance(go->pos, player.pos) <= go->attackDist)
			{
				SetState( STATE_Attack );
			}
			else if (PlayerSensed(go, &player))
			{
				SetState( STATE_Pursue );
			}
			else
			{
				SetState( STATE_Rest );
			}
		}


	//----------------------------------------------------------------

	State( STATE_Dead )
		
		OnEnter
			go->model->SetSeq(DIE);
			//要么释放内存,要么标志一下它死了
			SendDelayedMsgToCurrentState( MSG_Timeout, go->model->GetSeqTime()-400, go->unique_id, go->unique_id, go );



		OnMsg( MSG_Timeout )
			if (msg->state == STATE_Dead)
				go->bMarkedForDeletion = true;



EndStateMachine

}


bool PlayerSensed(GameObject *u, GameObject *p)
{
	float pRotYu = abs(GetRotY(u->pos, p->pos) - u->rotY);
	float distToP = GetDistance(u->pos, p->pos);
	if (pRotYu < 60.0f || pRotYu > 300.0f){		// 如果p在u视野内,即在120度角以内
		if (distToP <= u->eyeDist) {		//在可以看见的距离以内
			return true;
		}
	} else if (distToP <= u->earDist) {		//在可以听见的距离以内,这个距离小于看见的距离
		return true;
	}
	return false;
}


void CalcNewPos(GameObject *go)
{
	float incLen = incT * go->moveSpeed;
	go->oldPos = go->pos;
	go->newPos.x = go->oldPos.x + incLen * sinf(go->rotY * 0.0174533f);
	go->newPos.z = go->oldPos.z + incLen * cosf(go->rotY * 0.0174533f);
	go->newPos.y = map.getHeight(go->newPos.x, go->newPos.z);
}






































//void DroneTranslateStateName( unsigned int state, char* name )
//{
//	switch( state )
//	{
//		case STATE_Global:
//			strcpy( name, "Global" );
//			break;
//
//		case STATE_Idle:
//			strcpy( name, "Idle" );
//			break;
//		
//		case STATE_Wander:
//			strcpy( name, "Wander" );
//			break;
//		
//		case STATE_Pursue:
//			strcpy( name, "Pursue" );
//			break;
//		
//		case STATE_Evade:
//			strcpy( name, "Evade" );
//			break;
//		
//		case STATE_Cower:
//			strcpy( name, "Cower" );
//			break;
//		
//		case STATE_Hide:
//			strcpy( name, "Hide" );
//			break;
//		
//		case STATE_Dead:
//			strcpy( name, "Dead As A Doornail" );
//			break;
//		
//		default:
//			strcpy( name, "Can't translate state name" );
//	}
//
//}





⌨️ 快捷键说明

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