打造轻量级Windows Phone7 游戏引擎-Samurai 第三话SADirector与SAScreen
2013-10-23 12:39
239 查看
打造轻量级Windows Phone7 游戏引擎-Samurai 第三话SADirector与SAScreen
在XNA编程框架中,一开始项目就自动帮我们生成了一个“Game1.cs”文件,Game1主要就是这个样子的:
现在现在只有Game1.cs,而且Update与Draw的循环调用又得借助Game1的相应方法。那么,Game1是游戏的老大吗?或者应该问谁是整个游戏的老大呢?
游戏是由一个个页面够成,管理这些页面的管理者应该就是了吧!但是做页面的管理者也不是那么容易的事,因为管理者没有实际的权利来Update和Draw,他也不得不给Game1低头,说“老大呀,麻烦你更新的时候通知我一声呗”,Game1很嚣张的说“以后要想跟我混,得多学着点儿,I Jump,You Jump”(呵呵)。没错,虽然Game1目前是绝对的大佬,但是只要有页面管理者在,所有的事情都交给他就行了。我们就叫页面管理者为SADirector吧(就叫她阿SA导演吧)
阿SA导演主要干两件事:
跟Game1混,You Jump,I Jump:
太简单了,就是You Update,I Update;You Draw ,I Draw;
管理页面的切换(页面类还没出场,大家稍等一下吧)
也不难,就是作为上下文(状态模式),交给Screen选择下一个Screen的权利。只有Game1.cs,而且Update与Draw的循环调用又得借助Game1的相应方法。那么,Game1是游戏的老大吗?或者应该问谁是整个游戏的老大呢?
游戏是由一个个页面够成,管理这些页面的管理者应该就是了吧!但是做页面的管理者也不是那么容易的事,因为管理者没有实际的权利来Update和Draw,他也不得不给Game1低头,说“老大呀,麻烦你更新的时候通知我一声呗”,Game1很嚣张的说“以后要想跟我混,得多学着点儿,I Jump,You Jump”(呵呵)。没错,虽然Game1目前是绝对的大佬,但是只要有页面管理者在,所有的事情都交给他就行了。我们就叫页面管理者为SADirector吧(就叫她阿SA导演吧)
阿SA导演主要干两件事:
1.跟Game1混,You Jump,I Jump:
太简单了,就是You Update,I Update;You Draw ,I Draw;
2.管理页面的切换(页面类还没出场,大家稍等一下吧)
也不难,就是作为上下文(状态模式),交给Screen选择下一个Screen的权利。
3.如果是一个好的导演的话,在用完一个页面后要想想,我是释放掉你好,还是先留下,再用的时候直接让你重新初始化一下呢(作为一个懒汉导演,我还是选择了后者的方法)
下面,我先贴出来You Jump,I Jump的代码:在Game1.cs中:
在SADirector中:
关于Screen页面的切换(当然我们可以使用多线程加载资源以及Loading动画,但对于不是比较大的游戏,我比较习惯于一次性加载资源,所以并没有在页面切换时加入多线程和loading相关内容)不过未来这一部分还是打算做比较大的改动的,因为想做一些页面切换时候的3D效果,目前这一部分还没开工...回到正题,大家可以看看关于“状态模式”的描述,这里主要用的是状态模式。
直接贴上SADirector的所有代码吧:
下面是一个SADirector的子类:
下面页面基类SAScreen登场:
同样的SAScreen还是抽象类,我们通过继承来使用。
代码简单易懂,直接Ctrl V吧:
不过现在看这段代码,觉得“依赖项,常用引用”这样写真的很烂!!!不如直接提取出来一个静态的Util在SADirector构造的时候初始化,全局共享即可。(这不就是前面博客中提到的SAGlobal,原谅我吧,当初写SAGlobal是为了消灭掉常用引用,现在发现竟然忘了改)
稍稍改了下:
细心的读者会发现,这里面已经有了SetupInput和UnloadContent里的ResetInput,也就是说我们在每一个单独页面都重新注册在该页面中需要检测的输入,而当页面被回收再利用时,会调用ReInit方法(当然了,加载的资源因为没有被释放,所以就不用再重新LoadContent了)。花费了这么多功夫,我们是不是应该写一个页面转换以及使用不同的手势检测的小例子了呢?
I am sorry to tell you that,等到写完Button相关的内容吧~敬请期待~
在XNA编程框架中,一开始项目就自动帮我们生成了一个“Game1.cs”文件,Game1主要就是这个样子的:
public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; TargetElapsedTime = TimeSpan.FromTicks(333333); InactiveSleepTime = TimeSpan.FromSeconds(1); } protected override void Initialize() { //TODO base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); //TODO } protected override void UnloadContent() { //TODO } protected override void Update(GameTime gameTime) { //TODO base.Update(gameTime); } protected override void Draw(GameTime gameTime) { //TODO base.Draw(gameTime); } }
现在现在只有Game1.cs,而且Update与Draw的循环调用又得借助Game1的相应方法。那么,Game1是游戏的老大吗?或者应该问谁是整个游戏的老大呢?
游戏是由一个个页面够成,管理这些页面的管理者应该就是了吧!但是做页面的管理者也不是那么容易的事,因为管理者没有实际的权利来Update和Draw,他也不得不给Game1低头,说“老大呀,麻烦你更新的时候通知我一声呗”,Game1很嚣张的说“以后要想跟我混,得多学着点儿,I Jump,You Jump”(呵呵)。没错,虽然Game1目前是绝对的大佬,但是只要有页面管理者在,所有的事情都交给他就行了。我们就叫页面管理者为SADirector吧(就叫她阿SA导演吧)
阿SA导演主要干两件事:
跟Game1混,You Jump,I Jump:
太简单了,就是You Update,I Update;You Draw ,I Draw;
管理页面的切换(页面类还没出场,大家稍等一下吧)
也不难,就是作为上下文(状态模式),交给Screen选择下一个Screen的权利。只有Game1.cs,而且Update与Draw的循环调用又得借助Game1的相应方法。那么,Game1是游戏的老大吗?或者应该问谁是整个游戏的老大呢?
游戏是由一个个页面够成,管理这些页面的管理者应该就是了吧!但是做页面的管理者也不是那么容易的事,因为管理者没有实际的权利来Update和Draw,他也不得不给Game1低头,说“老大呀,麻烦你更新的时候通知我一声呗”,Game1很嚣张的说“以后要想跟我混,得多学着点儿,I Jump,You Jump”(呵呵)。没错,虽然Game1目前是绝对的大佬,但是只要有页面管理者在,所有的事情都交给他就行了。我们就叫页面管理者为SADirector吧(就叫她阿SA导演吧)
阿SA导演主要干两件事:
1.跟Game1混,You Jump,I Jump:
太简单了,就是You Update,I Update;You Draw ,I Draw;
2.管理页面的切换(页面类还没出场,大家稍等一下吧)
也不难,就是作为上下文(状态模式),交给Screen选择下一个Screen的权利。
3.如果是一个好的导演的话,在用完一个页面后要想想,我是释放掉你好,还是先留下,再用的时候直接让你重新初始化一下呢(作为一个懒汉导演,我还是选择了后者的方法)
下面,我先贴出来You Jump,I Jump的代码:在Game1.cs中:
public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SADirector director; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; TargetElapsedTime = TimeSpan.FromTicks(333333); InactiveSleepTime = TimeSpan.FromSeconds(1); //Config 全屏 graphics.IsFullScreen = true; //Config 竖屏 SAGraphicUtil.SetVertical(graphics); } protected override void Initialize() { //TODO base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); //TODO DIRECTOR director = new ScreenManager(this, graphics, spriteBatch); } protected override void UnloadContent() { //TODO DIRECTOR director.UnloadContent(); } protected override void Update(GameTime gameTime) { //TODO DIRECTOR director.Update(gameTime); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { //TODO DIRECTOR director.Draw(gameTime); base.Draw(gameTime); } protected override void OnActivated(object sender, EventArgs args) { //TODO DIRCTOR director.OnActivated(); base.OnActivated(sender, args); } }
在SADirector中:
#region 与Game的接口 public void Update(GameTime gameTime) { currentScreen.BaseUpdate(gameTime); } public void Draw(GameTime gameTime) { game.GraphicsDevice.Clear(Color.CadetBlue); currentScreen.BaseDraw(gameTime); } public virtual void UnloadContent() { } public virtual void OnActivated() { } #endregion
关于Screen页面的切换(当然我们可以使用多线程加载资源以及Loading动画,但对于不是比较大的游戏,我比较习惯于一次性加载资源,所以并没有在页面切换时加入多线程和loading相关内容)不过未来这一部分还是打算做比较大的改动的,因为想做一些页面切换时候的3D效果,目前这一部分还没开工...回到正题,大家可以看看关于“状态模式”的描述,这里主要用的是状态模式。
直接贴上SADirector的所有代码吧:
public abstract class SADirector { //常用的引用 protected static Game game; protected static GraphicsDeviceManager graphics; protected static SpriteBatch spriteBatch; protected static ContentManager content; //单例 protected SAScreen currentScreen; //缓存 protected Dictionary<ScreenType, SAScreen> screenDictionary; public delegate SAScreen CreateScreen(); public SADirector(Game game, GraphicsDeviceManager graphics, SpriteBatch spriteBatch) { SADirector.game = game; SADirector.content = game.Content; SADirector.graphics = graphics; SADirector.spriteBatch = spriteBatch; screenDictionary = new Dictionary<ScreenType, SAScreen>(); //注册 Global SAGlobal.Setup(game, spriteBatch, graphics); //设置竖屏 SAGraphicUtil.SetVertical(graphics); //初始化SAMusicManager SAMusicManager.Setup(); //ATTENTION 加载第一个页面 //ChangeScreenTo(ScreenType.Loading); } #region 与Game的接口 public void Update(GameTime gameTime) { currentScreen.BaseUpdate(gameTime); } public void Draw(GameTime gameTime) { game.GraphicsDevice.Clear(Color.CadetBlue); currentScreen.BaseDraw(gameTime); } public virtual void UnloadContent() { } public virtual void OnActivated() { } #endregion #region 切换页面(SAScreen需要知道) public virtual void ChangeScreenTo(ScreenType screenType){} public void ChangeScreenTo(ScreenType screenType, CreateScreen createScreen) { if (currentScreen != null) { //重置 currentScreen.UnloadContent(); } if (!screenDictionary.ContainsKey(screenType)) { screenDictionary.Add(screenType, createScreen()); screenDictionary[screenType].BaseLoadContent(); currentScreen = screenDictionary[screenType]; } else { currentScreen = screenDictionary[screenType]; //重新启动 currentScreen.ReInit(); } } #endregion #region 创建界面(工厂模式) #endregion } public enum ScreenType { Test, Loading, MainMenu, Game }
下面是一个SADirector的子类:
public class ScreenManager:SADirector { public ScreenManager(Game game,GraphicsDeviceManager graphics,SpriteBatch spriteBatch) :base(game,graphics,spriteBatch) { ChangeScreenTo(ScreenType.Test); } public override void ChangeScreenTo(ScreenType screenType) { switch (screenType) { case ScreenType.Test: ChangeScreenTo(screenType, CreateTestScreen); break; //... } } public SAScreen CreateTestScreen() { return new MarioScreen(game, spriteBatch, graphics, ChangeScreenTo); } }
下面页面基类SAScreen登场:
同样的SAScreen还是抽象类,我们通过继承来使用。
代码简单易懂,直接Ctrl V吧:
不过现在看这段代码,觉得“依赖项,常用引用”这样写真的很烂!!!不如直接提取出来一个静态的Util在SADirector构造的时候初始化,全局共享即可。(这不就是前面博客中提到的SAGlobal,原谅我吧,当初写SAGlobal是为了消灭掉常用引用,现在发现竟然忘了改)
public class SAScreen { #region 依赖项 常用引用 protected static Game game {set;get;} protected static GraphicsDeviceManager graphics { get; set; } protected static ContentManager content { get; set; } protected static SpriteBatch spriteBatch { get; set; } #endregion protected static Random random { get; set; } public delegate void ChangeScreenDelegate(ScreenType screenType); protected static ChangeScreenDelegate ChangeScreenTo; public SAScreen() { } public SAScreen(Game game, SpriteBatch spriteBatch, GraphicsDeviceManager graphics, ChangeScreenDelegate changeScreenDelegate) { SAScreen.game = game; SAScreen.spriteBatch = spriteBatch; SAScreen.content = game.Content; SAScreen.graphics = graphics; SAScreen.ChangeScreenTo = changeScreenDelegate; random = new Random(); } #region 与SADirector的接口 不可复写 public void BaseLoadContent() { LoadContent(); SetupInput(); Init(); } public void BaseUpdate(GameTime gameTime) { SAInput.UpdateInput(); Update(gameTime); } public void BaseDraw(GameTime gameTime) { spriteBatch.Begin(); Draw(gameTime); spriteBatch.End(); } public void BaseUnloadContent() { UnloadContent(); } public void ReInit() { Init(); SetupInput(); } #endregion #region 子类复写 public virtual void LoadContent() { //TODO } public virtual void Init() { //TODO } public virtual void Update(GameTime gameTime) { //TODO } //只管画,不管Begin和End public virtual void Draw(GameTime gameTime) { //TODO } public virtual void UnloadContent() { //如果子类override就更好了 SAInput.ResetInput(); } public virtual void SetupInput() { //TODO } #endregion } }
稍稍改了下:
public abstract class SAScreen { protected static Random random; public delegate void ChangeScreenDelegate(ScreenType screenType); protected static ChangeScreenDelegate ChangeScreenTo; static SAScreen() { random = new Random(); } public SAScreen() { } public SAScreen(ChangeScreenDelegate changeScreenDelegate) { SAScreen.ChangeScreenTo = changeScreenDelegate; } #region 与SADirector的接口 不可复写 public void BaseLoadContent() { LoadContent(); SetupInput(); Init(); } public void BaseUpdate(GameTime gameTime) { SAInput.UpdateInput(); Update(gameTime); } public void BaseDraw(GameTime gameTime) { SAGlobal.spriteBatch.Begin(); Draw(gameTime); SAGlobal.spriteBatch.End(); } public void BaseUnloadContent() { UnloadContent(); } public void ReInit() { Init(); SetupInput(); } #endregion #region 子类复写 public virtual void LoadContent() { //TODO } public virtual void Init() { //TODO } public virtual void Update(GameTime gameTime) { //TODO } //只管画,不管Begin和End public virtual void Draw(GameTime gameTime) { //TODO } public virtual void UnloadContent() { //如果子类override就更好了 SAInput.ResetInput(); } public virtual void SetupInput() { //TODO } #endregion }
细心的读者会发现,这里面已经有了SetupInput和UnloadContent里的ResetInput,也就是说我们在每一个单独页面都重新注册在该页面中需要检测的输入,而当页面被回收再利用时,会调用ReInit方法(当然了,加载的资源因为没有被释放,所以就不用再重新LoadContent了)。花费了这么多功夫,我们是不是应该写一个页面转换以及使用不同的手势检测的小例子了呢?
I am sorry to tell you that,等到写完Button相关的内容吧~敬请期待~
相关文章推荐
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第零话 前言
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第二话(上) Inputs 问题提出篇
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第一话 Globals & Music
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第五话 使用Samurai创建游戏
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第四话 Button(上)
- 打造轻量级Windows Phone7 游戏引擎-Samurai 第二话(中) Inputs 问题解决篇一
- Mozilla,Epic携手打造Unreal 3 游戏引擎
- 利用规则引擎打造轻量级的面向服务编程模式
- 自定义 Javascript 模板规则,打造轻量级模板引擎
- Unity打造简易的GalGame游戏剧本编辑引擎
- Cocos2d-x游戏引擎迈入3.0时代 打造完整工具链
- 使用游戏引擎photon打造一款特殊的远程控制软件
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 5(添加微信支持)
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 8(登陆界面)
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 9(登陆等待&结算界面)
- 打造真实画面 从游戏截图看顶级引擎(图)
- 【麦可网】Cocos2d-X跨平台游戏开发学习笔记---第三课:认识Cocos2D-X引擎
- Mozilla,Epic携手打造Unreal 3 游戏引擎
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 7(服务器连接&数据处理)
- 青瓷引擎之纯JavaScript打造HTML5游戏第二弹——《跳跃的方块》Part 10(排行榜界面&界面管理)