I am doing a project in Unity with C# and I want to have two drones that will wander in the room, and then attack each other using a state machine.
I have three classes AttackState, ChaseState and WonderState
For example, this is my WanderState Class:
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;
}
}
Then I have 2 drones, and each of them have a Drone script and a StateMachine script as follows:
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);
}
}
The problem I am facing is that my drones are going through the room walls
I tried to set for the walls a Mesh Collider or a Box collider an make the drone a rigid body, but none of these options worked. Also, for the drones I have a sphere collider.
Does anyone know why this behaviour and what can I do to fix it?