使用建造者模式模拟游戏地图的创建
Posted zaijianba
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用建造者模式模拟游戏地图的创建相关的知识,希望对你有一定的参考价值。
使用建造者模式模拟游戏地图的创建
换种形式学设计模式,让自己更有兴趣的学设计模式 :)
本文使用了建造者模式创建不同的游戏地图,当然是用控制台模拟的假地图...
1 何为建造者模式
1.1 介绍
建造者模式,是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
1.2 特点
- 隔离复杂对象的创建和使用,相同的方法,不同执行顺序,产生不同事件结果
- 多个部件都可以装配到一个对象中,但产生的运行结果不相同
- 产品类非常复杂或者产品类因为调用顺序不同而产生不同作用
- 初始化一个对象时,参数过多,或者很多参数具有默认值
- Builder模式不适合创建差异性很大的产品类
产品内部变化复杂,会导致需要定义很多具体建造者类实现变化,增加项目中类的数量,增加系统的理解难度和运行成本 - 需要生成的产品对象有复杂的内部结构,这些产品对象具备共性;
总的来说,建造者模式就是把一个个零部件添加到了一样产品上,最后创建出一个完整的产品,不同产品之间需要有共性,例如汽车都有轮子和引擎,可能引擎马力不同,轮子数量不同,用户只需要挑选成品产品而不需要知道造车子的细节。
2 建造者模式框架
2.1 建造者模式UML图
2.2 包含角色
- 指挥者(Director)直接和客户(Client)进行需求沟通;
- 沟通后指挥者将客户创建产品的需求划分为各个部件的建造请求(Builder);
- 将各个部件的建造请求委派到具体的建造者(ConcreteBuilder);
- 各个具体建造者负责进行产品部件的构建;
- 最终构建成具体产品(Product)。
3 创建游戏地图
3.1 需求分析
用户通过客户端选择地图种类之后,系统自动为用户创建不同的游戏地图。
游戏地图包含两种:
- 森林地图(树多)
- 怪兽地图(怪兽多)
地图包含的共通元素有:
- 树
- 路
- 怪兽
- NPC
3.2 确定模式
通过分析可知:
- 最终产品 游戏地图 差异性不大,包含共通性。
- 最终产品包含多种元素,有一定的复杂性。
- 地图元素的不同决定了地图的差异性,
通过以上的项目特点,我们可以看到建造者模式很符合本项目需求。??
3.3 代码编写
3.3.1 项目结构图
3.3.2 产品零配件代码
此项目中的产品零件即为地图元素
地图元素抽象类:
/// <summary>
/// 地图元素抽象类
/// </summary>
abstract class IMapElement
//x坐标
public int _x;
//y坐标
public int _y;
public string _name;
public IMapElement(string name)
//模拟加载地图元素耗时,并且需要一定间隔让随机数产生不重复
Thread.Sleep(100);
Random random = new Random();
this._x = random.Next(0, 100);
this._y = random.Next(0, 100);
this._name = name;
//元素展示
public abstract void Dispaly();
具体地图元素类:包含怪兽、NPC、树、路
/// <summary>
/// 怪兽类
/// </summary>
class Monster : IMapElement
public double _blood;
public Monster(string name) : base(name)
this._blood =new Random().Next(0,100);
public override void Dispaly()
Console.WriteLine($"元素类型:怪兽;血量:_blood;元素名称:_name;元素坐标x:_x,y:_y;\\r\\n");
/// <summary>
/// NPC类
/// </summary>
class NPC : IMapElement
public string _job;
public NPC(string name, string job) : base(name)
this._job = job;
public override void Dispaly()
Console.WriteLine($"元素类型:NPC;职位:_job;元素名称:_name;元素坐标x:_x,y:_y;\\r\\n");
/// <summary>
/// 树类
/// </summary>
class Tree : IMapElement
public int _height;
public Tree(string name) : base(name)
this._height = new Random().Next(1,50);
public override void Dispaly()
Console.WriteLine($"元素类型:树;高度:_heightm;元素名称:_name;元素坐标x:_x,y:_y;\\r\\n");
/// <summary>
/// 路
/// </summary>
class Way : IMapElement
public int _length;
public Way(string name) : base(name)
this._length = new Random().Next(100,10000);
public override void Dispaly()
Console.WriteLine($"元素类型:路;长度:_lengthm;元素名称:_name;元素坐标x:_x,y:_y;\\r\\n");
这些地图元素是地图的"零配件",地图元素的不同导致地图种类的不同。
3.3.3 具体产品
此项目中具体的产品即为地图(Game Map)
游戏地图类:
/// <summary>
/// 游戏场景(具体的产品)
/// </summary>
class GameMap
//地图元素集合
public IList<IMapElement> MapElements = new List<IMapElement>();
/// <summary>
/// 添加地图元素
/// </summary>
/// <param name="MapElement"></param>
public void AddMapElements(IMapElement MapElement)
MapElements.Add(MapElement);
/// <summary>
/// 展示地图
/// </summary>
public void Show()
Console.WriteLine("——————————————————————地图显示————————————————————\\r\\n");
foreach (var element in MapElements)
element.Dispaly();
3.3.4 创建者接口
创建者接口为创建一个Product对象的各个部位指定抽象接口。
interface IGameMapBuilder
void BuilderTree();
void BuilderWay();
void BuilderMonster();
void BuilderNPC();
GameMap GetGameMap();
3.3.5 具体创建者
具体创建者是产品构建差异体现,具体实现如何构建产品。
本项目中的具体创建者有两个:
- ForestMapBuilder(森林地图创建者)
- MonsterMapBuilder(怪兽地图创建者)
这两个创建者都继承抽象创建者IGameMapBuilder
ForestMapBuilder:
/// <summary>
/// 森林游戏场景具体建造者----特点:树多
/// </summary>
class ForestMapBuilder : IGameMapBuilder
private GameMap gameMap = new GameMap();
public void BuilderMonster()
Monster monster1 = new Monster("哥斯拉");
Monster monster2 = new Monster("异形");
Monster monster3 = new Monster("女朋友");
gameMap.AddMapElements(monster1);
gameMap.AddMapElements(monster2);
gameMap.AddMapElements(monster3);
public void BuilderNPC()
NPC npc1 = new NPC("NPC", "任务接取处");
gameMap.AddMapElements(npc1);
public void BuilderTree()
for (int i = 0; i < 15; i++)
gameMap.AddMapElements(new Tree($"树i"));
public void BuilderWay()
Way way = new Way("主路");
gameMap.AddMapElements(way);
public GameMap GetGameMap()
return gameMap;
MonsterMapBuilder:
/// <summary>
/// 怪物地图创建者 特点:怪物多
/// </summary>
class MonsterMapBuilder : IGameMapBuilder
private GameMap gameMap = new GameMap();
public void BuilderMonster()
for (int i = 0; i < 15; i++)
gameMap.AddMapElements(new Monster($"怪物i"));
public void BuilderNPC()
NPC npc1 = new NPC("任务npc", "任务接取处");
NPC npc2 = new NPC("商店npc", "购买物品");
gameMap.AddMapElements(npc1);
gameMap.AddMapElements(npc2);
public void BuilderTree()
for (int i = 0; i < 3; i++)
gameMap.AddMapElements(new Tree($"树i"));
public void BuilderWay()
Way way1 = new Way("主路");
Way way2 = new Way("史诗之路");
gameMap.AddMapElements(way1);
gameMap.AddMapElements(way2);
public GameMap GetGameMap()
return gameMap;
3.3.6 指挥者
指挥者指定创建者创建,并且决定创建顺序
本项目中的创建者为GameMapDirect
class GameMapDirector
public void Construct(IGameMapBuilder builder)
Console.WriteLine("---------------正在加载树资源-----------------");
builder.BuilderTree();
Console.WriteLine("---------------正在加载怪物资源---------------");
builder.BuilderMonster();
Console.WriteLine("---------------正在加载道路资源---------------");
builder.BuilderWay();
Console.WriteLine("---------------正在加载NPC资源----------------");
builder.BuilderNPC();
Console.WriteLine("-----------------资源加载完毕-----------------");
Construct()
方法参数为创建者,方法内部指定了创建顺序。
3.3.7 客户端代码
static void Main(string[] args)
Console.WriteLine("请选择地图类型:1.怪兽地图 2.森林地图");
string result = Console.ReadLine().Trim();
IGameMapBuilder builder = null;
if (Convert.ToInt32(result) == 1)
Console.WriteLine("--------------正在加载怪兽地图--------------------");
builder = new MonsterMapBuilder();
else
Console.WriteLine("--------------正在加载森林地图--------------------");
builder = new ForestMapBuilder();
GameMapDirector director = new GameMapDirector();
//建造者指派builder去建造地图
director.Construct(builder);
//建造者建造好地图之后返回地图
GameMap gameMap = builder.GetGameMap();
//地图呈现
gameMap.Show();
Console.Read();
3.3.8 最终结果
可以看到,玩家选择了怪兽地图,指挥者指定怪兽地图建造者建造地图,建造顺序按照指挥者方法内部顺序加载地图,最后呈现了一个怪物很多的地图:)
4 总结
4.1 优缺点:
优点:
- 使用建造者模式可以使客户端不必知道产品内部组成的细节。
- 具体的建造者类之间是相互独立的,这有利于系统的扩展。
- 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
缺点:
- 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
4.2 和抽象工厂对比
- 抽象工厂返回一个一系列相关产品族,建造者返回一个组装好的完整产品。
- 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象 。
- 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车
? 看到第三点突然想到,本项目中的地图元素可以使用简单工厂实现或者工厂方法模式实现,简单工厂的话就用Switch xxxxx
,使用工厂方法模式的话就有TreeFactory
、MonsterFactory
....
? 如果再之后怪兽细分为各种怪兽:皮卡丘、小拉达、等等等...那么就可以用抽象工厂模式生产怪兽族。。。妙呀??
版权声明:本文为吴恺的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文地址:https://www.cnblogs.com/zaijianba/p/11584625.html
我的个人博客地址:www.wukailiving.cn
本文是个小菜鸡写的,对代码理解并不深刻,轻喷。
如有不足之处,欢迎指正!
以上是关于使用建造者模式模拟游戏地图的创建的主要内容,如果未能解决你的问题,请参考以下文章