如何点击实例化对象获得积分,然后 link 积分对文本进行评分?
How to click on instantiated objects and get points, then link points to score text?
我想要的:
我希望玩家能够单击实例化对象并获得分数,然后将这些分数显示在记分文本中。
我做了什么:
我目前正在使用以下“FindGameObjectsWithTag”代码来检索作为实例化预制对象组件的按钮:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class CPointScore : MonoBehaviour
{
public TextMeshProUGUI CPointsText;
private float ScoreNum;
private GameObject[] CButtonGmeObjsHolder;
private void CTagFinder()
{
CButtonGmeObjsHolder = GameObject.FindGameObjectsWithTag("Ctag");
foreach (GameObject CButtonGmeObj in CButtonGmeObjsHolder)
{
Debug.Log("GmeObj Found");
Button CButton = CButtonGmeObj.GetComponent<Button>();
CButton.onClick.AddListener(AddScore);
}
}
public void AddScore()
{
ScoreNum += 1;
Debug.Log("Point Added # " + ScoreNum);
}
void Start()
{
InvokeRepeating("CTagFinder", 1f, 15.1f);
}
void Update()
{
CPointsText.text = ScoreNum.ToString();
}
}
因为 FindGameObjectsWithTag 仅在我启动 InvokeRepeating 代码后才调用。我在整个游戏过程中都有游戏对象生成,因此需要不断检查标签。
问题:
所以代码找到了标签,按钮可以被点击,记分文本更新,这很棒。问题是,如果我单击一个带标签的按钮,它会为自己注册一个点,并为当前在它之后产生的场景中的每个带标签的按钮注册一个点。例如,假设我目前在场景中有 4 个生成的对象,当单击第一个生成的对象时,它将添加 4 个点而不是 1 个。如果单击第二个生成的对象,它将添加 3 个点而不是 1 个。我想只有被点击的标记按钮注册一个点。
问题:
我可以在我的代码中更改什么,以便只有被单击的标记按钮注册一个点?
谢谢
我认为这里有两点:
- 您重复添加侦听器,因此当最终单击按钮时您将收到多个回调。
- 重复
FindGameObjectsWithTag
也很低效
您的主要问题是重复来电。
对于 CTagFinder
的每次重复调用,您将遍历所有现有按钮并执行
CButton.onClick.AddListener(AddScore);
因此这些现有按钮最终会附加 多个 听众!
您要么想确保每个按钮只调用一次,例如跟踪那些你已经为之做过的人:
private readonly HashSet<Button> alreadyRegisteredButtons = new HashSet<Button>();
然后
if(!alreadyRegisteredbuttons.Contains(CButton))
{
CButton.onClick.AddListener(AddScore);
alreadyRegisteredButtons.Add(CButton);
}
或者确保在添加之前删除回调,例如
CButton.onClick.RemoveListener(AddScore);
CButton.onClick.AddListener(AddScore);
一般来说,我不会重复使用 FindGameObjectWithTag 轮询对象。而是让你的代码事件驱动。这已经完全避免了这个问题,因为无论如何都不会重复附加监听器。
我会简单地将一个专用组件 YourComponent
附加到与按钮相同的 GameObject
并有一个全局
public static event Action<YourComponent> OnCTSButtonSpawned;
并在此专用组件中执行
private void Start()
{
OnCTSButtonSpawned?.Invoke(this);
}
并在你的 CPointScore
中收听此活动,例如
private void Awake()
{
YourComponent.OnCTSButtonSpawned += AttachListener;
}
private void AttachListener(YourComponent component)
{
if(compoenent.TryGetComponent<Button>(out var button))
{
button.onClick.AddListener(AddScore);
}
}
private void AddScore()
{
ScoreNum++;
CPointsText.text = ScoreNum.ToString();
}
我想要的: 我希望玩家能够单击实例化对象并获得分数,然后将这些分数显示在记分文本中。
我做了什么: 我目前正在使用以下“FindGameObjectsWithTag”代码来检索作为实例化预制对象组件的按钮:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class CPointScore : MonoBehaviour
{
public TextMeshProUGUI CPointsText;
private float ScoreNum;
private GameObject[] CButtonGmeObjsHolder;
private void CTagFinder()
{
CButtonGmeObjsHolder = GameObject.FindGameObjectsWithTag("Ctag");
foreach (GameObject CButtonGmeObj in CButtonGmeObjsHolder)
{
Debug.Log("GmeObj Found");
Button CButton = CButtonGmeObj.GetComponent<Button>();
CButton.onClick.AddListener(AddScore);
}
}
public void AddScore()
{
ScoreNum += 1;
Debug.Log("Point Added # " + ScoreNum);
}
void Start()
{
InvokeRepeating("CTagFinder", 1f, 15.1f);
}
void Update()
{
CPointsText.text = ScoreNum.ToString();
}
}
因为 FindGameObjectsWithTag 仅在我启动 InvokeRepeating 代码后才调用。我在整个游戏过程中都有游戏对象生成,因此需要不断检查标签。
问题: 所以代码找到了标签,按钮可以被点击,记分文本更新,这很棒。问题是,如果我单击一个带标签的按钮,它会为自己注册一个点,并为当前在它之后产生的场景中的每个带标签的按钮注册一个点。例如,假设我目前在场景中有 4 个生成的对象,当单击第一个生成的对象时,它将添加 4 个点而不是 1 个。如果单击第二个生成的对象,它将添加 3 个点而不是 1 个。我想只有被点击的标记按钮注册一个点。
问题: 我可以在我的代码中更改什么,以便只有被单击的标记按钮注册一个点?
谢谢
我认为这里有两点:
- 您重复添加侦听器,因此当最终单击按钮时您将收到多个回调。
- 重复
FindGameObjectsWithTag
也很低效
您的主要问题是重复来电。
对于 CTagFinder
的每次重复调用,您将遍历所有现有按钮并执行
CButton.onClick.AddListener(AddScore);
因此这些现有按钮最终会附加 多个 听众!
您要么想确保每个按钮只调用一次,例如跟踪那些你已经为之做过的人:
private readonly HashSet<Button> alreadyRegisteredButtons = new HashSet<Button>();
然后
if(!alreadyRegisteredbuttons.Contains(CButton))
{
CButton.onClick.AddListener(AddScore);
alreadyRegisteredButtons.Add(CButton);
}
或者确保在添加之前删除回调,例如
CButton.onClick.RemoveListener(AddScore);
CButton.onClick.AddListener(AddScore);
一般来说,我不会重复使用 FindGameObjectWithTag 轮询对象。而是让你的代码事件驱动。这已经完全避免了这个问题,因为无论如何都不会重复附加监听器。
我会简单地将一个专用组件 YourComponent
附加到与按钮相同的 GameObject
并有一个全局
public static event Action<YourComponent> OnCTSButtonSpawned;
并在此专用组件中执行
private void Start()
{
OnCTSButtonSpawned?.Invoke(this);
}
并在你的 CPointScore
中收听此活动,例如
private void Awake()
{
YourComponent.OnCTSButtonSpawned += AttachListener;
}
private void AttachListener(YourComponent component)
{
if(compoenent.TryGetComponent<Button>(out var button))
{
button.onClick.AddListener(AddScore);
}
}
private void AddScore()
{
ScoreNum++;
CPointsText.text = ScoreNum.ToString();
}