简介
Game Programming Patterns,游戏编程模式,大致看完了点,记录一下,以后再看再次深入学习时再补充,电子书地址。
命令模式
译者原话:“命令是具现化的方法调用”。意味着将概念变成数据 ——一个对象——可以存储在变量中,传给函数。 所以称命令模式为“具现化方法调用”,意思是方法调用被存储在对象中。听起来像是回调
命令模式是一种回调的面向对象实现。
function makeMoveUnitCommand(unit, x, y) {
// 这个函数就是命令对象:
return function() {
unit.moveTo(x, y);
}
}
//行动以及撤销
function makeMoveUnitCommand(unit, x, y) {
var xBefore, yBefore;
return {
execute: function() {
xBefore = unit.x();
yBefore = unit.y();
unit.moveTo(x, y);
},
undo: function() {
unit.moveTo(xBefore, yBefore);
}
};
}
更多的使用回调函数实现,将方法封装好
在按键控制角色移动跳跃等按键控制上 可以实现更多的自定义 而不是很多的绑定,每一个按键的事件都是一个回调
原型模式
三个怪物,基本,弓兵,长矛兵
不用建一个怪物基类,然后下面创建三种
而是在基本兵的基础上,衍生出弓兵与长矛兵,以基本兵为原型
单例模式
游戏中,很多例如声音,声音管理器,特效,特效管理器,模型,模型管理器等
很多的管理器都成了单例类
例如,一个子弹,子弹管理器
class Bullet
{
public:
int getX() const { return x_; }
int getY() const { return y_; }
void setX(int x) { x_ = x; }
void setY(int y) { y_ = y; }
private:
int x_, y_;
};
class BulletManager
{
public:
Bullet* create(int x, int y)
{
Bullet* bullet = new Bullet();
bullet->setX(x);
bullet->setY(y);
return bullet;
}
bool isOnScreen(Bullet& bullet)
{
return bullet.getX() >= 0 &&
bullet.getX() < SCREEN_WIDTH &&
bullet.getY() >= 0 &&
bullet.getY() < SCREEN_HEIGHT;
}
void move(Bullet& bullet)
{
bullet.setX(bullet.getX() + 5);
}
};
子弹需要管理器嘛
class Bullet
{
public:
Bullet(int x, int y) : x_(x), y_(y) {}
bool isOnScreen()
{
return x_ >= 0 && x_ < SCREEN_WIDTH &&
y_ >= 0 && y_ < SCREEN_HEIGHT;
}
void move() { x_ += 5; }
private:
int x_, y_;
};
这样直接就可以了
单例有时候会增加其他类的代码量,最好的是OOP(对象自己管理好自己)
所以,游戏中很多的声音管理器,特效管理器,模型管理器等等,可以都放到一个Game管理器中,通过这个game来获取每一个管理器下方法
class Game
{
public:
static Game& instance() { return instance_; }
// 设置log_, et. al. ……
Log& getLog() { return *log_; }
FileSystem& getFileSystem() { return *fileSystem_; }
AudioPlayer& getAudioPlayer() { return *audioPlayer_; }
private:
static Game instance_;
Log *log_;
FileSystem *fileSystem_;
AudioPlayer *audioPlayer_;
};
Game::instance().getAudioPlayer().play(VERY_LOUD_BANG);
观察者模式
观察者模式,也就mvc架构,C#将其嵌入了语法event
例如游戏中的成就系统,要是摸个环节达成成就 就调用成就 这样就太乱了
成就单独分隔开
//观察者 监听
class Observer
{
public:
virtual ~Observer() {}
virtual void onNotify(const Entity& entity, Event event) = 0;
};
//成就作为观察者处理消息
class Achievements : public Observer
{
public:
virtual void onNotify(const Entity& entity, Event event)
{
switch (event)
{
case EVENT_ENTITY_FELL:
if (entity.isHero() && heroIsOnBridge_)
{
unlock(ACHIEVEMENT_FELL_OFF_BRIDGE);
}
break;
// 处理其他事件,更新heroIsOnBridge_变量……
}
}
private:
void unlock(Achievement achievement)
{
// 如果还没有解锁,那就解锁成就……
}
bool heroIsOnBridge_;
};
此时还需要一个添加删除观察者的管理类 通知下发给每个注册的管理者
class Subject
{
protected:
void notify(const Entity& entity, Event event)
{
for (int i = 0; i < numObservers_; i++)
{
observers_[i]->onNotify(entity, event);
}
}
// 其他代码…………
};
享元模式
抽象出共有的属性 修改不同的属性
渲染一片森林,每棵树都有网格贴图位置颜色等,这样GPU消耗会大
class Tree
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
一个老方法就是使用相同的网格和纹理,只改变不同树位置颜色信息
class TreeModel
{
private:
Mesh mesh_;
Texture bark_;
Texture leaves_;
};
class Tree
{
private:
TreeModel* model_;
Vector position_;
double height_;
double thickness_;
Color barkTint_;
Color leafTint_;
};
迭代器模式
- 迭代器模式使得你能够获取到序列中的所有元素而不用关心其类型是array,list,linked list或者是其他什么序列结构。这一点使得能够非常高效的构建数据处理通道--即数据能够进行一系列的变换,或者过滤,得到结果。事实上,这正是LINQ的核心模式。
- LINQ(Language Integrated Query)语言集成查询是一组用于c#和Visual Basic语言的扩展。它允许编写C#或者Visual Basic代码以操作内存数据的方式,查询数据库。
class Program
{
static void Main()
{
int[] numbers={2,12,5,15};
IEnumerable lowNums=
from n in numbers
where n<10
select n;
foreach(var x in lowNums)
{
Console.WriteLine(x);
}
}
}
- 迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接口,那么就能够被迭代;调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。
- 迭代器类似数据库中的游标,他是数据序列中的一个位置记录。迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。
- 协程其实就是一个IEnumerator(迭代器)