《设计模式与游戏完美开发》-享元模式(FlyWeight)恶棍笔记

享元模式!
几乎任何时候都需要思考的,一个实例是可以复用的嘛!还是每一个调用者都需要有一份新的?

在游戏属性管理时,我们可以看到属性可以被切割两次:

  1. 共享or不共享
  2. 变化or不会变化
这部分是大家都有的属性。而且固定的。我出生时就是这样的数据。基本不会变化。它成为了一种配置。
比如超级士兵最高

public class BaseAttr
{
private int m_MaxHp;
private string m_AttrName;
private float m_speed;

public BaseAttr(int hp,float speed,string name)
{
	this.MaxHp=hp;
	this.MoveSpeed=speed;
	this.AttrName=AttrName;
}

public int GetMaxHp(){return m_MaxHP}
public float GetMoveSpeed(){return m_speed}
public string GetAttrName(){return m_AttrName}
}

我们可以在以上这部分内容之后继承一个新的类,增加我们的新属性。
比如我们新建一个EnemyBaseAttr类,表示怪物的属性,怪物在游戏中的属性会比普通玩家一个【暴击率】

接下来我们建立一些类来处理属性中【会变化】的部分

ICharacterAttr,SoldierAttr,EnemyAttr,这些定义角色属性中会按游戏执行而变化的部分,属于各角色对象自己管理的部分。
它会有一个BaseAttr。


public abstact class ICharacterAttr
{
protected BaseAttr m_BaseAttr=null;
protected int m_NowHp=0;
protected IAttrStrategy m_AttrStrategy=null;
//这个是我们在……嗯,策略模式里建立的策略类的属性类,方便进行属性计算的。
public ICharacterAttr(){}

protected void SetBaseAttr(BaseAttr BaseAttr){
	 m_BaseAttr=BaseAttr;//我猜是因为baseattr只有一个,所以这边传过来让它知道就可以了。
}
public void SetAttrStrategy(IAttrStrategy theAttrStrategy)
{
	m_AttrStrategy=theAttrStrategy;
}
//获取属性的计算策略
public IAttrStrategy GetAttrStrategy()
{
	return m_AttrStrategy;
}

/*
获取hp、最大hp(引用baseattr)(虚函数),获取移动速度(引用baseattr)(虚函数),获取属性名称(引用baseattr)(虚函数)
*/
除了以上这些内容以外。
还有哪些函数:
1. 回满当前hp值。m_nowHp=baseattr.GetMaxHp()
2. 初始化角色属性。virtual函数。initAttr(){m_AttrStrategy.InitAttr(this);FullNowHp();}
3. 获得攻击加成。(这个与策略类有关)m_AttrStrategy.GetAtkPlusValue(this);
4. 获得被武器攻击后的伤害值。

public void CalDmgValue(ICharacter Attacker)
{
	int AtkValue=Attacker.GetAtkValue();
	AtkValue -=m_AttrStrategy.GetDmgDescValue(this);
	m_NowHP -=AtkValue;
}//这里直接涉及到很多计算的情况了。
}

在以上这个类里面的一些虚函数,可以给子类重写。比如获得属性名称,比如初始化角色属性。
子类就是SoiderAttr和EnemyAttr

一些特殊化的内容就可以在这里实现。比如我们的士兵。会随着等级增加生命值。那么在获取最大生命值时,在这里就被特殊的调用为一个baseattr+一个特殊的、会变的属性a_addMaxhp.
而敌人则是有一个暴击率和获得暴击率、修改暴击率的方法。

public class SoldierAttr : ICharcterAttr
{
	protexted int m_SoldierLV;//这两个属性就是属于会变的属性
	protexted it m_AddMaxHp;
	public SoldierAttr(){}
	public void SetSoldierAttr(BaseAttr BaseAttr)
	{
		base.SetBaseAttr(BaseAttr);
		m_SoiderLV=1;
		m_AddMaxHp=0;
	}
	//还有一些函数,比如设置等级。获取等级。获取最大hp(base.GetMaxhp+m_addMaxHp)。设置新增的最大生命力。
}

然后是用属性工厂来分别管理游戏中的3个属性对象。

这个工厂类是可以提供给【调用者】以一个对应的attr实例。这个attr里面包含了会【变化】和不会【变化】的东西。

我们建立了一个叫做AttrFactory的类。它基本上只会有一个。它手上有士兵、怪物、武器的三个工厂,这个意思是,它手上有很多工厂的内容。
我感觉这个是这样用的。就是我们有一个表格,会这样配置我们的怪物

编号 名称 血量 速度
1 新兵 200 2.0
20 勇士 201 2.0

然后这些数据在游戏开始前被导入到这个工厂类中。被储存在士兵Attrdict中。
在创建这个attrFactory时就读入这个表格。这让这个类的其他方法能够在产生属性对象的过程中,获取对应的共享属性对象。

好。接下来就是重头戏。以下是这个类其中的一个方法。

public class AttrFactory : IAttrFactory
{

public overide SoidierAttr GetSoidierAttr(int AttrID)
{	
	//这里的id就是之前放到士兵dict中的key。如果找到,则创建一个soldierAttr返回。如果找不到,则报错。
	如果找到:
	SoldierAttr NewAttr =new SoldierAttr();
	NewAttr.SetSoiderAttr(m_SoldierAttrDB(AttrID));//看!不可变化的内容被包到了可变化的内容里。
	return NewAttr;

}
}

如果没有flyweight,那要怎么样实现工厂呢?

嗯。就是在工厂类里getsolderAttr(id)
switch(id)
4:return new SoldierAttr(“新兵”,200,1.0);
10:return new SoldierAttr(“战士”,201,1.1);
弊端在于,一个麻烦,不同的工厂都要重写,一个是没有实现共同的属性(配置)和特别的属性(临时)。

扩展

吃了一顿之后,忘了要扩展什么了。
噢,对,想想这个享元模式可以用在什么其他地方。
它包了一个包含了公用的对象的特殊对象的制作过程。除了形式上有意义以外,性能上也很重要。以后遇到有公用的对象的情况就可以用它。外部不需要知道制作过程。哇哦。结论中说可以用在对象池上。
就是有一些对象,是baseattr,在创建子弹时,其实是调用其中一个baseattr.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值