У меня есть несколько сборных. У каждого объекта есть скрипт, позволяющий его вращать (Скрипт "Вращение"). Я пытаюсь остановить на несколько секунд скорость вращения в моих объектах-клонах каждый раз, когда я нажимаю кнопку, которую я добавил на главный экран моей сцены в Unity. думаю, что лучшим решением было бы найти каждый объект с определенным тегом (все клоны имеют один и тот же тег). После нажатия кнопки каждый объект с указанным тегом должен остановиться. К сожалению, это не работает с объектами, являющимися клонами... Кто-нибудь может решить мою проблему?
У каждого клона есть скрипт ротации:
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);
}
}
Объекты создаются с помощью скрипта SunSpawner:
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);
}
}
}
Теперь я добавил Canvas и кнопку, в которой я хотел использовать функцию OnClick для остановки вращения в каждом объекте (клоне), который существует и имеет определенный тег (в моем случае это «Журнал»). Как я уже писал, я не могу этого сделать. Я пробовал несколько вещей: создать список, найти тег, обратиться к скрипту Rotation и запустить сопрограмму, но ничего не работает. В настоящее время у меня нет скрипта, добавленного к кнопке остановки, потому что я не знаю, как это решить.





Один из способов сделать это — через События.
Вращающиеся объекты подписываются на событие в тот момент, когда они создаются, и вы используете свои кнопки для вызова события, эффективно изменяя их состояние.
Под компонентом на холсте:
(Он не обязательно должен находиться прямо под вашим Canvas GameObject, но где угодно в вашем коде. Важно вызывать методы)
// 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(); }
Скрипт вращения:
(Этот скрипт должен быть на каждом вращающемся объекте в вашей сцене)
(Сценарий выше вызывает статические методы этого класса)
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);
}
Другой способ сделать это — FindObjectsOfType(), который менее эффективен, чем Events.
(Ссылка на документы: https://docs.unity3d.com/ScriptReference/Object.FindObjectsOfType.html)
Ты
Под компонентом на холсте:
// 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; }
}
Скрипт вращения:
(Этот скрипт должен быть на каждом вращающемся объекте в вашей сцене)
public float Speed;
bool shouldRotate = true;
void Update () {
if (!shouldRotate) { return; }
transform.Rotate (0, 0, Speed);
}
Спасибо. Не был уверен, что это сработает с прямой отпиской лямбд, но был уверен, что кто-нибудь это заметит :) Отредактировал ответ для работы с кешированным действием.
Я столкнулся с вопросом о лямбда-событии через несколько минут после прочтения вашего ответа, иначе я бы не заметил. :P Интеллектуально я знаю о проблеме с лямбдой, я просто не заметил.
Примечание: Как удалить обработчик лямбда-событий