Hey guys please check my fsm here my attack state doesn’t seem to work and idk why. If anyone knows please please help thank you.
public class PlagueFiniteStateMachine : MonoBehaviour
{
public enum doctorState
{
// define every state needed
Walking,
Attack,
Charge,
Return,
Idle,
Follow,
}
[SerializeField] float visibleDis= 15f;
[SerializeField] float visibleAngle= 10f;
[SerializeField] int attack= 10;
[SerializeField] float distance = 5f;
private Animator ani;
public LayerMask ignore;
[SerializeField] private GameObject player;
[SerializeField] NavMeshAgent plague;
[SerializeField] GameObject targetPos;
[SerializeField] GameObject aiBase;
[SerializeField] GameObject vaccine;
[SerializeField]GameObject Indicator;
PlayerMovement op;
//[SerializeField]Vector3 destination;
doctorState currentState;
void Start()
{
Indicator.SetActive(false);
plague = GetComponent<NavMeshAgent>();
ani = this.GetComponent<Animator>();
op = GetComponent<PlayerMovement>();
player = GameObject.FindGameObjectWithTag("Player");
targetPos = GameObject.FindGameObjectWithTag("Flag");
aiBase = GameObject.FindGameObjectWithTag("AIBase");
vaccine = GameObject.FindGameObjectWithTag("Flag");
ChangeState(doctorState.Walking); // on entry walking state is default state
plague.SetDestination(targetPos.transform.position);
}
void Update()
{
float stillAttack = Vector3.Distance(player.transform.position, plague.transform.position);
StateHandler();
if (stillAttack <= distance)
{
ChangeState(doctorState.Attack);
plague.SetDestination(player.transform.position);
op.takeDamage(attack);
}
}
// method to handle behaviours between states & conditions to switch states
void StateHandler()
{
switch (currentState)
{
case doctorState.Walking:
if (CanSeePlayer())
{
ChangeState(doctorState.Charge);
}
else if (CanAttack())
{
ChangeState(doctorState.Attack);
}
else if (ReachedTarget())
{
ChangeState(doctorState.Return);
}
break;
case doctorState.Attack:
if(CanSeePlayer())
{
ChangeState(doctorState.Charge);
}
else if (!CanAttack())
{
ChangeState(doctorState.Walking);
}
else if(ReachedTarget())
{
ChangeState(doctorState.Return);
}
break;
case doctorState.Charge:
if (!CanSeePlayer())
{
ChangeState(doctorState.Walking);
}
else if(CanAttack())
{
ChangeState(doctorState.Attack);
}
else if (ReachedTarget())
{
ChangeState(doctorState.Return);
}
break;
case doctorState.Return:
if (AgentReturnedVaccine())
{
Debug.Log("Agent secured the package, We have failed.");
ChangeState(doctorState.Idle);
}
break;
}
}
// method to handle the behaviour in transition between states
void ChangeState(doctorState newState)
{
if(currentState== newState) return; // to prevent unnecessary transitions;
currentState= newState;
//here is the enter logic for current states
switch (currentState)
{
case doctorState.Walking:
OnEnterWalking();
break;
case doctorState.Charge:
OnEnterCharge();
break;
case doctorState.Attack:
OnEnterAttack();
break;
case doctorState.Idle:
OnEnterIdle();
return;
case doctorState.Return:
OnEnterReturn();
break;
}
}
// Enter and exit methods for each state
void OnEnterWalking()
{
ani.SetBool("CanAttack", false);
ani.SetBool("CanCharge", false);
ani.SetBool("IsWalking", true);
plague.SetDestination(targetPos.transform.position);
Debug.Log("Current state is: " + currentState);
}
void OnEnterIdle()
{
Indicator.SetActive(false);
ani.SetBool("CanAttack", false);
ani.SetBool("CanCharge", false);
ani.SetBool("IsWalking", false);
ani.SetBool("IsIdle", true);
Debug.Log("Current state is: " + currentState);
}
void OnEnterCharge()
{
Indicator.SetActive(false);
ani.SetBool("IsWalking", false);
ani.SetBool("CanAttack", false);
ani.SetBool("CanCharge", true);
plague.SetDestination(player.transform.position);
Debug.Log("Current state is: " + currentState);
}
void OnEnterAttack()
{
Indicator.SetActive(false);
// float stillAttack = Vector3.Distance(player.transform.position, plague.transform.position);
ani.SetBool("CanCharge", false);
ani.SetBool("IsWalking", false);
ani.SetBool("CanAttack", true);
/*
if(stillAttack<= distance)
{
plague.SetDestination(player.transform.position);
op.takeDamage(attack);
}
*/
Debug.Log("Current state is: " + currentState);
}
void OnEnterReturn()
{
Indicator.SetActive(true);
ani.SetBool("IsWalking", false);
ani.SetBool("CanAttack", false);
ani.SetBool("CanCharge", true);
plague.SetDestination(aiBase.transform.position);
Debug.Log("Current state is: " + currentState);
}
bool Captured(Collider other)
{
string thisTag = "Agent";
GameObject someObject = GameObject.FindGameObjectWithTag(thisTag);
if (other.gameObject.tag == "flag" && someObject != null)
{
return true;
}
return false;
}
public bool CanSeePlayer() // boolean method to check if player is in range
{
Vector3 direction= player.transform.position- this.transform.position;
float angle= Vector3.Angle(direction, this.transform.forward);
if(direction.magnitude< visibleDis && angle< visibleAngle)
{
return true;
}
return false;
}
public bool CanAttack()
{
/*
RaycastHit hit;
int maxDis = 5;
;
if(Physics.Raycast(transform.position, Vector3.forward, maxDis, ignore ))
{
Debug.DrawRay(transform.position, transform.forward, Color.red);
Debug.Log("Hit " + player);
return true;
}
return false;
*/
if(Vector3.Distance(player.transform.position,plague.transform.position) <= distance)
{
return true;
}
return false;
}
bool ReachedTarget()
{
if(Vector3.Distance(targetPos.transform.position, plague.transform.position) < distance)
{
return true;
}
return false;
}
bool AgentReturnedVaccine()
{
return Vector3.Distance(aiBase.transform.position, plague.transform.position) < distance;
}
void OnTriggerEnter(Collider other)
{
if (Captured(other))
{
Debug.Log("Returning to base");
ChangeState(doctorState.Return);
}
}
}