在 Unity 中,如何根据另一个脚本中的随机选择动态修改游戏对象标签?
In Unity, how do I dynamically modify a gameobjects tag based on a random selection made in another script?
问题
我正在尝试制作一个 bubble/balloon popper 风格的游戏,并且有一个 Spawner 脚本 (Spawner.cs),它包含一个对象池(泡泡),然后这个 Spawner 脚本随机选择,池中的对象之一。
从这里开始,附加到池中所有泡泡的另一个脚本 (Bubble.cs) 应该检查 Spawner 脚本以查看池中的哪个泡泡当前被选为安全泡泡。如果这个气泡与当前的 safeBubble 匹配,那么气泡应该将它的标签更改为“安全”,如果它与 safeBubble 不匹配,那么它的标签应该是“Bad”。
似乎 Bubble.cs 最初会检查和设置(当我第一次点击播放时)但只有那时,他们才不会在选择第一个 safeBubble 后取消设置/重新检查,喜欢它应该。
想法是 safeBubble 随机变化,因此 active/spawned 气泡上的标签应该改变以反映它们是“安全”还是“坏”。
代码和我尝试过的东西
这是我的脚本,唯一没有提供的脚本是 GM.cs 但那只是乐谱管理器。
Bubble.cs
public class Bubble : MonoBehaviour{
public Spawner spawner;
public float popPoint = 10f;
public float spinSpeed;
public float riseSpeed;
public AudioSource popAudio;
public bool safe;
void Start(){
transform.name = transform.name.Replace("(Clone)","").Trim();
riseSpeed= Random.Range(0.05f, 0.1f);
spinSpeed= Random.Range(0.1f, 0.5f);
if (this.gameObject == spawner.safeBubble) {
this.tag ="Safe";
} else{
this.tag ="Bad";
}
}
void Update(){
if ( this.gameObject == spawner.safeBubble ){
this.tag ="Safe";
} else {
this.tag ="Bad";
}
transform.Translate (Vector3.up * riseSpeed, Space.World);
transform.Rotate (Vector3.right * 2* Time.deltaTime);
transform.Rotate (Vector3.up * spinSpeed* Time.deltaTime);
if(gameObject.transform.position.y >= popPoint ){
gameObject.SetActive(false);
}
}
}
Spawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Spawner : MonoBehaviour{
public int index;
public int randomIndex;
public List<GameObject>[] pool;
public GameObject[] bubbles;
public GameObject greenBubble;
public GameObject orangeBubble;
public GameObject pinkBubble;
public GameObject purpleBubble;
public GameObject redBubble;
public GameObject blueBubble;
public GameObject safeBubble;
public float timeBetweenSpawns;
public float speed = 1.0f;
public float swapTime;
public Transform spawnLoc;
public Vector3 Position1;
public Vector3 Position2;
public Image BubbleToPopImg;
public Sprite green;
public Sprite orange;
public Sprite pink;
public Sprite purple;
public Sprite red;
public Sprite blue;
public bool willGrow = true;
void Awake(){
bubbles = new GameObject[6];
bubbles [0] = greenBubble;
bubbles [1] = orangeBubble;
bubbles [2] = pinkBubble;
bubbles [3] = purpleBubble;
bubbles [4] = redBubble;
bubbles [5] = blueBubble;
safeBubble = bubbles[Random.Range(0, 5)];
swapTime = Random.Range (2f,3f);
// Randomiser ();
timeBetweenSpawns = Random.Range (0.6f,1.2f);
InvokeRepeating ("Spawn", 1f, timeBetweenSpawns);
pool = new List<GameObject>[bubbles.Length];
for (int i = 0; i < bubbles.Length; i++){
pool[i] = new List<GameObject>();
}
// Debug.Log("Safe Bubble is " + safeBubble);
}
public GameObject GetPooledObject(){
randomIndex = Random.Range(0, pool.Length);
for (int i = 0; i < pool[randomIndex].Count; i++){
GameObject go = pool[randomIndex][i];
if (!go.activeInHierarchy){
return go;
}
}
if (willGrow){
GameObject obj = (GameObject)Instantiate(bubbles[randomIndex]);
pool[randomIndex].Add(obj);
return obj;
}
return null;
}
public void Spawn(){
GameObject bubbles = GetPooledObject ();
if(bubbles != null){
bubbles.transform.position = spawnLoc.transform.position;
bubbles.transform.rotation = spawnLoc.transform.rotation;
bubbles.SetActive(true);
}
}
void Update(){
transform.position = Vector3.Lerp (Position1, Position2, Mathf.PingPong(Time.time*speed, 1.0f));
timeBetweenSpawns -= Time.deltaTime;
swapTime -= Time.deltaTime;
if(timeBetweenSpawns<=0){
timeBetweenSpawns = Random.Range (0.6f,1.1f);
}
if(swapTime <= 0){
Randomiser ();
swapTime = Random.Range (3f,6f);
}
switch(index){
case 5: BubbleToPopImg.sprite = blue; break;
case 4: BubbleToPopImg.sprite = red; break;
case 3: BubbleToPopImg.sprite = purple; break;
case 2: BubbleToPopImg.sprite = pink; break;
case 1: BubbleToPopImg.sprite = orange; break;
case 0: BubbleToPopImg.sprite = green; break;
}
}
public void Randomiser(){
index = randomIndex;
safeBubble = bubbles[index];
// Debug.Log("Safe Bubble is " + safeBubble);
}
}
Popper.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Popper : MonoBehaviour{
public GM gm;
void Update(){
if (Input.GetMouseButtonDown(0)) {
Shoot();
}
}
void Shoot(){
RaycastHit hit;
Ray ray = GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit)) {
if(hit.collider.tag == "Bad"){
Debug.Log("Ouch");
}
if(hit.collider.tag == "Safe"){
Debug.Log("Nice");
}
}
}
}
我虽然在 Bubble.cs 的启动和更新函数中设置和检查标签的简单 if
语句会起作用,但它不起作用,我只是不管理弄明白。
我也试过使用 switch
,但结果相同。
非常感谢任何帮助。
提前致谢。
在
this.gameObject == spawner.safeBubble
您检查现有对象是否等于您的 Prefab。
这当然永远不会是真的!
相反,只需在选择预制件后立即在预制件上设置标签
// Note that here was another mistake: The maxValue is EXCLUSIVE
// so Random.Range(0,5) returns the values 0 to 4!
// rather simply use the length of the array
safeBubble = bubbles[Random.Range(0, bubbles.Length)];
foreach(var bubble in bubbles)
{
bubble.tag = bubble == safeBubble ? "Safe" : "Bad";
}
这样,每次您 Instantiate
根据预制件,标签都已正确设置,以后无需从气泡本身执行此操作。
您可以在 bubble.cs 中添加一个函数(public) 来切换气泡脚本的变量安全,然后在分配安全气泡后从 spawner.cs 调用它(您还将必须在下次分配之前调用它)。
因此,将此添加到 bubble.cs
public void changestate()
{
safe = !safe ;
if (safe) this.Tag = "Safe";
else this.Tag = "Bad";
}
注意:我建议在上面的脚本中将 'this' 更改为 'gameObject'。
现在,在 Spawner.cs 中,分配安全气泡后,您可以这样做..
safebubble.GetComponent<Bubble>().changestate();
在更改安全气泡以将其切换回不良之前,您应该做同样的事情。
在我看来,使用像这样不使用更新功能的代码对性能有好处。
我希望理解它并发现它有帮助。
补充:如果你对第一个代码感到困惑,你可以这样做..
public void makesafe() {this.Tag = "Safe";}
public void makebad() {this.Tag = "Bad";}
然后你可以像这样在生成器中使用它们..
safebubble = bubbles[Random.Range(0, 5)];
safebubble.GetComponent<Bubble>().makesafe();
随机函数应该是这样的..
public void Randomizer()
{
if (safebubble != null) safebubble.GetComponent<Bubble>().makebad();
index = randomindex;
safebubble = bubbles[randomindex];
safebubble.GetComponent<Bubble>().makesafe();
}
抱歉解释不当。
问题
我正在尝试制作一个 bubble/balloon popper 风格的游戏,并且有一个 Spawner 脚本 (Spawner.cs),它包含一个对象池(泡泡),然后这个 Spawner 脚本随机选择,池中的对象之一。
从这里开始,附加到池中所有泡泡的另一个脚本 (Bubble.cs) 应该检查 Spawner 脚本以查看池中的哪个泡泡当前被选为安全泡泡。如果这个气泡与当前的 safeBubble 匹配,那么气泡应该将它的标签更改为“安全”,如果它与 safeBubble 不匹配,那么它的标签应该是“Bad”。
似乎 Bubble.cs 最初会检查和设置(当我第一次点击播放时)但只有那时,他们才不会在选择第一个 safeBubble 后取消设置/重新检查,喜欢它应该。
想法是 safeBubble 随机变化,因此 active/spawned 气泡上的标签应该改变以反映它们是“安全”还是“坏”。
代码和我尝试过的东西
这是我的脚本,唯一没有提供的脚本是 GM.cs 但那只是乐谱管理器。
Bubble.cs
public class Bubble : MonoBehaviour{
public Spawner spawner;
public float popPoint = 10f;
public float spinSpeed;
public float riseSpeed;
public AudioSource popAudio;
public bool safe;
void Start(){
transform.name = transform.name.Replace("(Clone)","").Trim();
riseSpeed= Random.Range(0.05f, 0.1f);
spinSpeed= Random.Range(0.1f, 0.5f);
if (this.gameObject == spawner.safeBubble) {
this.tag ="Safe";
} else{
this.tag ="Bad";
}
}
void Update(){
if ( this.gameObject == spawner.safeBubble ){
this.tag ="Safe";
} else {
this.tag ="Bad";
}
transform.Translate (Vector3.up * riseSpeed, Space.World);
transform.Rotate (Vector3.right * 2* Time.deltaTime);
transform.Rotate (Vector3.up * spinSpeed* Time.deltaTime);
if(gameObject.transform.position.y >= popPoint ){
gameObject.SetActive(false);
}
}
}
Spawner.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Spawner : MonoBehaviour{
public int index;
public int randomIndex;
public List<GameObject>[] pool;
public GameObject[] bubbles;
public GameObject greenBubble;
public GameObject orangeBubble;
public GameObject pinkBubble;
public GameObject purpleBubble;
public GameObject redBubble;
public GameObject blueBubble;
public GameObject safeBubble;
public float timeBetweenSpawns;
public float speed = 1.0f;
public float swapTime;
public Transform spawnLoc;
public Vector3 Position1;
public Vector3 Position2;
public Image BubbleToPopImg;
public Sprite green;
public Sprite orange;
public Sprite pink;
public Sprite purple;
public Sprite red;
public Sprite blue;
public bool willGrow = true;
void Awake(){
bubbles = new GameObject[6];
bubbles [0] = greenBubble;
bubbles [1] = orangeBubble;
bubbles [2] = pinkBubble;
bubbles [3] = purpleBubble;
bubbles [4] = redBubble;
bubbles [5] = blueBubble;
safeBubble = bubbles[Random.Range(0, 5)];
swapTime = Random.Range (2f,3f);
// Randomiser ();
timeBetweenSpawns = Random.Range (0.6f,1.2f);
InvokeRepeating ("Spawn", 1f, timeBetweenSpawns);
pool = new List<GameObject>[bubbles.Length];
for (int i = 0; i < bubbles.Length; i++){
pool[i] = new List<GameObject>();
}
// Debug.Log("Safe Bubble is " + safeBubble);
}
public GameObject GetPooledObject(){
randomIndex = Random.Range(0, pool.Length);
for (int i = 0; i < pool[randomIndex].Count; i++){
GameObject go = pool[randomIndex][i];
if (!go.activeInHierarchy){
return go;
}
}
if (willGrow){
GameObject obj = (GameObject)Instantiate(bubbles[randomIndex]);
pool[randomIndex].Add(obj);
return obj;
}
return null;
}
public void Spawn(){
GameObject bubbles = GetPooledObject ();
if(bubbles != null){
bubbles.transform.position = spawnLoc.transform.position;
bubbles.transform.rotation = spawnLoc.transform.rotation;
bubbles.SetActive(true);
}
}
void Update(){
transform.position = Vector3.Lerp (Position1, Position2, Mathf.PingPong(Time.time*speed, 1.0f));
timeBetweenSpawns -= Time.deltaTime;
swapTime -= Time.deltaTime;
if(timeBetweenSpawns<=0){
timeBetweenSpawns = Random.Range (0.6f,1.1f);
}
if(swapTime <= 0){
Randomiser ();
swapTime = Random.Range (3f,6f);
}
switch(index){
case 5: BubbleToPopImg.sprite = blue; break;
case 4: BubbleToPopImg.sprite = red; break;
case 3: BubbleToPopImg.sprite = purple; break;
case 2: BubbleToPopImg.sprite = pink; break;
case 1: BubbleToPopImg.sprite = orange; break;
case 0: BubbleToPopImg.sprite = green; break;
}
}
public void Randomiser(){
index = randomIndex;
safeBubble = bubbles[index];
// Debug.Log("Safe Bubble is " + safeBubble);
}
}
Popper.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Popper : MonoBehaviour{
public GM gm;
void Update(){
if (Input.GetMouseButtonDown(0)) {
Shoot();
}
}
void Shoot(){
RaycastHit hit;
Ray ray = GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit)) {
if(hit.collider.tag == "Bad"){
Debug.Log("Ouch");
}
if(hit.collider.tag == "Safe"){
Debug.Log("Nice");
}
}
}
}
我虽然在 Bubble.cs 的启动和更新函数中设置和检查标签的简单 if
语句会起作用,但它不起作用,我只是不管理弄明白。
我也试过使用 switch
,但结果相同。
非常感谢任何帮助。
提前致谢。
在
this.gameObject == spawner.safeBubble
您检查现有对象是否等于您的 Prefab。
这当然永远不会是真的!
相反,只需在选择预制件后立即在预制件上设置标签
// Note that here was another mistake: The maxValue is EXCLUSIVE
// so Random.Range(0,5) returns the values 0 to 4!
// rather simply use the length of the array
safeBubble = bubbles[Random.Range(0, bubbles.Length)];
foreach(var bubble in bubbles)
{
bubble.tag = bubble == safeBubble ? "Safe" : "Bad";
}
这样,每次您 Instantiate
根据预制件,标签都已正确设置,以后无需从气泡本身执行此操作。
您可以在 bubble.cs 中添加一个函数(public) 来切换气泡脚本的变量安全,然后在分配安全气泡后从 spawner.cs 调用它(您还将必须在下次分配之前调用它)。
因此,将此添加到 bubble.cs
public void changestate()
{
safe = !safe ;
if (safe) this.Tag = "Safe";
else this.Tag = "Bad";
}
注意:我建议在上面的脚本中将 'this' 更改为 'gameObject'。
现在,在 Spawner.cs 中,分配安全气泡后,您可以这样做..
safebubble.GetComponent<Bubble>().changestate();
在更改安全气泡以将其切换回不良之前,您应该做同样的事情。
在我看来,使用像这样不使用更新功能的代码对性能有好处。
我希望理解它并发现它有帮助。
补充:如果你对第一个代码感到困惑,你可以这样做..
public void makesafe() {this.Tag = "Safe";}
public void makebad() {this.Tag = "Bad";}
然后你可以像这样在生成器中使用它们..
safebubble = bubbles[Random.Range(0, 5)];
safebubble.GetComponent<Bubble>().makesafe();
随机函数应该是这样的..
public void Randomizer()
{
if (safebubble != null) safebubble.GetComponent<Bubble>().makebad();
index = randomindex;
safebubble = bubbles[randomindex];
safebubble.GetComponent<Bubble>().makesafe();
}
抱歉解释不当。