c# - 状态机 C#
问题描述
我正在使用 C# 在 Unity 中做一个项目,我想让两架无人机在房间里游荡,然后使用状态机互相攻击。我有三个类 AttackState、ChaseState 和 WonderState
例如,这是我的 WanderState 类:
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Linq;
using System;
using UnityEngine;
public class WanderState : BaseState
{
private Vector3? _destination;
private float stopDistance = 1.5f;
private float turnSpeed = 1f;
private readonly LayerMask _layerMask = LayerMask.NameToLayer("Walls");
private float _rayDistance = 5.0f;
private Quaternion _desiredRotation;
private Vector3 _direction;
private Drone _drone;
public WanderState(Drone drone) : base(drone.gameObject)
{
_drone = drone;
}
public override Type Tick()
{
var chaseTarget = CheckForAggro();
if (chaseTarget != null)
{
_drone.SetTarget(chaseTarget);
return typeof(ChaseState);
}
if (_destination.HasValue == false || Vector3.Distance(transform.position, _destination.Value) <= stopDistance)
{
FindRandomDestination();
}
transform.rotation = Quaternion.Slerp(transform.rotation, _desiredRotation, Time.deltaTime * turnSpeed); //Time.deltaTime * turnSpeed
if (IsForwardBlocked()) //IsForwardBlocked()
{
transform.rotation = Quaternion.Lerp(transform.rotation, _desiredRotation, 0.2f);
}
else
{
float droneSpeed = 2f;
transform.Translate(Vector3.forward * Time.deltaTime * droneSpeed);
}
Debug.DrawRay(transform.position, _direction * _rayDistance, Color.red);
while (IsPathBlocked())
{
FindRandomDestination();
Debug.Log("Wall");
}
return null;
}
private bool IsForwardBlocked()
{
Ray ray = new Ray(transform.position, transform.forward);
return Physics.SphereCast(ray, 0.5f, _rayDistance, _layerMask);
}
private bool IsPathBlocked()
{
Rigidbody obj = new Rigidbody();
Ray ray = new Ray(transform.position, _direction);
return Physics.SphereCast(ray, 0.5f, _rayDistance, _layerMask);
}
private void FindRandomDestination()
{
Vector3 testPosition = (transform.position + (transform.forward * 4f)) + new Vector3(UnityEngine.Random.Range(-4.5f, 4.5f), 0f,UnityEngine.Random.Range(-4.5f, 4.5f));
_destination = new Vector3(testPosition.x, 1f, testPosition.z);
_direction = Vector3.Normalize(_destination.Value - transform.position);
_direction = new Vector3(_direction.x, 0f, _direction.z);
_desiredRotation = Quaternion.LookRotation(_direction);
Debug.Log("Got direction");
}
Quaternion startingAngle = Quaternion.AngleAxis(-60, Vector3.up);
Quaternion stepAngle = Quaternion.AngleAxis(5, Vector3.up);
private Transform CheckForAggro()
{
float aggroRadius = 5f;
RaycastHit hit;
var angle = transform.rotation * startingAngle;
var direction = angle * Vector3.forward;
var pos = transform.position;
for (var i = 0; i < 24; i++)
{
if (Physics.Raycast(pos, direction, out hit, aggroRadius))
{
var drone = hit.collider.GetComponent<Drone>();
if (drone != null && drone.Team1 != gameObject.GetComponent<Drone>().Team1)
{
Debug.DrawRay(pos, direction * hit.distance, Color.red);
return drone.transform;
}
else
{
Debug.DrawRay(pos, direction * hit.distance, Color.yellow);
}
}
else
{
Debug.DrawRay(pos, direction * aggroRadius, Color.white);
}
direction = stepAngle * direction;
}
return null;
}
}
然后我有 2 架无人机,每架无人机都有一个 Drone 脚本和一个 StateMachine 脚本,如下所示:
public class Drone : MonoBehaviour
{
[SerializeField] private Team _team;
[SerializeField] private GameObject _laserVisual;
public Transform Target { get; private set; }
public Team Team1=> _team;
public StateMachine StateMachine => GetComponent<StateMachine>();
private void Awake()
{
InitializeStateMachine();
}
private void InitializeStateMachine()
{
var states = new Dictionary<Type, BaseState>()
{
{typeof(WanderState), new WanderState(this) },
{typeof(ChaseState), new ChaseState(this) },
{typeof(AttackState), new AttackState(this) }
};
GetComponent<StateMachine>().SetStates(states);
}
public void SetTarget(Transform target)
{
Target = Target;
}
public void FireWeapon()
{
_laserVisual.transform.position = (Target.position + transform.position) / 2f;
float distance = Vector3.Distance(a: Target.position, b: transform.position);
_laserVisual.transform.localScale = new Vector3(0.1f, 0.1f, distance);
_laserVisual.SetActive(true);
StartCoroutine(TurnOffLaser());
}
public IEnumerator TurnOffLaser()
{
yield return new WaitForSeconds(0.25f);
_laserVisual.SetActive(false);
if (Target != null)
{
GameObject.Destroy(Target.gameObject);
}
}
public enum Team
{
Red,
Blue
}
public class StateMachine : MonoBehaviour
{
private Dictionary<Type, BaseState> _availableStates;
public BaseState CurrentState { get; private set; }
public event Action<BaseState> OnStateChanged;
public void SetStates(Dictionary<Type, BaseState> states)
{
_availableStates = states;
}
private void Update()
{
if(CurrentState == null)
{
CurrentState = _availableStates.Values.First();
}
var nextState = CurrentState?.Tick();
if (nextState != null && nextState != CurrentState.GetType())
{
SwitchToNewState(nextState);
}
}
public void SwitchToNewState(Type nextState)
{
CurrentState = _availableStates[nextState];
OnStateChanged?.Invoke(CurrentState);
}
}
我面临的问题是我的无人机正在穿过房间的墙壁
我尝试为墙壁设置网格碰撞器或盒子碰撞器,但这些选项都不起作用。此外,对于无人机,我有一个球体对撞机。
有谁知道为什么会出现这种行为以及我能做些什么来解决它?
解决方案
为无人机添加刚体并确保未选中 isKinematic。
推荐阅读
- excel - 如何删除同一 Excel 单元格中存在的重复单词实例?
- sql - sql/vba 中 where 子句的第二部分有
- typescript - Chromium / typescript 期待不同位置的源地图
- reactjs - 如何使用 useState() 钩子和 history.push() 将状态传递给另一个组件
- macos - VMWare 工作站崩溃后无法启动
- c - RTL SDR IQ AM 解调
- c++ - 构造函数中 const 参数的目的是什么?
- python - 包括子蛇文件并生成它们的输出
- python - Django:无法解压不可迭代的 int 对象
- javascript - 错误 xhr.abort() 不是使用 Ajax jQuery 的函数