Hi! I’m trying to implement a “lazy state machine” using enums for simple enemy AI but for some reason the logic doesn’t work as intended. I need my enemy to stop from time to time to be in Idle state. But when Idle switch fires, my enemy continues to move despite movement requiring another state to fire.
What am I doing wrong?
private void Update()
{
Debug.Log(state);
onGround = Physics2D.Raycast(gameObject.transform.position, Vector2.down, groundLength, groundLayer);
Debug.DrawRay(gameObject.transform.position, Vector2.down * 1f, Color.red);
isAnythingThere = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 0.3f, sideInfo);
RaycastHit2D groundInfo = Physics2D.Raycast(groundDetection.position, Vector2.down, distance);
RaycastHit2D isPlayerInSight = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 3f, playerLayer);
switch (state)
{
default:
case State.patrol:
if ((groundInfo.collider == false || isAnythingThere) && !isPlayerInSight)
{
if (movingRight == true)
{
Debug.Log("Turn");
transform.eulerAngles = new Vector3(0, -180, 0);
movingRight = false;
speed = -speed;
}
else
{
transform.eulerAngles = new Vector3(0, 0, 0);
movingRight = true;
speed = -speed;
}
}
if (isPlayerInSight)
{
state = State.attack;
}
if (enemyIdleCheck == false)
{
StartCoroutine("IfEnemyWantsToIdle");
}
break;
case State.attack:
RaycastHit2D isPlayerThere = Physics2D.Raycast(wallDetection.position, Vector2.right * speed, 3f, playerLayer);
Debug.DrawRay(wallDetection.transform.position, Vector2.right * speed * 3f, Color.red);
if (isPlayerThere)
{
attackDirection = (playerPosition.position - transform.position).normalized;
}
else
{
if (!jumpCooldown)
{
state = State.patrol;
}
}
if (jumpCooldown == false)
{
jumpTimer = Time.time + jumpCooldownInSeconds;
}
break;
case State.idle:
if (isPlayerInSight)
{
state = State.attack;
}
if (!isInIdleState)
{
StartCoroutine("IdlingTime");
}
break;
}
}
private IEnumerator IfEnemyWantsToIdle()
{
enemyIdleCheck = true;
Debug.Log("Checking for idle possibility");
yield return new WaitForSeconds(2);
if (Random.Range(0, 20) > 10)
{
state = State.idle;
}
enemyIdleCheck = false;
if (isPlayerInSight)
{
state = State.attack;
enemyIdleCheck = false;
yield break;
}
}
private IEnumerator IdlingTime()
{
isInIdleState = true;
while (state == State.idle)
{
yield return new WaitForSeconds(Random.Range(2, 4));
isInIdleState = false;
state = State.patrol;
}
if (isPlayerInSight)
{
isInIdleState = false;
yield break;
}
}
private void FixedUpdate()
{
if (state == State.patrol)
{
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(movingSpeed * speed, rb.velocity.y);
}
}
if (state == State.attack)
{
if (!enemy.isTakingDamage)
{
rb.velocity = new Vector2(attackDirection.x * attackSpeed, rb.velocity.y);
}
if ((Random.Range(0, 100) > 90) && !jumpCooldown && onGround)
{
Debug.Log("Jumped!");
//rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * jumpForce);
rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
jumpCooldown = true;
Invoke("JumpCooldownTime", 1f);
}
}
}