- Home /
How to end this infinite loop problem in C#!?
SO, pretty much i tried to make a script which made the enemy approach the target (player) and stopped at a distance. Now i wanted the enemy to hit me after a few second intervals. I dunno what went wrong, but apparently something did, thats why i am running an infinte...
please help, here is the code
using UnityEngine;
using System.Collections;
public class AI : MonoBehaviour {
public Transform target;
public float moveSpeed = 50f;
float pos1, pos2;
float playerHealth;
public float attackSpeed = 1;
// Use this for initialization
void Start () {
playerHealth = target.GetComponent<hp>().curHealth;
}
// Update is called once per frame
void Update ()
{
Vector3 pos1 = target.transform.position;
Vector3 pos2 = gameObject.transform.position;
if (Vector3.Distance (pos1, pos2) < 10 && Vector3.Distance (pos1, pos2) > 2)
{
transform.LookAt(target);
gameObject.transform.position += gameObject.transform.forward * moveSpeed * Time.deltaTime;
}
else if (Vector3.Distance (pos1, pos2) < 2 && Vector3.Distance (pos1, pos2) > 0)
{
while (playerHealth > 0) {
hit();
}
}
}
IEnumerator hit()
{
playerHealth -= 5;
yield return new WaitForSeconds (attackSpeed);
}
}
What is the infinite loop causing? Or is it just an error?
Seems you get stuck in your while loop. Perhaps try something that isn't while or add something in to break your loop.
Answer by perchik · Jul 28, 2014 at 04:00 PM
Well, your while loop is a problem because of what you're trying to do.
IEnumerators are designed to run asynchronous operations which is not how you're using it. Seems like you want the player to keep taking damage while they're in a specific location, but only every few seconds (I assume it's like, standing in fire hurts every 2 seconds or something.)
Get rid of the while loop and keep track of the time manually.
using UnityEngine;
using System.Collections;
public class AI : MonoBehaviour {
public Transform target;
public float moveSpeed = 50f;
float pos1, pos2;
float playerHealth;
public float attackSpeed = 1;
public float lastAttackTime =0;
// Use this for initialization
void Start () {
playerHealth = target.GetComponent<hp>().curHealth;
}
// Update is called once per frame
void Update ()
{
Vector3 pos1 = target.transform.position;
Vector3 pos2 = gameObject.transform.position;
if (Vector3.Distance (pos1, pos2) < 10 && Vector3.Distance (pos1, pos2) > 2)
{
transform.LookAt(target);
gameObject.transform.position += gameObject.transform.forward * moveSpeed * Time.deltaTime;
}
else if (Vector3.Distance (pos1, pos2) < 2 && Vector3.Distance (pos1, pos2) > 0)
{
if(Time.time - lastAttackTime > attackSpeed)
{
lastAttackTime = Time.time;
playerHealth -=5;
}
}
}
}
thank you, atleast it ended the infinite loop, what it did not was to attack the user. So, can you make some improvement?
Answer by Ryzokuken · Jul 29, 2014 at 02:13 AM
I kind helped myself, i figured out that you cannot run IEnumerator functions cannot be run on update plainly, so i used StartCoroutine() kinda this::
else if (Vector3.Distance (pos1, pos2) < 1.5 && Vector3.Distance (pos1, pos2) > 0)
{
while (playerHP.curHealth > 0) {
hit();
}
}
was converted to this
else if (Vector3.Distance (pos1, pos2) < 1.5 && Vector3.Distance (pos1, pos2) > 0)
{
while (playerHP.curHealth > 0) {
StartCoroutine(hit());
}
}
That shouldn't work... You will now start the coroutine every frame and kill your player pretty quickly.
You could fix this by checking a bool to see if you were currently attacking. But see my answer for a completely different approach.
Answer by Kiwasi · Jul 29, 2014 at 09:39 AM
Another way to achieve this would be to abandon Update altogether and just use a coroutine.
using UnityEngine;
using System.Collections;
public class AI : MonoBehaviour {
public Transform target;
public float moveSpeed = 50f;
float playerHealth;
public float attackSpeed = 1;
// Use this for initialization
void Start () {
playerHealth = target.GetComponent<hp>().curHealth;
StartCoroutine(Behaviour());
}
// Update is not used...
void Update () {}
IEnumerator Behaviour () {
while (true){
while (Vector3.Distance (target.transform.position, gameObject.transform.position) < 10 && Vector3.Distance (target.transform.position, gameObject.transform.position) > 2){
yeild return StartCouroutine(Move());
}
// Checking the player health first to avoid unneeded distance checks
while (playerHealth > 0 && Vector3.Distance (target.transform.position, gameObject.transform.position) < 2 && Vector3.Distance (target.transform.position, gameObject.transform.position) > 0){
yeild return StartCoroutine(Hit());
}
yield return null;
}
}
IEnumerator Hit() {
playerHealth -= 5;
yield return new WaitForSeconds (attackSpeed);
}
IEnumerator Move () {
transform.LookAt(target);
gameObject.transform.position += gameObject.transform.forward * moveSpeed * Time.deltaTime;
yield return null;
}
}
sqr$$anonymous$$agnitude should also be used ins$$anonymous$$d of distance. You should also calculate the distance once for both the close and far checks. I got lazy and copied the code from your question.
Your answer
Follow this Question
Related Questions
Distribute terrain in zones 3 Answers
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Multiple Cars not working 1 Answer
itween: firing oncomplete AFTER ONE LOOP 0 Answers
Turning Spinners Based on an Integer 0 Answers