在 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();

}

抱歉解释不当。