Конечный автомат C#

#c# #unity3d

#c# #unity3d

Вопрос:

Я делаю проект в Unity с C #, и я хочу иметь два дрона, которые будут бродить по комнате, а затем атаковать друг друга с помощью конечного автомата. У меня есть три класса 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 amp;amp; 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 дрона, и у каждого из них есть сценарий дрона и сценарий 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 amp;amp; nextState != CurrentState.GetType())
        {
            SwitchToNewState(nextState);
        }
    }

    public void SwitchToNewState(Type nextState)
    {
        CurrentState = _availableStates[nextState];
        OnStateChanged?.Invoke(CurrentState);
    }
}

  

Проблема, с которой я сталкиваюсь, заключается в том, что мои дроны проходят сквозь стены комнаты

Я попытался установить для стен сетчатый или коробчатый коллайдер, но ни один из этих вариантов не сработал. Кроме того, для дронов у меня есть сферический коллайдер.

Кто-нибудь знает, почему такое поведение и что я могу сделать, чтобы это исправить?

Ответ №1:

Добавьте жесткое тело в drone и убедитесь, что флажок isKinematic снят.

Комментарии:

1. Я попробовал то, что вы говорите, но если свойство isKinematic не установлено, объекты дронов начинают вылетать за пределы комнаты. Если свойство проверено, они действуют нормально, но все равно проходят сквозь стены. Может быть, мне тоже следует добавить свойство в поле? Я пробовал с жестким телом, но все еще не работает. У вас есть другое предложение, потому что я застрял, и мне действительно нужно сделать этот проект.