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_; };