Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
12 Jun 22 - 14 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 /
avatar image
1
Question by AntLewis · Jul 07, 2016 at 10:01 AM · coroutinesinterfaces

Implementating a coroutine within an interface

Hi guys, I've been following the live tutorial on interfaces to make an AI state machine .I've pasted the code below (but only included one implementation of the interface to keep it short!)

 using UnityEngine;
 using System.Collections;
 
 public class StatePatternEnemy : MonoBehaviour 
 {
     public float searchingTurnSpeed = 120f;
     public float searchingDuration = 4f;
     public float sightRange = 20f;
     public Transform[] wayPoints;
     public Transform eyes;
     public Vector3 offset = new Vector3 (0,.5f,0);
     public MeshRenderer meshRendererFlag;
 
 
     [HideInInspector] public Transform chaseTarget;
     [HideInInspector] public IEnemyState currentState;
     [HideInInspector] public ChaseState chaseState;
     [HideInInspector] public AlertState alertState;
     [HideInInspector] public PatrolState patrolState;
     [HideInInspector] public NavMeshAgent navMeshAgent;
 
     private void Awake()
     {
         chaseState = new ChaseState (this);
         alertState = new AlertState (this);
         patrolState = new PatrolState (this);
 
         navMeshAgent = GetComponent<NavMeshAgent> ();
     }
 
     // Use this for initialization
     void Start () 
     {
         currentState = patrolState;
     }
     
     // Update is called once per frame
     void Update () 
     {
         currentState.UpdateState ();
     }
 
     private void OnTriggerEnter(Collider other)
     {
         currentState.OnTriggerEnter (other);
     }
 }

The interface:

 using UnityEngine;
 using System.Collections;
 
 public interface IEnemyState
 {
 
     void UpdateState();
 
     void OnTriggerEnter (Collider other);
 
     void ToPatrolState();
 
     void ToAlertState();
 
     void ToChaseState();
 }

..and an implementation of the interface:

 using UnityEngine;
 using System.Collections;
 
 public class PatrolState : IEnemyState 
 
 {
     private readonly StatePatternEnemy enemy;
     private int nextWayPoint;
 
     public PatrolState (StatePatternEnemy statePatternEnemy)
     {
         enemy = statePatternEnemy;
     }
 
     public void UpdateState()
     {
         Look ();
         Patrol ();
     }
     
     public void OnTriggerEnter (Collider other)
     {
         if (other.gameObject.CompareTag ("Player"))
             ToAlertState ();
     }
     
     public void ToPatrolState()
     {
         Debug.Log ("Can't transition to same state");
     }
     
     public void ToAlertState()
     {
         enemy.currentState = enemy.alertState;
     }
     
     public void ToChaseState()
     {
         enemy.currentState = enemy.chaseState;
     }
 
     private void Look()
     {
         RaycastHit hit;
         if (Physics.Raycast (enemy.eyes.transform.position, enemy.eyes.transform.forward, out hit, enemy.sightRange) && hit.collider.CompareTag ("Player")) {
             enemy.chaseTarget = hit.transform;
             ToChaseState();
         }
     }
 
     void Patrol ()
     {
         enemy.meshRendererFlag.material.color = Color.green;
         enemy.navMeshAgent.destination = enemy.wayPoints [nextWayPoint].position;
         enemy.navMeshAgent.Resume ();
 
         if (enemy.navMeshAgent.remainingDistance <= enemy.navMeshAgent.stoppingDistance && !enemy.navMeshAgent.pathPending) {
             nextWayPoint =(nextWayPoint + 1) % enemy.wayPoints.Length;
         
         }
 
 
     }
 }

Not having used interfaces before, it seems like a really nice and clean pattern but I've encountered a problem when in an implementation of the interface I've tried to use a coroutine. I appreciate why this doesn't work - implementations of the interface don't inherit from a monobehaviour. So my question is, what is the cleanest method starting a coroutine within an implementation of an interface?

As I understand it there are two ways:

  1. In the interface, also inherit from a monobehaviour (as I say I'm pretty inexperienced with interfaces). However, I know doing this means I can't call a constructor, and I'd also need to add all the interfaces to the gameobject as components? Is that correct?

  2. Within the interface, use the reference to StatePatternEnemy (called enemy) and use that to trigger the coroutine from StatePatternBehaviour. So as an example I'd add this code to StatePatternEnemy:

      public void TriggerCoroutine(IEnumerator whichCoroutine ){
             StartCoroutine(whichCoroutine);
         }
    
    

and within PatrolState, I'd add this:

     public void StartState()
     {
             // enemy is a reference to StatePatternEnemy
         enemy.TriggerCoroutine( ScanBehaviour () );
 
     }

and within PatrolState also add the actual coroutine:

     IEnumerator ScanBehaviour()
     { 
         // Coroutine code, do whatever....
             yield return null;
          
     }

..and if I wanted to stop a coroutine, I'd repeat as above adding a CancelCoroutine function in StatePatternEnemy that uses StopCoroutine (instead of start).

Any advice on this would be much appreciated!

Thanks!

Comment
Add comment · Show 1
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
avatar image ericbegue · Jul 08, 2016 at 11:02 AM 0
Share

I would like to suggest an alternative to State $$anonymous$$achines for writing AIs. State $$anonymous$$achines becomes tedious to create and modify as the AIs grow in complexity, because of the inter-dependencies of the states due to the transition conditions. You're already experiencing that with a 3 state AI: Patrol, Alert and Chase.

You might be interested in Behaviour Tree (BT), which is a nice tool be build AI with. Though harder to learn and to master than FS$$anonymous$$, BT is simpler to use and yet you can achieved more complex AIs more easily.

I'm the author of Panda BT, a script-based behaviour framework. If you are interested, this package contains examples of patrolling-chasing-attacking behaviours.

2 Replies

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by Bunny83 · Jul 07, 2016 at 01:12 PM

There are several solutions for this. The easiest way is to use a simple singleton MonoBehaviour that runs the coroutines. I once created the CoroutineHelper class which does exactly this. It provides a way to run coroutines on a singleton instance.

In your case you only need a MonoBehaviour singleton so you can use it's StartCoroutine method. The actual coroutine (the generator method that returns IEnumerator) can be defined in your custom class.

So all you would need is a singleton implementation which you can use like that:

 // CoroutineHost.cs
 public class CoroutineHost : MonoBehaviourSingleton<CoroutineHost> { }

With that class you can simply do:

 CoroutineHost.Instance.StartCoroutine( ... );

in any class.

edit

If you want to be able to stop a coroutine you have to store the actual coroutine reference which you need to stop it

 Coroutine someCoroutine;
 
 someCoroutine = CoroutineHost.Instance.StartCoroutine( MyCoroutine() );


To stop that coroutine you just have to do this:

 CoroutineHost.Instance.StopCoroutine( someCoroutine );

You can not use StopCoroutine( MyCoroutine() ) as "MyCoroutine" will return a new IEnumerator each time you call it.

Comment
Add comment · Show 1 · Share
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
avatar image AntLewis · Jul 07, 2016 at 04:33 PM 0
Share

Great - thanks so much for the info, incredible useful

avatar image
0

Answer by TimCoster · Jul 15, 2019 at 12:26 PM

Don't know if it's the correct way but it seems to works fine if you put System.Collections. in front of the IEnumerator:

 using UnityEngine;
 
 public interface IWeapon
 {
     System.Collections.IEnumerator Fire(Transform target);
 }
Comment
Add comment · Share
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

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

48 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 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

WWW download in background during position animation 2 Answers

Time.time undependable in a coroutine? 1 Answer

Dynamically updating a Coroutine's parameters every frame 1 Answer

How to stop a coroutine with multiple parameters? 1 Answer

Need help on making a semi-circle rotation 1 Answer


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