《游戏编程模式》(8)
来源:互联网 发布:编程图标 编辑:程序博客网 时间:2024/06/06 00:37
《游戏编程模式》最后一篇,刚从英国玩了一圈,春节又要到啦
Chapter 19 对象池
使用固定的对象池重用对象,取代单独地分配和释放对象,达到提升性能和优化内存使用的目的。
使用情境:
- 频繁创建销毁对象;
- 对象大小基本一致;
- 堆上分配内存较慢或可能产生内存碎片;
粒子类:
用union节省内存:粒子使用时用live结构体,不使用时用next指针
1 class Particle 2 { 3 4 public: 5 Particle() 6 : framesLeft_(0) 7 {} 8 9 void init(double x, double y,10 double xVel, double yVel, int lifetime)11 {12 x_ = x; y_ = y;13 xVel_ = xVel; yVel_ = yVel;14 framesLeft_ = lifetime;15 } 16 17 bool animate()18 {19 if (!inUse()) return false;20 21 framesLeft_--;22 x_ += xVel_;23 y_ += yVel_;24 25 return framesLeft_ == 0;26 }27 28 bool inUse() const { return framesLeft_ > 0; }29 30 Particle* getNext() const { return state_.next; }31 void setNext(Particle* next) { state_.next = next; }32 33 private:34 int framesLeft_; 35 36 union37 {38 // State when it's in use.39 struct40 {41 double x, y;42 double xVel, yVel;43 } live;44 45 // State when it's available.46 Particle* next;47 48 } state_;49 50 };
粒子对象池:
1 class ParticlePool 2 { 3 4 public: 5 void create(double x, double y, 6 double xVel, double yVel, int lifetime); 7 8 void animate() 9 {10 for (int i = 0; i < POOL_SIZE; i++)11 {12 particles_[i].animate();13 }14 } 15 16 private:17 static const int POOL_SIZE = 100;18 Particle particles_[POOL_SIZE];19 20 Particle* firstAvailable_;21 };22 23 ParticlePool::ParticlePool()24 {25 // The first one is available.26 firstAvailable_ = &particles_[0];27 28 // Each particle points to the next.29 for (int i = 0; i < POOL_SIZE - 1; i++)30 {31 particles_[i].setNext(&particles_[i + 1]);32 }33 34 // The last one terminates the list.35 particles_[POOL_SIZE - 1].setNext(NULL);36 37 }
构造函数中串起一个链表。
创建一个新粒子:
1 void ParticlePool::create(double x, double y, 2 double xVel, double yVel, 3 int lifetime) 4 { 5 // Make sure the pool isn't full. 6 assert(firstAvailable_ != NULL); 7 8 // Remove it from the available list. 9 Particle* newParticle = firstAvailable_;10 firstAvailable_ = newParticle->getNext();11 12 newParticle->init(x, y, xVel, yVel, lifetime);13 }
动画放完放回粒子池:
1 void ParticlePool::animate() 2 { 3 for (int i = 0; i < POOL_SIZE; i++) 4 { 5 if (particles_[i].animate()) 6 { 7 // Add this particle to the front of the list. 8 particles_[i].setNext(firstAvailable_); 9 firstAvailable_ = &particles_[i];10 }11 }12 }
- 如果对象尺寸大小不一,可以考虑根据对象的尺寸划分大小不同的池,避免过多的内存浪费;
- 向对象池请求失败:
(1). 避免;
(2). 不创建了(特效叠加时…);
(3). 清理现存对象(是否会卡);
(4). 增加对象池大小(适当时机再恢复原大小)
Chapter 20 空间分区
将对象存储在根据位置组织的数据结构中来高效地定位它们。
你有一组对象(可能还挺多),将对象存储在一个根据对象位置来组织的数据结构中,该数据结构可以让你高效查询位于或靠近某处的对象。当对象位置改变时,更新并继续维护该空间数据对象。
用更复杂的数据结构(空间)来换取大量查询时的性能优化(时间)。
Unit类:
1 class Unit 2 { 3 friend class Grid; 4 5 public: 6 Unit(Grid* grid, double x, double y) 7 : grid_(grid), 8 x_(x), 9 y_(y)10 {} 11 12 void move(double x, double y);13 14 private:15 double x_, y_;16 Grid* grid_; 17 18 Unit* prev_;19 Unit* next_;20 };
Grid类:
1 class Grid 2 { 3 4 public: 5 Grid() 6 { 7 // Clear the grid. 8 for (int x = 0; x < NUM_CELLS; x++) 9 {10 for (int y = 0; y < NUM_CELLS; y++)11 {12 cells_[x][y] = NULL;13 }14 }15 }16 17 static const int NUM_CELLS = 10;18 static const int CELL_SIZE = 20; 19 20 private:21 Unit* cells_[NUM_CELLS][NUM_CELLS];22 23 };
cells_是一个双重链表,记录了单元格内的unit链。
初始化:找到单位所在的单元格加到链表前面
1 Unit::Unit(Grid* grid, double x, double y) 2 : grid_(grid), 3 x_(x), 4 y_(y), 5 prev_(NULL), 6 next_(NULL) 7 { 8 grid_->add(this); 9 }10 11 void Grid::add(Unit* unit)12 {13 // Determine which grid cell it's in.14 int cellX = (int)(unit->x_ / Grid::CELL_SIZE);15 int cellY = (int)(unit->y_ / Grid::CELL_SIZE);16 17 // Add to the front of list for the cell it's in.18 unit->prev_ = NULL;19 unit->next_ = cells_[cellX][cellY];20 cells_[cellX][cellY] = unit;21 22 if (unit->next_ != NULL)23 {24 unit->next_->prev_ = unit;25 }26 }
Unit移动:查看是否还在原先的单元格,如果离开了原先的单元格,从链表中移除再add
1 void Unit::move(double x, double y) 2 { 3 grid_->move(this, x, y); 4 } 5 6 void Grid::move(Unit* unit, double x, double y) 7 { 8 // See which cell it was in. 9 int oldCellX = (int)(unit->x_ / Grid::CELL_SIZE);10 int oldCellY = (int)(unit->y_ / Grid::CELL_SIZE); 11 12 // See which cell it's moving to.13 int cellX = (int)(x / Grid::CELL_SIZE);14 int cellY = (int)(y / Grid::CELL_SIZE);15 16 unit->x_ = x;17 unit->y_ = y;18 19 // If it didn't change cells, we're done.20 if (oldCellX == cellX && oldCellY == cellY) return; 21 22 // Unlink it from the list of its old cell.23 if (unit->prev_ != NULL)24 {25 unit->prev_->next_ = unit->next_;26 }27 28 if (unit->next_ != NULL)29 {30 unit->next_->prev_ = unit->prev_;31 } 32 33 // If it's the head of a list, remove it.34 if (cells_[oldCellX][oldCellY] == unit)35 {36 cells_[oldCellX][oldCellY] = unit->next_;37 } 38 39 // Add it back to the grid at its new cell.40 add(unit);41 42 }
战斗:查找单元格相邻一半的单元格(4个)
1 void Grid::handleMelee() 2 { 3 for (int x = 0; x < NUM_CELLS; x++) 4 { 5 for (int y = 0; y < NUM_CELLS; y++) 6 { 7 handleCell(x, y); 8 } 9 }10 }11 12 void Grid::handleCell(int x, int y)13 {14 Unit* unit = cells_[x][y];15 while (unit != NULL)16 {17 // Handle other units in this cell.18 handleUnit(unit, unit->next_); 19 20 // Also try the neighboring cells.21 if (x > 0 && y > 0) handleUnit(unit, cells_[x - 1][y - 1]);22 if (x > 0) handleUnit(unit, cells_[x - 1][y]);23 if (y > 0) handleUnit(unit, cells_[x][y - 1]);24 if (x > 0 && y < NUM_CELLS - 1)25 {26 handleUnit(unit, cells_[x - 1][y + 1]);27 } 28 29 unit = unit->next_;30 }31 }32 33 void Grid::handleUnit(Unit* unit, Unit* other)34 {35 while (other != NULL)36 {37 if (distance(unit, other) < ATTACK_DISTANCE)38 {39 handleAttack(unit, other);40 } 41 42 other = other->next_;43 }44 }
四叉树:
如果空间中的对象超过阈值,空间就一切四
- 添加单个对象不会产生一次以上的拆分动作
- 删除对象需要判断父区域对象总数,如果低于阈值则合并区域
- 移动对象等于一次删除和一次添加
0 0
- 《游戏编程模式》(8)
- 《游戏编程模式》(8)
- 《游戏编程模式》(6)
- 《游戏编程模式》(6)
- 游戏编程入门(19):使用演示模式展示游戏
- 游戏编程模式 - 状态模式
- 游戏编程模式:轻量级(Flyweight)模式(Part I)
- 游戏编程模式:轻量级(Flyweight)模式(Part II)
- 游戏编程模式:轻量级(Flyweight)模式(Part III)
- 游戏编程模式:命令模式(Part I)
- 游戏编程模式:命令模式(Part II)
- 游戏编程模式:命令模式(Part III)
- 游戏核心算法编程内幕学习(三):设计模式
- 游戏编程模式:前言(架构,性能和游戏)(Part I)
- 游戏编程模式:前言(架构,性能和游戏)(Part II)
- 游戏编程模式:前言(架构,性能和游戏)(Part III)
- 【游戏核心算法编程内幕】---设计模式
- 游戏编程模式——命令模式(自定义配置按键)
- macOS Sierra 10.12.2与intellij 2017 EAP与Docker 1.13.0
- 怎样打开64位 Ubuntu 的32位支持功能?
- java的输入输出1
- JDBC调用存储过程
- spark入门之一 spark组件
- 《游戏编程模式》(8)
- PYTHON笔记-字符串
- Ubuntu 16.04 安装 Nvidia 显卡驱动
- 1046.Shortest Distance (20)
- Git远程分支
- Android图片加载库对比:Universal-Image-Loader vs Glide vs Fresco vs Picasso几大框架的选择
- 设计模式笔记之----建造者模式
- Session保持持久化对象
- 《硅谷之谜》读书笔记:追求卓越,改变自己