游戏编程模式算是一本比较著名的书了,全书针对游戏编程中的问题介绍了多种设计模式。学习设计模式可以加强我们的程序架构能力,写出更加强大和优雅的程序。
在线 C#
# 写在前面
其实针对 设计模式
,之前我就学习过《大话设计模式》自己也随书将二十多种设计模式实现了一遍;但我在学习游戏开发的过程中发现,标准的设计模式并非对游戏编程支持良好,故而有了专门看一看游戏设计模式的打算,加上寒假学习 cpp,让我有了拿起这本书的想法。
此文仅为学习记录,欢迎指正。
设计模式并不是刻意为之的东西,是前辈经验的总结,也许你在不知不觉中就已经使用了某种设计模式。
# 命令模式
将一个请求封装成一个对象,从而允许你使用不同的请求、队列和日志将将客户端参数化,支持请求的撤销与恢复。
从上述的描述中我们可以找到几个关键点: 请求队列
, 日志
, 撤销与恢复
。
如果你需要这些特性,此事不妨试试命令模式吧。
# 适用场景
- 试想一下,我们在游戏中需要监听用户的输入,以让我们控制的角色响应玩家发布的
命令
,这个命令可能是移动,攻击,也可能是打开菜单,退出游戏。在需要复杂的输入检测时,你可能需要将玩家输入进行组合,如在恰当的时机按下某几个键位就可以使用特殊技能。 - 在网络游戏中,我们操控我们的角色需要在所有连接的客户端中同步,其中有一种同步方式称为
状态同步
,及玩家操作角色时,客户端会向所有服务器执行相同的命令,以同步角色的状态信息。这样的情况,多少也使用了命令模式在里面。 - 如果你需要撤销和重做,如一款回合制策略游戏,你可能需要撤销之前的动作,让玩家更专注于策略本身。
# 代码
根据上述描述,我们可以建立一个最基础的命令模式模板。
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
public class Program | |
{ | |
public static void Main() | |
{ | |
var pl=new Player(0,0); | |
Console.WriteLine(pl); | |
var moveC=new MoveCommand(1,0,pl); | |
moveC.Excute(); | |
Console.WriteLine(pl); | |
moveC.Undo(); | |
Console.WriteLine(pl); | |
} | |
} | |
public class Player | |
{ | |
public int x,y; | |
public Player(int x,int y) | |
{ | |
this.x=x; | |
this.y=y; | |
} | |
public override string ToString() | |
{ | |
return $"玩家pos:[{x},{y}]"; | |
} | |
} | |
public abstract class Command | |
{ | |
public abstract void Excute(); | |
public abstract void Undo(); | |
} | |
public class MoveCommand:Command | |
{ | |
private int x,y; | |
private Player player; | |
public MoveCommand(int x,int y,Player pl){this.x=x;this.y=y;this.player=pl;} | |
public override void Excute() | |
{ | |
Console.WriteLine("Move Excute!"); | |
Console.WriteLine("Move To {0},{1}",x,y); | |
player.x+=x; | |
player.y+=y; | |
} | |
public override void Undo() | |
{ | |
Console.WriteLine("Move Undo!!"); | |
player.x-=x; | |
player.y-=y; | |
} | |
} |
如上所示就是一个命令模式的基本使用,在某些情况下我们应该将所有操作用命令管理,尽管这样比较麻烦,但一旦建立起一个统一的管理模式后,你会发现一切都是值得的。
# 存在的问题
仔细观察你会发现,我们每次我们使用一个命令都会创建一个命令对象,如果我们频繁的使用命令我们就会不断的创建对象,而这些对象其实我们只使用了一次。怎么解决这个问题呢?下一章的 享元模式
让我们一起来解决吧。