在之前的设计中有提到,游戏过程就是一个有限状态机。而之前状态机我们已经实现,我们在此之上实现之前提到的
驱动级任务及临时任务的概念。
我们可以认为 地图及场景切换 是我们的驱动级任务。而战斗、弹出窗口、小游戏等是游戏中的临时任务。
对于我们的游戏引擎,必须能够方便的添加新的场景、随时启动子任务。而这一切在基于我们的引擎开发的时候不应该再要考虑架构上的资源管理、内存管理等问题。
下面是我们的类图:
GDE_Task是我们的所有任务的基类,具有属性 EngineInstance用于保存游戏引擎实例,RootUIElement用于保存该任务的根绘图元素(用于界面绘制)。
派生类StateMachine(状态机) 具有方法 设置根元素 SetRootUIElement 和 切换下一个状态 RunNextStatus
派生类SubTask(子任务) 具有方法 设置根元素 SetRootUIElement 和 子任务结束 SubTaskEnd
然后下面我们给出三个用于测试的类,都派生ITask接口,必须实现 Run方法作为具体任务的逻辑入口。
编辑界面 TestStatus1 为 主界面,有三个按钮“新游戏”“读取进度”“退出”。
编辑界面 TestStatus2 为 一个场景,载入一个背景图片。
编辑界面 SubTaskTest 为一个战斗场景,具有一个提示栏和一个按钮,点击按钮则认为是该战斗结束。
具体逻辑为 ,在主界面点新游戏 ,切换到场景1,然后立即打开战斗,当战斗退出时,又回到场景1
下面为测试结果截图:
点击新游戏进入
点击结束战斗,回到场景
下面是任务调度核心部分代码:
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Threading; using GDE_X.UI; namespace GDE_X.Framework { /// <summary> /// 任务容器抽象基类 /// </summary> abstract public class GDE_Task { /// <summary> /// 游戏引擎实例 /// </summary> public GameEngine EngineInstance { set; get; } /// <summary> /// UI根元素 /// </summary> protected UserControl RootUIElement { set; get; } /// <summary> /// 设置UI根元素 /// </summary> /// <param name="UIElementInstance">根元素实例</param> abstract public void SetRootUIElement(UserControl UIElementInstance); } /// <summary> /// 状态机基类 /// </summary> public class StateMachine : GDE_Task { /// <summary> /// 设置UI根元素 /// </summary> /// <param name="UIElementInstance">根元素实例</param> public override void SetRootUIElement(UserControl UIElementInstance) { (UIElementInstance as IStateMachine).TaskHandle = this; RootUIElement = UIElementInstance; EngineInstance.RootCanvas.Children.Add(RootUIElement); } /// <summary> /// 游戏引擎主状态机执行指定状态 /// </summary> /// <param name="NextStatus">状态名</param> public void RunNextStatus(GameStatus NextStatus) { GameEngine.CurrentStatus = NextStatus; EngineInstance.RootCanvas.Children.Remove(RootUIElement);//移除当前状态机所属的界面根元素 CompositionTarget.Rendering += new EventHandler(GameEngine.NextStatus); } } /// <summary> /// 子任务抽象类 /// </summary> public class SubTask : GDE_Task { /// <summary> /// 设置UI根元素 /// </summary> /// <param name="UIElementInstance">根元素实例</param> public override void SetRootUIElement(UserControl UIElementInstance) { (UIElementInstance as ISubTask).TaskHandle = this; RootUIElement = UIElementInstance; EngineInstance.RootCanvas.Children.Add(RootUIElement); } /// <summary> /// 子任务结束 /// </summary> public void SubTaskEnd() { EngineInstance.RootCanvas.Children.Remove(RootUIElement); } } }
下面是三个测试界面的启动代码:
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using GDE_X.UI; namespace GDE_X.Framework { /////////////////////测试状态机////////////////////////////////////////////////// public class TestStatus1 : StateMachine, ITask { Brush brush_instance = new ImageBrush { ImageSource = ResManager.GetImage("/Test/1.jpg") }; public void Run() { MessageBox.Show("TestStatus1 called"); EngineInstance.RootCanvas.Background = brush_instance; EngineInstance.StartSubTask(new SubTaskTest() as SubTask); //RunNextStatus(GameStatus.Test); } } public class TestStatus2 : StateMachine, ITask { //Brush brush_instance = new ImageBrush { ImageSource = ResManager.GetImage("/Test/2.png") }; public void Run() { //MessageBox.Show("TestStatus called"); //EngineInstance.RootCanvas.Background = brush_instance; //RunNextStatus(GameStatus.Empty); SetRootUIElement(new MainMenu()); } } //////////////////////测试子任务//////////////////////// /// <summary> /// 子任务测试类 /// </summary> public class SubTaskTest : SubTask, ITask { public void Run() { MessageBox.Show("test sub task"); SetRootUIElement(new TestUI()); } } }
ITask接口部分代码
namespace GDE_X.Framework { /// <summary> /// 任务节点接口 /// </summary> public interface ITask { /// <summary> /// 启动任务 /// </summary> void Run(); } /// <summary> /// 子任务 界面 - 任务句柄 管理接口 /// /// 子任务启动的界面元素需实现此接口 /// </summary> public interface ISubTask { /// <summary> /// 所属任务句柄 /// </summary> SubTask TaskHandle { set; get; } } /// <summary> /// 状态机 界面 - 任务句柄 管理接口 /// /// 状态机启动的界面元素需要实现此接口 /// </summary> public interface IStateMachine { /// <summary> /// 所属任务句柄 /// </summary> StateMachine TaskHandle { set; get; } } }