7_DoubleBuffer 游戏编程中的双缓存模式
### double buffer 双缓存 简单说: 当一个缓存被读取的时候,往另一个缓存里写入, 如此交替 #### the pattern
有两个缓存实例,一个是 current buffer, 一个是next buffer 从current buffer读取信息, 往next buffer里写入信息.
swap操作,进行两种buff的身份切换 #### 何时使用
需要增量修改的状态
在修改的过程中需要进行访问
当访问数据的时候,不会发现数据正在被写入
读操作不用等待写的操作完成 #### 注意事项 swap操作比较耗时
必须有两个buffer, 内存消耗变大 #### Sample Code ####一个帧缓存的例子 ```
class Framebuffer
{
public:
Framebuffer() { clear(); } void clear()
{
for (int i = ; i < WIDTH * HEIGHT; i++)
{
pixels_[i] = WHITE;
}
} void draw(int x, int y)
{
pixels_[(WIDTH * y) + x] = BLACK;
} const char* getPixels()
{
return pixels_;
} private:
static const int WIDTH = ;
static const int HEIGHT = ; char pixels_[WIDTH * HEIGHT];
}; // 问题版本
class Scene
{
public: // 每一帧执行 void draw()
{
buffer_.clear(); buffer_.draw(, );
buffer_.draw(, );
// 问题! video driver 可以在任何时候读取pixels, 可能会读到非法值
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
buffer_.draw(, );
} Framebuffer& getBuffer() { return buffer_; } private:
Framebuffer buffer_; void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_; current_ = next_;
next_ = temp;
} }; // 使用double buffer
class Scene
{
public:
Scene()
: current_(&buffers_[]),
next_(&buffers_[])
{} // video driver 只会从 current里获取pixel
void draw()
{
next_->clear(); next_->draw(, );
// ...
next_->draw(, ); swap();
} Framebuffer& getBuffer() { return *current_; } private:
void swap()
{
// Just switch the pointers.
Framebuffer* temp = current_;
current_ = next_;
next_ = temp;
} Framebuffer buffers_[];
Framebuffer* current_;
Framebuffer* next_;
}; ``` ##### Artificial unintelligence ```
class Actor
{
public:
Actor() : slapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void reset() { slapped_ = false; }
void slap() { slapped_ = true; }
bool wasSlapped() { return slapped_; } private:
bool slapped_;
}; // 每一帧都会调用actor的update, ,所有的actor需要同时进行更新
// actor之间可以交互, 例如击打 class Stage
{
public:
void add(Actor* actor, int index)
{
actors_[index] = actor;
} void update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
actors_[i]->reset();
}
} private:
static const int NUM_ACTORS = ; Actor* actors_[NUM_ACTORS];
}; // 同一时间, 只会有一个actor执行update class Comedian : public Actor
{
public:
void face(Actor* actor) { facing_ = actor; } virtual void update()
{
if (wasSlapped()) facing_->slap();
} private:
Actor* facing_;
}; // 面对某人
harry ------> balay ------> chump
^ |
|
-------------------------------v Stage stage; Comedian* harry = new Comedian();
Comedian* baldy = new Comedian();
Comedian* chump = new Comedian(); harry->face(baldy);
baldy->face(chump);
chump->face(harry); stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); harry->slap(); stage.update(); // slap
harry ---slap---> balay --slap----> chump
^ |
|
----------------slap---------------v
正确的结果 #如果把三人的执行顺序换一下, 结果将不正确#
stage.add(harry, );
stage.add(baldy, );
stage.add(chump, ); 只有harry slap 了baldy buffered slaps // 把slap用buffer记录下来 class Actor
{
public:
Actor() : currentSlapped_(false) {} virtual ~Actor() {}
virtual void update() = ; void swap()
{
// Swap the buffer.
currentSlapped_ = nextSlapped_; // Clear the new "next" buffer.
nextSlapped_ = false;
} void slap() { nextSlapped_ = true; }
bool wasSlapped() { return currentSlapped_; } private:
bool currentSlapped_;
bool nextSlapped_;
}; void Stage::update()
{
for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->update();
} for (int i = ; i < NUM_ACTORS; i++)
{
actors_[i]->swap();
}
} ``` #### buffer swap
swap需要锁住两个buffer, 所需需要尽量的轻量快速
交换指针 引用
.快速
.外部代码不能保存buffer指针
当前的数据,是两帧之前的数据(读current的同时,数据写入了next) buffer之间拷贝数据
如果无法进行swap,可以把next的数据copy到current
如果数量小则没什么问题,如果大则会耗时 ```
当很多对象都有需要swap操作时, 会很慢
下面这个例子,不用swap,而是slap的时候修改了next的值 class Actor
{
public:
static void init() { current_ = ; }
static void swap() { current_ = next(); } void slap() { slapped_[next()] = true; }
bool wasSlapped() { return slapped_[current_]; } private:
static int current_;
static int next() { return - current_; } bool slapped_[];
};
``` #### See also
double buffer 模式在图形编程上应用广泛 You can find the Double Buffer pattern in use in almost every graphics API out there. For example, OpenGL has swapBuffers(), Direct3D has “swap chains”, and Microsoft’s XNA framework swaps the framebuffers within its endDraw() method.
7_DoubleBuffer 游戏编程中的双缓存模式的更多相关文章
- 第28月第21天 记事本Unicode 游戏编程中的人工智能技术
1. Windows平台,有一个最简单的转化方法,就是使用内置的记事本小程序notepad.exe.打开文件后,点击文件菜单中的另存为命令,会跳出一个对话框,在最底部有一个编码的下拉条. 里面有四个选 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用
RPC(Remote Procedure Call Protocol)--远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议.RPC协议假定某些传输协议的存在 ...
- windows游戏编程X86 32位保护模式下的内存管理概述(二)
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22448323 作者:jadeshu 邮箱: jades ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[3]--体验
运行环境,客户端一般编译为.Net 3.5 Unity兼容,服务端因为用了一些库,所以一般为4.0 或往上.同一份代码,建立拥有2个项目.客户端引用: WindNet.Client服务端引用: OpL ...
- 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序
在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...
- 游戏编程系列[1]--游戏编程中RPC协议的使用[2]--Aop PostSharp篇
上一篇我们使用了一个通用JSON协议约定来进行达到远程调用的目的.但是从实现上,我们需要不断的在所有的方法上添加拦截,并且判断拦截,然后执行,这就达到了一个比较繁琐的目的. 之前我们尝试过使用代码生成 ...
- windows游戏编程X86 32位保护模式下的内存管理概述(一)
本系列文章由jadeshu编写,转载请注明出处.http://blog.csdn.net/jadeshu/article/details/22445945 作者:jadeshu 邮箱: jades ...
- 如何系统掌握游戏编程中3D图形学相关的基础?
https://www.zhihu.com/question/27544895 三维几何学基础:三维坐标系统点与矢量矩阵与几何变换四元数与三维旋转
- 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记5——Direct3D中的顶点缓存和索引缓存
第12章 Direct3D绘制基础 1. 顶点缓存 计算机所描绘的3D图形是通过多边形网格来构成的,网网格勾勒出轮廓,然后在网格轮廓的表面上贴上相应的图片,这样就构成了一个3D模型.三角形网格是构建物 ...
随机推荐
- DFS应用——找出无向图的割点
[0]README 0.1) 本文总结于 数据结构与算法分析, 源代码均为原创, 旨在 理解 "DFS应用于找割点" 的idea 并用源代码加以实现: 0.2) 必须要事先 做个s ...
- systemctl使用说明
# systemctl #输出已激活单元 # systemctl list-units #输出已激活单元 # systemctl --failed #输出运行失败的单元 # systemctl lis ...
- Lumen开发:phpunit单元测试
先来直接运行,cmd先进入根目录,然后进入tests或是test文件夹 运行命令行:..\vendor\bin\phpunit ExampleTest.php laravel/lumen中集成了PHP ...
- iOS 线程管理的学习记录
本文转载至 http://www.2cto.com/kf/201312/265451.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 2 ...
- HTML使用post方式提交中文内容出现乱码的错误解决方式
今天在做一个例子的时候,使用post方式提交表单,如果有中文的话,在另一个页面显示出来的时候,总是会出现乱码: 但是将提交方式改为get的时候,就不会出现这种错误. 详细错误见下面图片和代码. HTM ...
- php自定义函数: amr转mp3格式
<?php function amr2mp3($file){ if (file_exists($file . '.mp3') == true) { return; } else { $param ...
- fkwの题目(祝松松生日快乐!)
麓山国际实验学校 傅少,匡哥和巨夫出的题目(共3道) 一.题目概况 题目名称 打地铺 泡妹子 开房间 题目类型 传统 传统 传统 可执行文件名 deeeep soccer room 输入文件名 dee ...
- MySQL删除相同前缀的表,修改某个库的存储引擎
MySQL5.0 之后,提供了一个新的数据库information_schema,用来记录MySQL总的元数据信息.元数据指的是 数据的数据. 比如表名.列名.列类型.索引名等表的各种属性名称.这个库 ...
- ARDUINO W5100 WebServer测试
1.直接下载官方的enternet->WebServer代码 /* Web Server A simple web server that shows the value of the anal ...
- ZOJ - 3705 Applications 【模拟】
题目链接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3705 题意 给出N个队员 然后一个教练要从中选择 M名队员 要选 ...