Unity使用协程要求用户按顺序“一步一步”进行操作
许多游戏会在新手教程要求玩家按顺序操作,或者解谜游戏会要求玩家按顺序进行操作。 使用if语句未免不是一种方法,但是当步骤数特别多的时候,嵌套会使整段代码看上去非常臃肿,难以阅读。
使用协程去管理这些步骤,则不需要if语句去进行嵌套了。 此处抛砖引玉,演示一个极简的项目,要求用户按顺序依次点击ABC三个按钮,顺序正确则Debug打印按钮名字,错误则报错,并且从上一次按下的正确的按钮继续执行。
新建一个C#脚本命名为GameManager,并且新建空物体挂载这个脚本
代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
int step;
int pressed;
bool check;
private void Start()
{
step = 1;
StartCoroutine("Begin");
}
public void Button_Press(int i)
{
pressed = i;
check = true;
}
void Error()
{
Debug.Log("Wrong");
}
bool Check()
{
if (check)
{
if (pressed != step)
{
Error();
check = false;
return false;
}
check = false;
return true;
}
return false;
}
IEnumerator Begin()
{
Debug.Log("开启协程");
while (step <= 3)
{
yield return StartCoroutine("Step" + step);
step++;
}
yield return null;
}
IEnumerator Step1()
{
Debug.Log("开始协程一");
yield return new WaitUntil(() => Check() == true);
Debug.Log("A");
yield return null;
}
IEnumerator Step2()
{
Debug.Log("开始协程二");
yield return new WaitUntil(() => Check() == true);
Debug.Log("B");
yield return null;
}
IEnumerator Step3()
{
Debug.Log("开始协程三");
yield return new WaitUntil(() => Check() == true);
Debug.Log("C");
yield return null;
}
}
给每一个按钮增添点击事件,“1”表示希望这个按钮第一个被点击,即顺序。
因为只有三个按钮,所以只加了三个协程,根据需要可以继续往下加Step4、Step5… 并不限于按钮,要点是改变pressed的值,故只要用户其他动作加入改变pressed值的代码即可。
补充
上述设计的思想是,每一个按钮会赋予全局变量pressed不同的值,并且启动检测机制判断preesed是否跟当前的步骤数相等,相等就执行相应的代码,否则就报错。 该设计一个弊端就是,因为step每次按钮点击正确就会自增1,而按钮的值是固定的,因此当同一个按钮需要被多次点击时就不适用了。 解决方案是 ①修改pressed,每一个按钮增加一个int计数器计算点击次数,根据计数器值的不同改变不同的pressed值; 这样的话需要用if语句进行判断甚至嵌套,与我们设计的初衷违背。 ②修改step,让它不再每次自增1。 StartCoroutine(“Step” + step)会根据函数名启用不同的协程,修改step意味着要修改函数名,而且后续新增步骤会带来麻烦。
故③修改检测机制。 原来的检测机制是step与pressed进行判断,那么只要不与step进行判断,而另起炉灶重载Check()函数,指定pressed跟我们需要的值进行判断即可。
bool Check(int i)
{
}
....
....
IEnumerator Step1()
{
Debug.Log("开始协程一");
yield return new WaitUntil(() => Check(1) == true);
Debug.Log("A");
yield return null;
}
IEnumerator Step2()
{
Debug.Log("开始协程二");
yield return new WaitUntil(() => Check(1) == true);
Debug.Log("A");
yield return null;
}
这样便可以使pressed指定与常量1进行比较,上述代码表示需要连续点击按钮A两次。
另外根据需要可以改变Check()的参数,例如
bool Check(int i,int j)
{
if (check)
{
if (pressed != i && pressed != j)
{
Error();
check = false;
return false;
}
check = false;
return true;
}
return false;
}
IEnumerator Step3()
{
Debug.Log("开始协程三");
yield return new WaitUntil(() => Check(1, 2) == true);
if (pressed == 1)
{
Debug.Log("A");
}
else if( pressed == 2)
{
Debug.Log("B");
}
yield return null;
}
就表示允许用户在特定的步骤里,既可以点击A,也可以点击B完成该步骤。
|