Unity常用命令模式详解
在调用一些简单的方法实现一系列的动作时,回退的问题比较重要。作为一款用户体验良好的产品而言,有回退功能将显得比较人性化,想想如果我们常用的window,在删除一个文件后无法恢复将变得多么的糟糕。更为直观的例子是在玩一些小游戏时,比如象棋、推箱子,提供了悔棋的功能,用户有了更多选择的余地。
本文主要将的将是在unity中实现一个以常听说的命令模式为设计原理,实现一个可以撤销移动、旋转、颜色和文字信息的小demo。
命令模式,主要成员有提出要求的客户、设置命令的收集者、执行命令的接收者。客户要求很简单,点击按扭就要实现一项目具体的效果,设置命令的收集者无需要知道命令如何执行,只需要为执行者做好配制。用命令的执行者将执行一个方法,所有的命令者是继承于有这个方法的接口的类。
抽象到程序代码中,这三类成员分别对应于界面上的用户,remotecontrol (这里是随便命名的),remoteloader
先制作如上的界面,方便你比较直观的认识,其中左边两个是用于切换选择不同的命令。下面第一个按扭可以执行选中的命令,第二个按扭可以进行撤销操作。
程序,ugui面局如下,在canvas下分别设置了执行者和配制者。
制作好界面之后就可以来实现具体的脚本编辑了,分别创建好接口icommand,配制脚本remoteloader和执行脚本remotecontrol,结构如下:
在commonds中,分别编写了用于移动,旋转,颜色,文字的脚本
这样一来,就可以实现一个可撤销的命令模式了,效果如下所示:
其中用于保存undo方法和具体怎么undo都是使用stack来实现的,下面分别是部分代码实现 :
一、接口
public interface icommand { void execute(); void undo(); }
二、执行器
public class remotecontrol : monobehaviour { public button ctrlbtn; public button undobtn; public text ctrlname; private icommand icommand; public stack<unityaction> undofunctions = new stack<unityaction>(); void awake(){ ctrlbtn.onclick.addlistener(onctrlbtnclicked); undobtn.onclick.addlistener(onundobtnclicked); } public void settext(string textinfo) { ctrlname.text = textinfo; } public void setcommond(icommand icommand) { this.icommand = icommand; } /// <summary> /// 执行 /// </summary> public void onctrlbtnclicked() { if (icommand != null) { icommand.execute(); undofunctions.push(icommand.undo); } } /// <summary> /// 撤销 /// </summary> private void onundobtnclicked() { if (undofunctions.count > 0) { undofunctions.pop().invoke(); } } }
三、配制加载器
public class remoteloader : monobehaviour { public button lastbtn; public button nextbtn; private int index; private const int num_command = 10; private icommand[] commands; private string[] textinfos; private movecommand movexcmd; private movecommand moveycmd; private movecommand movezcmd; private rotatecommand rotxcmd; private rotatecommand rotycmd; private rotatecommand rotzcmd; private colorchangecommand redcolorcmd; private colorchangecommand greencolorcmd; private colorchangecommand bluecolorcmd; private textchangecommand textcmd; private string[] infos = { "a","b", "c", "d", "e", "f" }; public remotecontrol remotectrl; public gameobject cube; void awake() { lastbtn.onclick.addlistener(onlastbtnclicked); nextbtn.onclick.addlistener(onnextbtnclicked); } void start() { commands = new icommand[num_command]; textinfos = new string[num_command]; textinfos[0] = "x方向移动"; commands[0] = new movecommand(cube.transform, vector3.right); textinfos[1] = "y方向移动"; commands[1] = new movecommand(cube.transform, vector3.up); textinfos[2] = "z方向移动"; commands[2] = new movecommand(cube.transform, vector3.forward); textinfos[3] = "x轴旋转10度"; commands[3] = new rotatecommand(cube.transform, vector3.right * 10); textinfos[4] = "y轴旋转10度"; commands[4] = new rotatecommand(cube.transform, vector3.up * 10); textinfos[5] = "z轴旋转10度"; commands[5] = new rotatecommand(cube.transform, vector3.forward * 10); textinfos[6] = "变红"; commands[6] = new colorchangecommand(color.red, cube.getcomponent<renderer>().material); textinfos[7] = "变绿"; commands[7] = new colorchangecommand(color.green, cube.getcomponent<renderer>().material); textinfos[8] = "变蓝"; commands[8] = new colorchangecommand(color.blue, cube.getcomponent<renderer>().material); textinfos[9] = "换信息"; commands[9] = new textchangecommand(cube.getcomponentinchildren<textmesh>(), infos); } private void onnextbtnclicked() { if (index == num_command || index == -1) { index = 0; } remotectrl.setcommond(commands[index]); remotectrl.settext(textinfos[index]); index++; } private void onlastbtnclicked() { if (index == num_command || index == -1) { index = num_command - 1; } remotectrl.setcommond(commands[index]); remotectrl.settext(textinfos[index]); index--; } }
四、颜色转换命令脚本
public class colorchangecommand : icommand { private stack<color> m_origincolor = new stack<color>(); private color m_color; private material m_material; public colorchangecommand(color color, material material) { m_color = color; m_material = material; } public void execute() { m_origincolor.push(m_material.color); m_material.color = m_color; } public void undo() { m_material.color = m_origincolor.pop(); } }
五、移动命令脚本
public class movecommand : icommand { private vector3 m_offset; private transform m_object; public movecommand(transform obj, vector3 offset) { this.m_object = obj; this.m_offset = offset; } public void execute() { m_object.transform.position += m_offset; } public void undo() { m_object.transform.position -= m_offset; } }
六、转换命令脚本
public class remotecontrol : monobehaviour { public button ctrlbtn; public button undobtn; public text ctrlname; private icommand icommand; public stack<unityaction> undofunctions = new stack<unityaction>(); void awake(){ ctrlbtn.onclick.addlistener(onctrlbtnclicked); undobtn.onclick.addlistener(onundobtnclicked); } public void settext(string textinfo) { ctrlname.text = textinfo; } public void setcommond(icommand icommand) { this.icommand = icommand; } /// <summary> /// 执行 /// </summary> public void onctrlbtnclicked() { if (icommand != null) { icommand.execute(); undofunctions.push(icommand.undo); } } /// <summary> /// 撤销 /// </summary> private void onundobtnclicked() { if (undofunctions.count > 0) { undofunctions.pop().invoke(); } } }
七、文字加载脚本
public class textchangecommand : icommand { private stack<string> lastinfos = new stack<string>(); private ienumerator<string> datas; private textmesh m_textmesh; public textchangecommand(textmesh textmesh,icollection<string> texts) { datas = texts.getenumerator(); m_textmesh = textmesh; } public void execute() { if (!datas.movenext()) { datas.reset(); datas.movenext(); } lastinfos.push(m_textmesh.text); m_textmesh.text = datas.current; } public void undo() { m_textmesh.text = lastinfos.pop(); } }
仅供参考,谢谢阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: UnityShader3实现彩光效果
下一篇: c#在程序中定义和使用自定义事件方法总结