Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by scr33ner · Sep 25, 2015 at 02:40 AM · c#ainpcstate-machinebehavior

Fixing enemy behavior state machine in Unity

I'm working on a state machine for my game's NPC.

The only thing I can't to get work properly is the hit sequence. The hits register. What I would like to happen is for the attack sequence (animation) to stop, play the hit animation sequence, & then go back to the chase/attack state using a coroutine.

Currently, the attack sequence seems to just loop through, ignoring the coroutine.

Here's the code attached to the NPC: using UnityEngine; using System.Collections; ///

/// State pattern enemy. /// Handles animation sequences & states /// [RequireComponent(typeof(AudioSource))] public class StatePatternEnemy : MonoBehaviour { public Transform[] wayPoints; public float searchTurnSpeed = 120f; public float searchDuration = 5f; public float sightRange = 15f; public float alertZone = 20f; public float stopAtDistance = 0f; //used to stop chase public float hitSequenceTimer = 1.25f; //use to return to attackState public float animWalkSpeed = 1f; public float animRunSpeed = 1.75f; public float animPunchSpeed = 1f; public float animGotHitSpeed = 1f;

     public GameObject nmeFistL;
     public GameObject nmeFistR;
 
     public Vector3 offset = new Vector3(0,0.5f,0);//offsets raycast so it won't aim for foot
 
     public Transform eyes;
     public bool onAlert = false;
     public Transform chaseTarget;
 
     [HideInInspector]public float         playerDistance;  //player's transform info
     [HideInInspector]public float         alertSearchTimer;//increment timer search value
     [HideInInspector]public Vector3       enemyToTarget;   //player's Vector info
     [HideInInspector]public IEnemyState   currentState;
     [HideInInspector]public AlertState   _alertState;
     [HideInInspector]public AttackState  _attackState;
     [HideInInspector]public ChaseState   _chaseState;
     [HideInInspector]public HitState     _hitState;
     [HideInInspector]public PatrolState  _patrolState;
     [HideInInspector]public NavMeshAgent _navMeshAgent;
 
     public AudioClip sfxGrunterThreat;
     public float     sfxVolume = 0.125f;
 
     public AnimationClip nmeGotHit;
     public AnimationClip nmeIdle;
     public AnimationClip nmeJump;
     public AnimationClip nmePunch;
     public AnimationClip nmeRoar;
     public AnimationClip nmeRun;
     public AnimationClip nmeTaunt;
     public AnimationClip nmeWalk;
 
     AudioSource _sfx;
     RaycastHit  _hit;
 
     private void Awake()
     {
         _alertState  = new AlertState(this);
         _attackState = new AttackState(this);
         _chaseState  = new ChaseState(this);
         _hitState    = new HitState(this);
         _patrolState = new PatrolState(this);
 
         _navMeshAgent = GetComponent<NavMeshAgent>();
         _sfx          = GetComponent<AudioSource>();
     }
 
     // Use this for initialization
     void Start ()
     {
         currentState = _patrolState;
     }
     
     // Update is called once per frame
     void Update ()
     {
         currentState.UpdateState();
         Rayline();//remove later
         BeAlert();
         print(currentState);
     }
 
     private void OnTriggerEnter(Collider other)
     {
         if (other.gameObject.CompareTag ("fireBall"))
         {
             ///create a hit state to move player
             ///back & play the hit animation after coroutine
             currentState = _hitState;
             StopAnim();
             Debug.Log("fire");
             StartCoroutine(EnemyHitSequence());
         }
     }
     public void BeAlert()
     {
         ///ensure the player is within alert zone
         float playerDistance = Vector3.Distance(chaseTarget.position, transform.position);
         if(playerDistance > alertZone)
         {
             nmeFistL.SetActive(false);
             nmeFistR.SetActive(false);
             currentState = _patrolState;
             //print("Outside alertzone: " + playerDistance);
         }
         else
         {
             //print("Alertzone: " + playerDistance);
             //print("AlertZone Timer" + alertZoneTimer);
             onAlert = true;
             enemyToTarget = ((chaseTarget.position + offset) - eyes.transform.position);
 
             //check to see if player is in visual range & is hit with the rayCast
             if(Physics.Raycast(eyes.position, enemyToTarget, out _hit, sightRange) && _hit.collider.CompareTag("Player") && (playerDistance <= sightRange))
             {
                 currentState = _chaseState;  //player is found & being chased
                 StopChase();                 //player is being attacked
                 // _attackState setUp is in stopChase method
             }
             else// <---player not found but is close, be on alert!
             {
                 //currentState = _patrolState;
                 if(onAlert == true)
                 {
                     currentState = _alertState;            //look around for a bit
                     alertSearchTimer += Time.deltaTime;
                     ///if player isn't found, go patrol
                     if(alertSearchTimer >= searchDuration)
                     {
                         onAlert = false;
                         currentState = _patrolState;//nothing is found go back & patrol
                     }
                 }
             }
         }
     }
 
     public void StopChase()
     {
         _navMeshAgent.speed = 3.5f;//slow down the navAgent
         
         float playerDistance = Vector3.Distance(chaseTarget.position, transform.position);
         //stop navMeshAgent to begin attack sequence
         if (playerDistance <= stopAtDistance)
         {
             ///set this up to go on attack
             /// ensure enemy is looking at player
             enemyToTarget = ((chaseTarget.position + offset) - eyes.transform.position);
             if(Physics.Raycast(eyes.position, enemyToTarget, out _hit, sightRange) && _hit.collider.CompareTag("Player"))
             {
                 nmeFistL.SetActive(true);
                 _navMeshAgent.Stop();
                 currentState = _attackState;
             }
             ///ensure the enemy isn't hitting air
             /// & will always look for the player
             else
             {
                 transform.Rotate(chaseTarget.position, searchTurnSpeed * Time.deltaTime, 0);
             }
         }
         print("in stop chase");
     }
     
     public void EnemyGotHit()
     {
         //print("CurrentState in enemyGotHit: " + currentState);
         //transform.Translate(0f,0.25f,-0.125f);
         AnimGotHit();
         //_navMeshAgent.Stop();
         //StartCoroutine(EnemyHitSequence());
     }
 
     IEnumerator EnemyHitSequence()
     {
         EnemyGotHit();
         print("CurrentState in hit sqnz: " + currentState);
         yield return new WaitForSeconds(hitSequenceTimer);
         //_navMeshAgent.Resume();
         currentState = _attackState;
         StopChase();
         print("CurrentState after switch in coroutine: " + currentState);
     }
 
     public void Rayline()
     {
         Vector3 forward = transform.TransformDirection(Vector3.forward) * 10;
         Debug.DrawRay(eyes.transform.position, forward, Color.green);
     }
 
     public void StopAnim()
     {
         GetComponent<Animation>().Stop("nmeWalk");
         GetComponent<Animation>().Stop("nmePunch");
     }
 
     public void AnimWalk()
     {
         GetComponent<Animation>().Play("nmeWalk", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         GetComponent<Animation>()["nmeWalk"].speed = animWalkSpeed;
     }
     public void AnimRun()
     {
         GetComponent<Animation>().Play("nmeRun", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         GetComponent<Animation>()["nmeWalk"].speed = animRunSpeed;
     }
     public void AnimPunch()
     {
         GetComponent<Animation>().Play("nmePunch", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         GetComponent<Animation>()["nmePunch"].speed = animPunchSpeed;
     }
     public void AnimRoar()
     {
         GetComponent<Animation>().Play("nmeRoar", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         //GetComponent<Animation>()["nmeRoar"].speed = animRunSpeed;
     }
     public void AnimTaunt()
     {
         GetComponent<Animation>().Play("nmeTaunt", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         GetComponent<Animation>()["nmeTaunt"].speed = animRunSpeed;
     }
     public void AnimGotHit()
     {
         GetComponent<Animation>().Play("nmeGotHit", PlayMode.StopAll);
         GetComponent<Animation>().wrapMode = WrapMode.Once;
         GetComponent<Animation>()["nmeGotHit"].speed = animGotHitSpeed;
     }
 
     public void SfxNmeThreat()
     {
         _sfx.PlayOneShot(sfxGrunterThreat, sfxVolume);
     }
 
 }
 Attack state:
 using UnityEngine;
 using System.Collections;
 /// <summary>
 /// Attack state stays within attack.
 /// Exiting out of attack sequence is handled within
 /// StatePatternEnemy
 /// </summary>
 public class AttackState : IEnemyState
 {
     private float searchTimer;
     private readonly StatePatternEnemy enemy;
     
     public AttackState (StatePatternEnemy _statePatternEnemy)
     {
         enemy = _statePatternEnemy;
     }
 
     public void UpdateState()
     {
         Look();
         AttackSequence();
     }
     
     public void OnTriggerEnter(Collider other)
     {
 
     }
     
     public void ToPatrolState()
     {
         enemy.currentState = enemy._attackState;
         searchTimer = 0f;
     }
     
     public void ToAlertState()
     {
         enemy.currentState = enemy._alertState;
         searchTimer = 0f;
     }
     
     public void ToChaseState()
     {
         enemy.currentState = enemy._attackState;
         searchTimer = 0f;
     }
     
     public void ToAttackState()
     {
         /// create a mono behavior for attack & other animation sequences
         /// check for distance
         /// if player is in range
         /// attack
         /// else
         /// ToChaseState();
         Debug.Log("Attacking");
     }
     public void ToHitState()
     {
         enemy.currentState = enemy._hitState;
         searchTimer = 0;
     }
     private void Look()
     {
         RaycastHit hit;
         Vector3 enemyToTarget = ((enemy.chaseTarget.position + enemy.offset) - enemy.eyes.transform.position);
         if(Physics.Raycast(enemy.eyes.position, enemyToTarget, out hit, enemy.sightRange) && hit.collider.CompareTag("Player"))
         {
             //Debug.Log("player found in: " + enemy.currentState);
             enemy.chaseTarget = hit.transform;
         }
         else//if player is hidden then
         {
             //Debug.Log("player not found in: " + enemy.currentState);
             ToAlertState();
         }
     }
     private void AttackSequence()
     {
         //RaycastHit hit;
         //Vector3 enemyToTarget = ((enemy.chaseTarget.position + enemy.offset) - enemy.eyes.transform.position);
         //if(Physics.Raycast(enemy.eyes.position, enemyToTarget, out hit, enemy.sightRange) && hit.collider.CompareTag("Player"))
         //{
         //    Debug.Log("start attack");
         //}
         //face the player
         //enemy.transform.Rotate(enemy.chaseTarget.position,enemy.searchTurnSpeed * Time.deltaTime, 0);//original code
         enemy._navMeshAgent.transform.LookAt(enemy.chaseTarget.position);
         enemy.AnimPunch();
     }
 }

Finally, the hit state:

 using UnityEngine;
 using System.Collections;
 /// <summary>
 /// Attack state stays within attack.
 /// Exiting out of attack sequence is handled within
 /// StatePatternEnemy
 /// </summary>
 public class HitState : IEnemyState
 {
     private float searchTimer;
     private readonly StatePatternEnemy enemy;
     
     public HitState (StatePatternEnemy _statePatternEnemy)
     {
         enemy = _statePatternEnemy;
     }
     
     public void UpdateState()
     {
         Look();
         EnemyIsHit();
     }
     
     public void OnTriggerEnter(Collider other)
     {
         if (other.gameObject.CompareTag ("fireBall"))
         {
             Debug.Log("!");
             enemy.currentState = enemy._hitState;
 
         }
     }
     
     public void ToPatrolState()
     {
         enemy.currentState = enemy._patrolState;
         searchTimer = 0f;
     }
     
     public void ToAlertState()
     {
         enemy.currentState = enemy._alertState;
         searchTimer = 0f;
     }
     
     public void ToChaseState()
     {
         enemy.currentState = enemy._chaseState;
         searchTimer = 0f;
     }
     
     public void ToAttackState()
     {
         enemy.currentState = enemy._attackState;
         searchTimer = 0f;
     }
     public void ToHitState()
     {
 
     }
     private void Look()
     {
         RaycastHit hit;
         Vector3 enemyToTarget = ((enemy.chaseTarget.position + enemy.offset) - enemy.eyes.transform.position);
         if(Physics.Raycast(enemy.eyes.position, enemyToTarget, out hit, enemy.sightRange) && hit.collider.CompareTag("Player"))
         {
             enemy.chaseTarget = hit.transform;
         }
         else//if player is hidden then
         {
             ToAlertState();
         }
     }
     private void EnemyIsHit()
     {
         //Debug.Log("HitState.cs");
         //Debug.Log("EnemyIsHit() state: " + enemy.currentState);
         //enemy.currentState = enemy._attackState;
         //Debug.Log("EnemyIsHit() After state switch: " + enemy.currentState);
         enemy._navMeshAgent.transform.LookAt(enemy.chaseTarget.position);
         enemy.StopChase(); // calling StopChase method goes back to attackState
     }
 }

I could really use some help fixing this, thank you

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
â–¼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

0 Replies

· Add your reply
  • Sort: 

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

31 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Enemy AI script for 2D platformer 1 Answer

How to make an npc/ai walk next to the player? (C#) 1 Answer

Several NPC with waypoints 1 Answer

how to smoothly transition between animations in the "Any State" state machine. 1 Answer

Enemy watches player and shoots but bullets will not project.. 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges