统一评分系统的创建
Creation of a score system in unity
我目前正在开发一个简单的 2D 游戏,以学习有关游戏开发的许多知识。
尽管如此,我在创建评分系统时遇到了一些问题。
我想每秒更新一次比分,每秒加1分,比赛结束后停止计时
我开始写这个
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
void Start () {
score = 0;
}
void Update () {
StartCoroutine(updateScoreManager(1f, 1));
distance.text = score.ToString();
}
IEnumerator updateScoreManager(float totalTime, int amount) {
score += amount;
yield return new WaitForSeconds (totalTime);
}
}
问题是 GUIText 中没有显示任何内容,所以我不知道它是否有效。游戏结束后如何停止计数?
The issues are that nothing shows up in the GUIText so I don't know if
it works
会发生什么?它总是为零还是什么都不显示?如果没有 - 检查坐标、图层等以确保您正确定位它。参考http://docs.unity3d.com/Manual/class-GUIText.html
And how can I stop the count when the game is over?
在游戏结束事件中使用 StopCoroutine(updateScoreManager)
,并且不要忘记将分数设置为零。
其实是说你的代码设计的不好。实现 State、Observer、Component 模式会很棒。使用状态,您可以实现 Game、GameOver 等游戏状态。使用 Observer,您可以通知您的分数组件。使用组件,您可以通过将评分逻辑放置到评分组件来满足单一责任原则。
至少考虑单独的开始游戏初始化、更新组件和游戏结束逻辑。
我将跳过有关您正在实施的模式的讲座,因为我不知道您的其余代码是什么样子,但更新问题的根源在这里:
IEnumerator updateScoreManager(float totalTime, int amount)
{
score += amount;
yield return new WaitForSeconds(totalTime);
}
实际上,当我 运行 处理这类问题时,我将失败的逻辑与源应用程序分开,以帮助减少噪音。
因此,当我为您的算法制作原型时(下面的代码)发生的事情是得分始终为零,因为 StartCoroutine 应该使用 updateScoreManager 的 return 值来进行更新,而 .Update() 是打电话。
如果我的原型看起来与您尝试实现此代码的方式相匹配,那么我可以post稍后我将如何解决这个问题。
但基本上,不是 returning IEnumerator return 一个更新分数的 int,这可能会让你解决这个问题。
除非你能在代码的其他地方描述 use-case 你需要 IEnumerator 的地方?
执行原型:
class Program
{
static void Main(string[] args)
{
Ans34612672 Ans34612672 = new Ans34612672();
Ans34612672.Execute();
Console.ReadKey();
}
}
原型包装器Class:
public class Ans34612672
{
public Ans34612672()
{
}
public bool Execute()
{
bool retValue = false;
scoremanager Manager = new scoremanager();
Manager.Start();
while(Manager.score < 20)
{
Manager.Update();
}
Console.WriteLine(Manager.distance);
Console.ReadKey();
return retValue;
}
}
原型Class是:
public class scoremanager : MonoBehaviour
{
public int score;
public GUIText distance;
public void Start()
{
score = 0;
distance = new GUIText();
}
public void Update()
{
IEnumerator UpdateResults = updateScoreManager(1f, 1);
StartCoroutine(UpdateResults);
distance.text = score.ToString();
}
private void StartCoroutine(IEnumerator enumerator)
{
//Implement Logic
}
IEnumerator updateScoreManager(float totalTime, int amount)
{
score += amount;
yield return new WaitForSeconds(totalTime);
}
}
internal class WaitForSeconds
{
private float totalTime;
public WaitForSeconds(float totalTime)
{
this.totalTime = totalTime;
}
}
public class GUIText
{
internal string text;
}
public class MonoBehaviour
{
}
首先,我认为您应该使用 uGUI,因为这是 Unity 现在为 UI 接受的解决方案:http://blogs.unity3d.com/2014/05/28/overview-of-the-new-ui-system/
我真的不能说你的 GUIText 有什么问题,因为我不知道位置是否关闭或其他什么,但我可以告诉你如何更好地管理计数。
您不需要使用更新功能,使用更新功能违背了使用协程更新文本的目的。使用协程可以让您控制何时开始更新以及何时停止更新。因此,一种解决方案是完全摆脱更新功能,以便更好地控制它:
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
private Coroutine scoreCoroutine;
void Start () {
score = 0;
scoreCoroutine = StartCoroutine(updateScoreManager(1f, 1));
}
IEnumerator updateScoreManager(float totalTime, int amount) {
while(true) {
score += amount;
distance.text = score.ToString();
yield return new WaitForSeconds (totalTime);
}
}
// example of ending game
void EndGame() {
StopCoroutine(scoreCoroutine);
scoreCoroutine = null;
}
}
这可能看起来很奇怪(为什么我要使用无限循环)?但这就是协程的美妙之处,您可以编写这样的代码,因为 yield 语句允许您从代码中 return 并稍后返回到同一位置。通常 while 循环会导致您的游戏崩溃,但是 yield 语句让您创建一个 time while 循环!
希望对您有所帮助!
我在您的代码中发现了一些小问题。先覆盖一下吧。
- 您正在
Update
中呼叫 Coroutine
,延迟时间为 1 秒。这意味着您的 Coroutine
每秒执行 30 或 60 次。
- 您也在
Update
中分配文本。这可能是它刷新文本的原因(对此不确定)
- 在您的
Coroutine
中,您的延迟即 WaitForSeconds
在这里没有用,因为在那行代码之后没有发生任何事情。
我正在修改你的确切代码,这样你就能明白你想要的也可以通过这个来实现:)
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
public bool isGameOver = false;
void Start () {
score = 0;
StartCoroutine(updateScoreManager(1f, 1));
}
void Update () {
}
IEnumerator updateScoreManager(float totalTime, int amount) {
while(!isGameOver){
score += amount;
distance.text = score.ToString();
yield return new WaitForSeconds (totalTime);
}
}
}
有什么变化...
Update
中没有代码。
- 只调用一次
Coroutine
。
- 在
Coroutine
中,它正在改变 score
和 distance
两者,每 totalTime
秒一次。直到 isGameOver
标志为 false
。游戏结束后 true
。
我想您的问题的简单解决方案是 InvokeRepeating
//Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
public void InvokeRepeating(string methodName, float time, float repeatRate);
所以你转换后的代码是
public class 得分管理器:MonoBehaviour {
public int score;
public GUIText distance;
void Start () {
InvokeRepeating("updateScoreManager",1f,1f);
}
void Update () {
distance.text = score.ToString();
}
void updateScoreManager() {
score += 1;
}
我目前正在开发一个简单的 2D 游戏,以学习有关游戏开发的许多知识。
尽管如此,我在创建评分系统时遇到了一些问题。
我想每秒更新一次比分,每秒加1分,比赛结束后停止计时
我开始写这个
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
void Start () {
score = 0;
}
void Update () {
StartCoroutine(updateScoreManager(1f, 1));
distance.text = score.ToString();
}
IEnumerator updateScoreManager(float totalTime, int amount) {
score += amount;
yield return new WaitForSeconds (totalTime);
}
}
问题是 GUIText 中没有显示任何内容,所以我不知道它是否有效。游戏结束后如何停止计数?
The issues are that nothing shows up in the GUIText so I don't know if it works
会发生什么?它总是为零还是什么都不显示?如果没有 - 检查坐标、图层等以确保您正确定位它。参考http://docs.unity3d.com/Manual/class-GUIText.html
And how can I stop the count when the game is over?
在游戏结束事件中使用 StopCoroutine(updateScoreManager)
,并且不要忘记将分数设置为零。
其实是说你的代码设计的不好。实现 State、Observer、Component 模式会很棒。使用状态,您可以实现 Game、GameOver 等游戏状态。使用 Observer,您可以通知您的分数组件。使用组件,您可以通过将评分逻辑放置到评分组件来满足单一责任原则。
至少考虑单独的开始游戏初始化、更新组件和游戏结束逻辑。
我将跳过有关您正在实施的模式的讲座,因为我不知道您的其余代码是什么样子,但更新问题的根源在这里:
IEnumerator updateScoreManager(float totalTime, int amount)
{
score += amount;
yield return new WaitForSeconds(totalTime);
}
实际上,当我 运行 处理这类问题时,我将失败的逻辑与源应用程序分开,以帮助减少噪音。
因此,当我为您的算法制作原型时(下面的代码)发生的事情是得分始终为零,因为 StartCoroutine 应该使用 updateScoreManager 的 return 值来进行更新,而 .Update() 是打电话。
如果我的原型看起来与您尝试实现此代码的方式相匹配,那么我可以post稍后我将如何解决这个问题。
但基本上,不是 returning IEnumerator return 一个更新分数的 int,这可能会让你解决这个问题。
除非你能在代码的其他地方描述 use-case 你需要 IEnumerator 的地方?
执行原型:
class Program
{
static void Main(string[] args)
{
Ans34612672 Ans34612672 = new Ans34612672();
Ans34612672.Execute();
Console.ReadKey();
}
}
原型包装器Class:
public class Ans34612672
{
public Ans34612672()
{
}
public bool Execute()
{
bool retValue = false;
scoremanager Manager = new scoremanager();
Manager.Start();
while(Manager.score < 20)
{
Manager.Update();
}
Console.WriteLine(Manager.distance);
Console.ReadKey();
return retValue;
}
}
原型Class是:
public class scoremanager : MonoBehaviour
{
public int score;
public GUIText distance;
public void Start()
{
score = 0;
distance = new GUIText();
}
public void Update()
{
IEnumerator UpdateResults = updateScoreManager(1f, 1);
StartCoroutine(UpdateResults);
distance.text = score.ToString();
}
private void StartCoroutine(IEnumerator enumerator)
{
//Implement Logic
}
IEnumerator updateScoreManager(float totalTime, int amount)
{
score += amount;
yield return new WaitForSeconds(totalTime);
}
}
internal class WaitForSeconds
{
private float totalTime;
public WaitForSeconds(float totalTime)
{
this.totalTime = totalTime;
}
}
public class GUIText
{
internal string text;
}
public class MonoBehaviour
{
}
首先,我认为您应该使用 uGUI,因为这是 Unity 现在为 UI 接受的解决方案:http://blogs.unity3d.com/2014/05/28/overview-of-the-new-ui-system/
我真的不能说你的 GUIText 有什么问题,因为我不知道位置是否关闭或其他什么,但我可以告诉你如何更好地管理计数。
您不需要使用更新功能,使用更新功能违背了使用协程更新文本的目的。使用协程可以让您控制何时开始更新以及何时停止更新。因此,一种解决方案是完全摆脱更新功能,以便更好地控制它:
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
private Coroutine scoreCoroutine;
void Start () {
score = 0;
scoreCoroutine = StartCoroutine(updateScoreManager(1f, 1));
}
IEnumerator updateScoreManager(float totalTime, int amount) {
while(true) {
score += amount;
distance.text = score.ToString();
yield return new WaitForSeconds (totalTime);
}
}
// example of ending game
void EndGame() {
StopCoroutine(scoreCoroutine);
scoreCoroutine = null;
}
}
这可能看起来很奇怪(为什么我要使用无限循环)?但这就是协程的美妙之处,您可以编写这样的代码,因为 yield 语句允许您从代码中 return 并稍后返回到同一位置。通常 while 循环会导致您的游戏崩溃,但是 yield 语句让您创建一个 time while 循环!
希望对您有所帮助!
我在您的代码中发现了一些小问题。先覆盖一下吧。
- 您正在
Update
中呼叫Coroutine
,延迟时间为 1 秒。这意味着您的Coroutine
每秒执行 30 或 60 次。 - 您也在
Update
中分配文本。这可能是它刷新文本的原因(对此不确定) - 在您的
Coroutine
中,您的延迟即WaitForSeconds
在这里没有用,因为在那行代码之后没有发生任何事情。
我正在修改你的确切代码,这样你就能明白你想要的也可以通过这个来实现:)
public class scoremanager : MonoBehaviour {
public int score;
public GUIText distance;
public bool isGameOver = false;
void Start () {
score = 0;
StartCoroutine(updateScoreManager(1f, 1));
}
void Update () {
}
IEnumerator updateScoreManager(float totalTime, int amount) {
while(!isGameOver){
score += amount;
distance.text = score.ToString();
yield return new WaitForSeconds (totalTime);
}
}
}
有什么变化...
Update
中没有代码。- 只调用一次
Coroutine
。 - 在
Coroutine
中,它正在改变score
和distance
两者,每totalTime
秒一次。直到isGameOver
标志为false
。游戏结束后true
。
我想您的问题的简单解决方案是 InvokeRepeating
//Invokes the method methodName in time seconds, then repeatedly every repeatRate seconds.
public void InvokeRepeating(string methodName, float time, float repeatRate);
所以你转换后的代码是
public class 得分管理器:MonoBehaviour {
public int score;
public GUIText distance;
void Start () {
InvokeRepeating("updateScoreManager",1f,1f);
}
void Update () {
distance.text = score.ToString();
}
void updateScoreManager() {
score += 1;
}