Boss Room 是一款使用 Unity MLAPI 制作的全功能合作多人 RPG。 它旨在作为学习样本,展示类似游戏中经常出现的某些典型游戏模式。
您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

119 行
3.8 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom.Server
{
/// <summary>
/// Handles enemy AI. Contains AIStateLogics that handle some of the details,
/// and has various utility functions that are called by those AIStateLogics
/// </summary>
public class AIBrain
{
private enum AIStateType
{
ATTACK,
//WANDER,
IDLE,
}
private ServerCharacter m_serverCharacter;
private ActionPlayer m_actionPlayer;
private AIStateType m_currentState;
private Dictionary<AIStateType, AIState> m_logics;
private List<ServerCharacter> m_hatedEnemies;
public AIBrain(ServerCharacter me, ActionPlayer myActionPlayer)
{
m_serverCharacter = me;
m_actionPlayer = myActionPlayer;
m_logics = new Dictionary<AIStateType, AIState>
{
[ AIStateType.IDLE ] = new IdleAIState(this),
//[ AIStateType.WANDER ] = new WanderAIState(this), // not written yet
[ AIStateType.ATTACK ] = new AttackAIState(this, m_actionPlayer),
};
m_hatedEnemies = new List<ServerCharacter>();
m_currentState = AIStateType.IDLE;
}
/// <summary>
/// Should be called by the AIBrain's owner each Update()
/// </summary>
public void Update()
{
AIStateType newState = FindBestEligibleAIState();
if (m_currentState != newState)
{
m_logics[ newState ].Initialize();
}
m_currentState = newState;
m_logics[ m_currentState ].Update();
}
private AIStateType FindBestEligibleAIState()
{
// for now we assume the AI states are in order of appropriateness,
// which may be nonsensical when there are more states
foreach (AIStateType type in Enum.GetValues(typeof(AIStateType)))
{
if (m_logics[ type ].IsEligible())
{
return type;
}
}
Debug.LogError("No AI states are valid!?!");
return AIStateType.IDLE;
}
#region Functions for AIStateLogics
/// <summary>
/// Returns true if it be appropriate for us to murder this character, starting right now!
/// </summary>
public bool IsAppropriateFoe(ServerCharacter potentialFoe)
{
if (potentialFoe == null || potentialFoe.IsNPC)
{
return false;
}
// FIXME: check for dead!
// Also, we could use NavMesh.Raycast() to see if we have line of sight to foe?
return true;
}
/// <summary>
/// Notify the AIBrain that we should consider this character an enemy.
/// </summary>
/// <param name="character"></param>
public void Hate(ServerCharacter character)
{
if (!m_hatedEnemies.Contains(character))
{
m_hatedEnemies.Add(character);
}
}
/// <summary>
/// Return the raw list of hated enemies -- treat as read-only!
/// </summary>
public List<ServerCharacter> GetHatedEnemies()
{
// first we clean the list -- remove any enemies that have disappeared (became null), are dead, etc.
m_hatedEnemies.RemoveAll(enemy => !IsAppropriateFoe(enemy));
return m_hatedEnemies;
}
/// <summary>
/// Retrieve info about who we are. Treat as read-only!
/// </summary>
/// <returns></returns>
public ServerCharacter GetMyServerCharacter()
{
return m_serverCharacter;
}
#endregion
}
}