游戏中的设计模式:享元模式
2017-04-28 22:59
288 查看
Flyweight Pattern : Use sharing to support large numbers of fine-grained objects efficiently.
假设在你的游戏中有一片森林,森林是由成千上万棵树形成,每棵树都有这样几个部分:
用来规定树干和树叶的形状的网格模型。
树干和树叶的纹理。
这棵树在树林中的位置。
用来调整尺寸和色调的参数,以使得每棵树看起来都不一样。
如果用下面的代码来实现树的类
用草图来表示就是这样的,每一棵树都有着自己的网格模型,纹理,以及其他数据,也就是说游戏中有一千棵树,你的内存中就有一千棵树的数据、网格模型和纹理。用这些去构成一个森林的话,GPU在一帧内所需处理的东西就太多了。
事实上,没有多少游戏开发者会这样做。虽然森林里有成千上万棵树,但是其实它们看起来都差不多。它们可能使用了相同的网格模型和纹理。这意味着这些树对象中的大部分属性在它们的实例中都是相同的。
Flyweight(抽象享元类):它通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法设置外部数据(外部状态)。
ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象,并在具体享元类中为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类,为每一个具体享元对象提供唯一的享元对象。
UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,用户可以将不能被共享的子类设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
FlyweightFactory(享元工厂类):享元工厂类用于创建并管理Flyweight对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合。当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)并将新建的对象存储在享元池中。
抽象享元类:
具体享元类:
享元工厂类:
这些代码用一张图来表示就像这样,通过把较大的网格模型和纹理图片共享,节约了内存空间,提高游戏性能。
享元模式可以减少内存中对象的数量,使得相同或者相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能
在享元模式中,外部状态相对独立,而且不会影响到其内部状态,这样使享元对象可以子啊不同环境中被共享
缺点:
享元模式使系统变得复杂,需要分离内部状态和外部状态,这让程序的逻辑复杂化
参考:http://gameprogrammingpatterns.com/flyweight.html
ab21
导语
如果一个软件系统在运行时所创建的相同或者相似的对象数量太多,将导致运行代价过高,带来系统资源浪费、性能下降等问题。在游戏开发中,这也是一个值得关注的问题,游戏的性能会直接影响玩家的游戏体验。假设在你的游戏中有一片森林,森林是由成千上万棵树形成,每棵树都有这样几个部分:
用来规定树干和树叶的形状的网格模型。
树干和树叶的纹理。
这棵树在树林中的位置。
用来调整尺寸和色调的参数,以使得每棵树看起来都不一样。
如果用下面的代码来实现树的类
public class Tree { private Mesh mesh_; private Texture bark_; private Texture leaves_; private Vector3 position_; private double height_; private double thickness_; private Color barkTint_; private Color leafTint_; }
用草图来表示就是这样的,每一棵树都有着自己的网格模型,纹理,以及其他数据,也就是说游戏中有一千棵树,你的内存中就有一千棵树的数据、网格模型和纹理。用这些去构成一个森林的话,GPU在一帧内所需处理的东西就太多了。
事实上,没有多少游戏开发者会这样做。虽然森林里有成千上万棵树,但是其实它们看起来都差不多。它们可能使用了相同的网格模型和纹理。这意味着这些树对象中的大部分属性在它们的实例中都是相同的。
定义
享元模式:运用共享技术有效地支持大量细粒度对象的复用。结构
享元模式结构较为复杂,通常结合工厂模式一起使用,在它的结构图中包含一个享元工厂类,结构如下图Flyweight(抽象享元类):它通常是一个接口或抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法设置外部数据(外部状态)。
ConcreteFlyweight(具体享元类):它实现了抽象享元类,其实例称为享元对象,并在具体享元类中为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类,为每一个具体享元对象提供唯一的享元对象。
UnsharedConcreteFlyweight(非共享具体享元类):并不是所有的抽象享元类的子类都需要被共享,用户可以将不能被共享的子类设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
FlyweightFactory(享元工厂类):享元工厂类用于创建并管理Flyweight对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合。当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)并将新建的对象存储在享元池中。
实现
考虑到游戏中的森林会使用相同的网格模型,树干及树叶纹理。我们可以为这些需要共用的属性新建一个类TreeModel,这样每一种类型的树就共用一种
TreeModel:
public class TreeModel { private Mesh mesh_; private Texture bark_; private Texture leaves_; }
抽象享元类:
public interface ITree { void setParam(Vector3 pos, double h, double t, Color bTint, Color lTint); }
具体享元类:
public class Tree : ITree { private TreeModel model_; private Vector3 position_; private double height_; private double thickness_; private Color barkTint_; private Color leafTint_; public Tree() { //default constructor } public Tree(TreeModel mod, Vector3 pos, double h, double t, Color bTint, Color lTint) { model_ = mod; setParam(pos, h, t, bTint, lTint); } //设置树的外部参数 public void setParam(Vector3 pos, double h, double t, Color bTint, Color lTint) { this.position_ = pos; this.height_ = h; this.thickness_ = t; this.barkTint_ = bTint; this.leafTint_ = lTint; } }
享元工厂类:
public class TreeFactory : System.Object { private static TreeFactory instance; //使用Hashtable存储TreeModel,实现享元池 private Hashtable TreeModels = new Hashtable (); public static PatrolFactory getInstance () { if (instance == null) { instance = new PatrolFactory (); } return instance; } public Tree getTree (string mod, TreeModel mod, Vector3 pos, double h, double t, Color bTint, Color lTint) { if (TreeModels.ContainsKey(mod)) { //如果mod存在,则直接在享元池中获取对应的TreeModel,用它创建Tree TreeModel model_ = (TreeModel)TreeModels[mod]; Tree temp = new Tree(model_, pos, h, t, bTint, lTint); } else { //如果mod不存在,先创建一个新的对象添加到享元池中,然后用它创建Tree TreeModel model_ = new TreeModel(); TreeModels.Add(mod, model_); Tree temp = new Tree(model_, pos, h, t, bTint, lTint); } return temp; } }
这些代码用一张图来表示就像这样,通过把较大的网格模型和纹理图片共享,节约了内存空间,提高游戏性能。
更多
单纯享元模式与复合享元模式……优缺点
优点:享元模式可以减少内存中对象的数量,使得相同或者相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能
在享元模式中,外部状态相对独立,而且不会影响到其内部状态,这样使享元对象可以子啊不同环境中被共享
缺点:
享元模式使系统变得复杂,需要分离内部状态和外部状态,这让程序的逻辑复杂化
参考:http://gameprogrammingpatterns.com/flyweight.html
ab21
相关文章推荐
- 游戏中的设计模式八(享元模式)
- 设计模式之Bridge——游戏篇
- 设计模式——享元模式
- 设计模式学习笔记(十二)——Flyweight享元模式
- 设计模式之Bridge——游戏篇
- 游戏开发中常用的设计模式
- 游戏开发中常用的设计模式
- 设计模式(13)-享元模式(Flyweight)
- .NET设计模式(13):享元模式(Flyweight Pattern)
- 经验技巧分享--ASP.NET和Ajax应用一个超级实用的设计模式---享元模式
- ASP.NET和Ajax应用一个超级实用的设计模式---享元模式
- 设计模式之Bridge——游戏篇
- 设计模式 --- 享元模式(Flyweight Pattern) 精选经验合集
- 设计模式与泡mm的关系之flyweight享元模式及享元模式的再思考
- builder模式在游戏设计中的应用
- 设计模式之Bridge——游戏篇
- 设计模式之Flyweight享元模式
- 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)
- 设计模式中结构型模式(六)享元模式(Facade)
- 设计模式学习(九)外观模式-享元模式-代理模式