Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create a State Machine #4

Open
wants to merge 1 commit into
base: State-Machine-Setup
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Assets/Scripts/Enemy/EnemyController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public class EnemyController
protected int currentHealth;
protected EnemyState currentState;
protected NavMeshAgent Agent => enemyView.Agent;
protected EnemyScriptableObject Data => enemyScriptableObject;
protected Quaternion Rotation => enemyView.transform.rotation;
protected Vector3 Position => enemyView.transform.position;
public EnemyScriptableObject Data => enemyScriptableObject;
public Quaternion Rotation => enemyView.transform.rotation;
public Vector3 Position => enemyView.transform.position;


public EnemyController(EnemyScriptableObject enemyScriptableObject)
Expand Down
70 changes: 14 additions & 56 deletions Assets/Scripts/Enemy/OnePunchMan/OnePunchManController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,23 @@ public class OnePunchManController : EnemyController
{
private bool isIdle;
private bool isRotating;

private bool isShooting;
private float idleTimer;
private float shootTimer;
private float targetRotation;
private PlayerController target;


private OnePunchManStateMachine stateMachine;
public OnePunchManController(EnemyScriptableObject enemyScriptableObject) : base(enemyScriptableObject)
{
enemyView.SetController(this);
InitializeVariables();
// InitializeVariables();
CreateStateMachine();
stateMachine.ChangeState(OnePunchManStates.IDLE);
}

private void CreateStateMachine() => stateMachine = new OnePunchManStateMachine(this);
private void InitializeVariables()
{
isIdle = true;
Expand All @@ -36,47 +40,16 @@ public override void UpdateEnemy()
if (currentState == EnemyState.DEACTIVE)
return;

if(isIdle && !isRotating && !isShooting)
{
idleTimer -= Time.deltaTime;
if(idleTimer <= 0)
{
isIdle = false;
isRotating = true;
targetRotation = (Rotation.eulerAngles.y + 180) % 360;
}
}

if(!isIdle && isRotating && !isShooting)
{
SetRotation(CalculateRotation());
if(IsRotationComplete())
{
isIdle = true;
isRotating = false;
ResetTimer();
}
}

if(!isIdle && !isRotating && isShooting)
{
Quaternion desiredRotation = CalculateRotationTowardsPlayer();
SetRotation(RotateTowards(desiredRotation));

if(IsFacingPlayer(desiredRotation))
{
shootTimer -= Time.deltaTime;
if (shootTimer <= 0)
{
shootTimer = enemyScriptableObject.RateOfFire;
Shoot();
}
}

}
stateMachine.Update();
}

public override void PlayerEnteredRange(PlayerController targetToSet)
{
base.PlayerEnteredRange(targetToSet);
stateMachine.ChangeState(OnePunchManStates.SHOOTING);
}

public override void PlayerExitedRange() => stateMachine.ChangeState(OnePunchManStates.IDLE);
private void ResetTimer() => idleTimer = enemyScriptableObject.IdleTime;

private Vector3 CalculateRotation() => Vector3.up * Mathf.MoveTowardsAngle(Rotation.eulerAngles.y, targetRotation, enemyScriptableObject.RotationSpeed * Time.deltaTime);
Expand All @@ -94,21 +67,6 @@ private Quaternion CalculateRotationTowardsPlayer()

private Quaternion RotateTowards(Quaternion desiredRotation) => Quaternion.LerpUnclamped(Rotation, desiredRotation, enemyScriptableObject.RotationSpeed / 30 * Time.deltaTime);

public override void PlayerEnteredRange(PlayerController targetToSet)
{
base.PlayerEnteredRange(targetToSet);
isIdle = false;
isRotating = false;
isShooting = true;
target = targetToSet;
shootTimer = 0;
}

public override void PlayerExitedRange()
{
isIdle = true;
isRotating = false;
isShooting = false;
}

}
}
54 changes: 54 additions & 0 deletions Assets/Scripts/Enemy/OnePunchMan/OnePunchManStateMachine.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;

namespace StatePattern.Enemy
{
public class OnePunchManStateMachine
{
private OnePunchManController Owner;
private IState currentState;

protected Dictionary<OnePunchManStates, IState> States = new Dictionary <OnePunchManStates, IState>();

public OnePunchManStateMachine(OnePunchManController Owner)
{
this.Owner = Owner;
CreateStates();
SetOwner();
}

private void SetOwner()
{
foreach(IState state in States.Values)
{
state.Owner = Owner;
}
}

private void CreateStates()
{
States.Add(OnePunchManStates.IDLE, new IdleState(this));
States.Add(OnePunchManStates.ROTATING, new RotatingState(this));
States.Add(OnePunchManStates.SHOOTING , new ShootingState(this));

}

public void Update() => currentState?.Update();

protected void ChangeState(IState newState)
{
currentState?.OnStateExit();
currentState = newState;
currentState?.OnStateEnter();
}

public void ChangeState(OnePunchManStates newState) => ChangeState(States[newState]);
}

public enum OnePunchManStates
{
IDLE,
ROTATING,
SHOOTING
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/Enemy/OnePunchMan/OnePunchManStateMachine.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Assets/Scripts/States.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions Assets/Scripts/States/IState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using StatePattern.Enemy;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IState
{
public OnePunchManController Owner { get; set; }

public void OnStateEnter();
public void Update();
public void OnStateExit();

}
11 changes: 11 additions & 0 deletions Assets/Scripts/States/IState.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions Assets/Scripts/States/IdleState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace StatePattern.Enemy
{
public class IdleState : IState
{
public OnePunchManController Owner { get; set; }
private OnePunchManStateMachine stateMachine;
private float timer;

public IdleState(OnePunchManStateMachine stateMachine) => this.stateMachine = stateMachine;

public void OnStateEnter() => ResetTimer();

public void Update()
{
timer -= Time.deltaTime;
if (timer <= 0)
stateMachine.ChangeState(OnePunchManStates.ROTATING);
}

public void OnStateExit() => timer = 0;
private void ResetTimer() => timer = Owner.Data.IdleTime;
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/States/IdleState.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions Assets/Scripts/States/RotatingState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using StatePattern.Main;
using StatePattern.Player;

namespace StatePattern.Enemy
{
public class RotatingState : IState
{
public OnePunchManController Owner { get; set; }
private OnePunchManStateMachine stateMachine;
private float targetRotation;

public RotatingState(OnePunchManStateMachine stateMachine) => this.stateMachine = stateMachine;

public void OnStateEnter() => targetRotation = (Owner.Rotation.eulerAngles.y + 180) % 360;

public void Update()
{
// Calculate and set the character's rotation based on the target rotation.
Owner.SetRotation(CalculateRotation());
if (IsRotationComplete())
stateMachine.ChangeState(OnePunchManStates.IDLE);
}

public void OnStateExit() => targetRotation = 0;

private Vector3 CalculateRotation() => Vector3.up * Mathf.MoveTowardsAngle(Owner.Rotation.eulerAngles.y, targetRotation, Owner.Data.RotationSpeed * Time.deltaTime);

private bool IsRotationComplete() => Mathf.Abs(Mathf.Abs(Owner.Rotation.eulerAngles.y) - Mathf.Abs(targetRotation)) < Owner.Data.RotationThreshold;
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/States/RotatingState.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

58 changes: 58 additions & 0 deletions Assets/Scripts/States/ShootingState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using StatePattern.Enemy;
using StatePattern.Main;
using StatePattern.Player;

namespace StatePattern.Enemy
{
public class ShootingState : IState
{
public OnePunchManController Owner { get; set; }
private OnePunchManStateMachine stateMachine;
private PlayerController target;
private float shootTimer;

public ShootingState(OnePunchManStateMachine stateMachine) => this.stateMachine = stateMachine;

public void OnStateEnter()
{
SetTarget();
shootTimer = 0;
}

public void Update()
{
Quaternion desiredRotation = CalculateRotationTowardsPlayer();
Owner.SetRotation(RotateTowards(desiredRotation));

if (IsRotationComplete(desiredRotation))
{
shootTimer -= Time.deltaTime;
if (shootTimer <= 0)
{
ResetTimer();
Owner.Shoot();
}
}
}

public void OnStateExit() => target = null;

private void SetTarget() => target = GameService.Instance.PlayerService.GetPlayer();

private Quaternion CalculateRotationTowardsPlayer()
{
Vector3 directionToPlayer = target.Position - Owner.Position;
directionToPlayer.y = 0f;
return Quaternion.LookRotation(directionToPlayer, Vector3.up);
}

private Quaternion RotateTowards(Quaternion desiredRotation) => Quaternion.LerpUnclamped(Owner.Rotation, desiredRotation, Owner.Data.RotationSpeed / 30 * Time.deltaTime);

private bool IsRotationComplete(Quaternion desiredRotation) => Quaternion.Angle(Owner.Rotation, desiredRotation) < Owner.Data.RotationThreshold;

private void ResetTimer() => shootTimer = Owner.Data.RateOfFire;
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/States/ShootingState.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading