Reputation: 11
so i made a state machine for my game but my problem is that when the enemy "sees" the player it switches from idle to attack skipping chase state and the enemy never moves. Also it doesn't switch back to chase state when player is out of attack range. this is my entire state machine:
State script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class State : MonoBehaviour
{
public abstract State RunCurrentState();
}
State Manager script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class StateManager : MonoBehaviour
{
[SerializeField] private State currentState;
void Update()
{
RunStateMachine();
}
private void RunStateMachine()
{
State nextState = currentState?.RunCurrentState();
if (nextState != null)
{
SwitchToTheNextState(nextState);
}
}
private void SwitchToTheNextState(State nextState)
{
currentState = nextState;
}
}
Idle State script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class IdleState : State
{
public ChaseState ChaseState;
[SerializeField] private GameObject _target;
[SerializeField][Range(0, 100)] private float _seenRange;
private bool _isSpotted;
private float _delta;
private void Start()
{
_target = GameObject.Find("Player");
_delta = _target.transform.localScale.x / 2f;
StartCoroutine(CheckForTargets());
}
private IEnumerator CheckForTargets()
{
while (true)
{
yield return new WaitForSeconds(1);
if (_target == null)
{
Debug.Log("No target...");
}
else
{
_isSpotted = false;
RaycastHit2D[] seenEntities = Physics2D.RaycastAll(transform.position, _target.transform.position - transform.position, _seenRange);
//Debug.DrawRay(transform.position, _target.transform.position - transform.position, Color.red, 1f, false);
foreach (var ent in seenEntities)
{
if (ent.transform.tag == _target.tag)
{
var ray2d = new Ray2D(_target.transform.position, transform.position - _target.transform.position); // enemies are not in world space
_isSpotted = true;
for (float i = 0; i < Vector3.Distance(_target.transform.position, transform.position); i += _delta)
{
var tile = MapManager.Instance.SteppedOnTile(Vector3Int.FloorToInt(ray2d.GetPoint(i)));
if (!tile.isWalkable)
{
_isSpotted = false;
break;
}
}
}
}
}
if (_isSpotted)
{
gameObject.GetComponent<SpriteRenderer>().color = new Color(1, 0, 0);
}
else
{
gameObject.GetComponent<SpriteRenderer>().color = new Color(1, 1, 1);
Debug.Log("a");
}
}
}
public void OnDrawGizmos()
{
//Gizmos.DrawLine(transform.position, _target.transform.position);
}
public override State RunCurrentState()
{
if (_isSpotted)
{
_isSpotted = false;
StopAllCoroutines();
return ChaseState;
}
else
{
return this;
}
}
}
Chase state:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChaseState : State
{
[SerializeField] private AttackState attackState;
private bool isInAttackRange;
[Range(0,100)] [SerializeField] private float attackRange = 10.0f;
[SerializeField] private GameObject _target;
private MovementComponent _movementScript;
private void Start()
{
_movementScript = GetComponent<MovementComponent>();
if (_target == null) _target = GameObject.Find("Player");
}
private void FixedUpdate()
{
var distance = Vector3.Distance(transform.position, _target.transform.position);
isInAttackRange = distance <= attackRange;
}
public override State RunCurrentState()
{
if (isInAttackRange)
{
return attackState;
}
else
{
return this;
}
}
private void ChasePlayer()
{
if (_target != null)
{
Vector3 direction = _target.transform.position - transform.position;
//direction.Normalize();
_movementScript.Move(direction);
}
else
{
Debug.LogError("Player doesnt exist :)");
}
}
}
and finally Attack state script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AttackState : State
{
[SerializeField] private Transform _target;
private float attackRange = 5.0f;
private ChaseState chaseState;
private AttackComponent _attackScript;
public AttackState(ChaseState chaseState)
{
this.chaseState = chaseState;
}
void Start()
{
_target = GameObject.Find("Player").transform;
_attackScript = GetComponent<AttackComponent>();
}
public override State RunCurrentState()
{
if (_target != null && Vector3.Distance(transform.position, _target.position) <= attackRange)
{
_attackScript.Attack(transform.position - _target.position);
return this;
}
else
{
switch (tag)
{
case "Enemy_Apple":
return chaseState;
default:
return this;
}
}
}
}
i've tried asking friends, chatgpt but when some issues were fixed other were made.
Upvotes: 0
Views: 51