0

I have a few prefabs. Each object has a script that allows it to rotate (Script "Rotation"). I try to stop, for a few seconds, the rotation speed in my clone objects, every time when I press a button that I added to the main screen of my scene in Unity. think the best solution would be to find every object with a specific tag (all clones have the same tag). After pressing the button, each object with the specified tag should stop. Unfortunately, it doesn't work on objects that are clones... Can anyone solve my problem?

Each clone has a rotation script:

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

public class Rotation : MonoBehaviour {

    public float speed;
    public float speed2 = 0f;
    private Rigidbody2D rb2D;


    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    public void Update () {

        transform.Rotate (0, 0, speed);
    }

    public void Stop (){

        StartCoroutine(SpeedZero());
        Debug.Log ("ZEROOOOO");
    }

    IEnumerator SpeedZero()
    {
        transform.Rotate (0, 0, speed2);
        yield return new WaitForSeconds(20);
        transform.Rotate (0, 0, speed);

    }
}

The objects are spawned using the SunSpawner script:

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

public class SunSpawner : MonoBehaviour {


    public GameObject[] theSuns;
    public Transform generationPoint;


    private int sunSelector;
    private float sceneHeight;

    float distance = 0.5f;


    Vector3 maxWidthPoint;
    Vector3 minWidthPoint;

    //Radious base on circle collider radious
    float lastSunRadious = 2f;

    public void Update (){

        if (transform.position.y < generationPoint.position.y) {

            sunSelector = Random.Range(0, theSuns.Length);
            float currentSunRadious = theSuns[sunSelector].GetComponentInChildren<CircleCollider2D>().radius * theSuns[sunSelector].GetComponentInChildren<CircleCollider2D>().transform.localScale.x * theSuns[sunSelector].transform.localScale.x;
            float distanceBetween = distance + lastSunRadious + currentSunRadious; //Random.Range(lastSunRadious+currentSunRadious, sceneHeight);
            float sunXPos = Random.Range(minWidthPoint.x + currentSunRadious, maxWidthPoint.x - currentSunRadious);

            Vector3 newSunPosition = new Vector3(sunXPos, transform.position.y + distanceBetween, transform.position.z);

            transform.position = newSunPosition;
            lastSunRadious = currentSunRadious;
            Instantiate (theSuns [sunSelector], transform.position, transform.rotation);

        }
    }
}

Now I added Canvas and a button in which I wanted to use the OnClick function to stop rotation in every object (clone) that exists and has a specific tag (in my case it is "Log"). As I wrote, I can't do it. I tried a few things, create a list, search for a tag, refer to the Rotation script and run coroutine, but nothing works. Currently, I don't have any script added to the stop button, because I don't know how to solve it.

Polan31
  • 11
  • 1
  • 5

1 Answers1

0

One way to do this is via Events.
The rotating objects subscribe to an event the moment they're instantiated and you use your button(s) to invoke the event, effectively changing their state.


Under a Component on your Canvas:
(It doesn't have to be directly under your Canvas GameObject, but anywhere in your code. The important thing is to call the methods)

// Call these methods from your onClick from the appropriate button.
// For example the Stop button should call StopClonesRotation().
public void StopClonesRotation() { Rotation.StopRotating(); }
public void StartClonesRotation() { Rotation.StartRotating(); }

Rotation Script:
(This script should be on every Rotating Object on your scene)
(The script above makes calls to this class' static methods)

public delegate void RotateAction();
public static event RotateAction StopRotating;
public static event RotateAction StartRotating;

RotateAction startAction;
RotateAction endAction;

public float Speed;
bool shouldRotate = true;


private void Awake() {
    startAction = () => shouldRotate = true;
    endAction = () => shouldRotate = false;
}
void OnEnable() {
    StartRotating += startAction;
    StopRotating += endAction;
}
void OnDisable() {
    StartRotating -= startAction;
    StopRotating -= endAction;
}

void Update () {
   if (!shouldRotate) { return; }
   transform.Rotate (0, 0, Speed);
}

Another way to do this is FindObjectsOfType(), which is way less performant than Events.
(Link to the docs: https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html)
You

Under a Component on your Canvas:

// Call these methods from your onClick from the appropriate button.
// For example the Stop button should call StopClonesRotation().
public void StopClonesRotation() { 
   var allRotatingObjects = FindObjectsOfType<Rotation>();
   foreach (var rotatingObj in allRotatingObjects) { rotatingObj.shouldRotate = false; }
}
public void StartClonesRotation() { 
   var allRotatingObjects = FindObjectsOfType<Rotation>();
   foreach (var rotatingObj in allRotatingObjects) { rotatingObj.shouldRotate = true; }
}

Rotation Script:
(This script should be on every Rotating Object on your scene)

public float Speed;
bool shouldRotate = true;

void Update () {
   if (!shouldRotate) { return; }
   transform.Rotate (0, 0, Speed);
}
Lyrca
  • 528
  • 2
  • 15
  • 1
    Note: [How to remove a lambda event handler](https://stackoverflow.com/questions/1362204/how-to-remove-a-lambda-event-handler) – Draco18s no longer trusts SE Jul 21 '19 at 18:56
  • Thanks. Wasn't sure if it'd work with directly unsubscribing lamdas but was sure someone would spot this :) *Edited the answer to work with a cached action.* – Lyrca Jul 22 '19 at 09:13
  • 1
    I ran into a lambda event question a few minutes after reading your answer otherwise I wouldn't have noticed. :P Intellectually I'm aware of the lambda problem, I just didn't notice. – Draco18s no longer trusts SE Jul 22 '19 at 14:34