Home > Software design >  My Colors are not waiting the time I'm giving them actually there not waiting at all instead th
My Colors are not waiting the time I'm giving them actually there not waiting at all instead th

Time:07-15

I don't know where I went wrong here, I'm trying to make a random choice attack system, well kind of but instead it's not waiting and at all for anything but probably for the first wait time. The results I'm looking for is: wait for amount of seconds then pick a random attack then change color and go back to original color then repeat process

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BossMovement : MonoBehaviour
{
    // changes color
    public Color originalColor;
   

    public Transform spawnPoint;

    // weapons

    //choses a  Attackmove to do
    int AttackChoice;

    
    public float distanceStop;
    public float distanceR;
    /// changes the material of the boss 
    private Material mymaterial;

    //animator 
    public Animator anim;

    public float distance;
    public float distance3;
    // player 
    public Transform target;

    // how fast we are going
    public float speed = 4f;
    public float speedR;




    Rigidbody rig;
    // Start is called before the first frame update
    private void Start()
    {
        rig = GetComponent<Rigidbody>();
        anim = GetComponentInChildren<Animator>();
        
        
    }
    
    private void Update()
    {
        
        whento();
        StopFollowing();
        StartCoroutine(AttackChoices());

    }
    // Update is called once per frame
    void followPlayer()
    {
        var step = speed * Time.deltaTime;
        transform.position = Vector3.MoveTowards(rig.transform.position, target.position, step);
        

    }
            
    IEnumerator  AttackChoices()
    {
        yield return new WaitForSeconds(15);
        AttackChoice = Random.Range(0, 4);
        

        if (AttackChoice == 1)
        {
            
            gameObject.GetComponentInChildren<Renderer>().material.color = Color.white;
            yield return new WaitForSeconds(15);
            gameObject.GetComponentInChildren<Renderer>().material.color  = originalColor;
        }

        if (AttackChoice == 2)
        {
            
            gameObject.GetComponentInChildren<Renderer>().material.color = Color.blue;
            yield return new WaitForSeconds(15);
            gameObject.GetComponentInChildren<Renderer>().material.color = originalColor;
        }
        if (AttackChoice == 3)
        {

            gameObject.GetComponentInChildren<Renderer>().material.color = Color.red;
            yield return new WaitForSeconds(15);
            gameObject.GetComponentInChildren<Renderer>().material.color = originalColor;
        }

        if (AttackChoice == 4)
        {

            yield return new WaitForSeconds(15);
        }

    }
    void whento()
    {
        // follow player
        transform.LookAt(target);

        //raycast that shoots at player
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit, distance))
        {
            if (hit.transform.CompareTag("Player"))
            {
                followPlayer();
                anim.SetFloat("Speed", 1, 0f, Time.deltaTime);
            }
        }
        else
        {
            anim.SetFloat("Speed", 0, 0.1f, Time.deltaTime);
        }
    }

    void StopFollowing()
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, transform.forward, out hit, distance3))
        {

            if (hit.transform.CompareTag("Player"))
            {
                distance = distanceStop;
            }
        }
        else
        {
            distance = distanceR;
        }
    }

        private void ChargeUpAndRealse()
        {
            anim.SetLayerWeight(anim.GetLayerIndex("ChargeLayer"), 1);
            anim.SetTrigger("Charge");
            anim.SetLayerWeight(anim.GetLayerIndex("ChargeLayer"), 0);
        }

    
}




    

CodePudding user response:

You are doing

StartCoroutine(AttackChoices());

EVERY FRAME within Update starting thousands of concurrent running routines. A Coroutine does not delay the code which is using StartCoroutine.

You rather need to

  • make sure to run only one routine, wait for i to finish, then start the next one
  • or simply use a while loop

Like e.g.

private void Start()
{
    rig = GetComponent<Rigidbody>();
    anim = GetComponentInChildren<Animator>();
    
    StartCoroutine(AttackChoices());
}

private void Update()
{
    whento();
    StopFollowing();
}


void followPlayer()
{
    var step = speed * Time.deltaTime;
    transform.position = Vector3.MoveTowards(rig.transform.position, target.position, step);
}
        
IEnumerator  AttackChoices()
{
    while(true)
    {
        yield return new WaitForSeconds(15);
        AttackChoice = Random.Range(0, 4);

        .....
    }
}

instead of true you could of course also have a certain flag field you can disable when you want to terminate the routine


Then note that

Random.Range(0, 4);

will return one of 0, 1, 2, 3 as the upper bound is exclusive for the int overload!


In general for better performance you should cache things and use a switch:

IEnumerator  AttackChoices()
{
    var material = GetComponentInChildren<Renderer>().material;

    while(true)
    {
        yield return new WaitForSeconds(15);

        AttackChoice = Random.Range(0, 4);
        
        switch(AttackChoice)
        {
            case 0:
                yield return ColorAndReset(Color.white);
                break;

            case 1:
                yield return ColorAndReset(Color.blue);
                break;

            case 2:
                yield return ColorAndReset(Color.red);
                break;

            case 3:
                yield return new WaitForSeconds(15);
                break;
        }
    }
}

private static IEnumerator ColorAndReset(Material material, Color color)
{
    material.color = color;
    yield return new WaitForSeconds(15);
    material.color = originalColor;
}

And a last general note: If you are dealing with Rigidbody (=> Physics) you do not want to do anything via transform directly but rather only go through the Rigibody component! See e.g.

Also you want to do things in FixedUpdate (the Physics frame) in order to not break / fight against the Physics engine resulting in undesired behavior and breaking collision detection

Little hint here: The rigidbody alternative to

transform.forward

would be e.g.

rb.rotation * Vector3.forward
  • Related