Koan《iphone游戏开发》 读书笔记之一:游戏引擎揭秘


Koan《iphone游戏开发》 读书笔记之一:游戏引擎揭秘
2011年09月01日
  本人做的读书笔记,版权归《iphone游戏开发》作者:[美]Paul Zirkle Joe Hogue 著 张龙 译,如作者及译者认为侵犯版权,本人马上删除该笔记,另外,转载慎重,因为版权非本人。。
  游戏引擎的组成:应用框架、状态机、图形引擎、物力引擎、音频引擎、游戏输入以及游戏逻辑等。
  
  图:游戏引擎的功能结构
  1.1、应用框架
  包含启动应用的必要代码,创建应用实例并实例化其余的子系统。当应用启动时,首先创建Framework类,负责创建与销毁状态机、图形引擎、物理引擎(如果需要的话)和音频引擎。框架要注意所有平台的特异性,包括处理任意的系统事件(比如关机与休眠)、管理资源的加载与卸载,这样其他代码就可以专注于游戏本身了。
  主循环
  框架会提供一个主循环,这是任何交互式程序的背后推动力。循环的每一次迭代中,程序都会检查并处理到来的事件,更新游戏逻辑,必要时还会绘制屏幕。
  
  图:主循环序列
  主循环的实现方式取决于所用的系统。对于基本的控制台应用来说,它可以与调用每一个函数的while循环一样简单:
  while (!finished) {
  handle_events();
  update();
  render();
  sleep(20);  //每次循环让代码休眠一段时间,使循环不会持续不断地占据cpu的全部时间
  }
  iphone的实例:
  void main(void) {
  OS_regsister_event_handler(myEventHandler);
  OS_regsister_update_function(myUpdate);
  OS_regsister_render_function(myRender);
  }
  1.2、游戏状态管理器
  主菜单、制作人员界面、帮助、游戏中……这些每一部分都是一种游戏状态。每种游戏状态都会负责处理用户输入、渲染界面并提供特定于该状态的应用逻辑。
  状态机
  游戏状态管理器是个状态机,这意味着它会跟踪当前的游戏状态。当应用启动时,状态机会创建基本的状态信息。接下来会继续创建每个状态所需的信息,并在应用离开某个状态时销毁临时信息。显而易见的一个状态是,玩家所处的界面(主菜单、游戏场景等)。但是一个敌方的人工智能代理,它可能处于“睡眠”、“攻击”、“死亡”等状态,那么,状态机也可以跟踪这些状态。
  那么,游戏状态管理器的合理架构是什么样子?
  状态机有多种实现方式,最基本的是简单的开关的语句:
  class StateManager {
  void main_loop() {
  switch(myState) {
  case STATE_01:
  state01_handle_event();
  state01_update();
  state01_render();
  break;
  case STATE_02:
  state02_handle_event();
  state02_update();
  state02_render(); break; case STATE_03: state03_handle_event(); state03_update(); state03_render(); break; } } }  如你所见,状态越多,代码块越大。此外,当进入或离开某个状态时,我们通常能够预测出需要执行的全部任务:初始化特定于状态的变量、加载新的资源(如图片)并释放前一个状态所使用的资源。在简单的switch语句中,我们需要将这些代码块添加到每个case中,以确保不会遗漏任何一步。对简单的情况来说,该框架没有问题,但是游戏状态管理器这样复杂的东西需要更好的解决方案。要实现状态机,最好的方式几乎就是使用函数指针了:
  class StateManager {
  //the function pointer:
  void (*m_stateHandleEventFPTR) (void);
  void (*m_stateUpdateFPTR) (void);
  void (*m_stateRenderFPTR) (void);
  void main_loop() {
  stateHandleEventFPTR();
  m_stateUpdateFPTR();
  m_stateRenderFPTR();
  }
  void change_state (void (*newHandleEventFPTR) (void),
  void (*newUpdateFPTR) (void),
  void (*newRenderFPTR) (void)) {
  m_stateHandleEventFPTR = newUpdateFPTR;
  m_stateUpdateFPTR = newUpdateFPTR;
  m_stateRenderFPTR = newRenderFPTR;
  }
  };
  现在的主循环变得非常小巧和简单,然而我们能处理很多游戏状态。但是该方案不能帮助我们初始化与释放状态。 把游戏状态当成对象属性时比较恰当的想法。接下来我们来看看oop的解决方案。
  首先创建一个类来代表游戏状态:
  class GameState {
  GameState(); //constructor
  virtual ~GameState(); //desructor
  virtual void Handle_Event();
  virtual void Update();
  virtual void Render();
  };
  接下来修改状态管理器以使用该类:
  class StateManager {
  GameState *m_state;
  void main_loop() {
  m_state->Handle_event();
  m_state->Update();
  m_state->Render();
  }
  void change_state(GameState *newState) {
  delete m_state;
  m_state = newState;
  }
  }
  1.3、图形引擎
  图形引擎负责处理可视化输出。这包含了绘制与玩家交互的图形用户接口(GUI)对象、动态的2D界面或3D模型并渲染背景与特效。
  纹理
  在2D图形中,平面图像是一个像素接一个像素地显示在屏幕上的,而3D图形中则会对一些三角形(也叫做网格)进行数学上的处理并生成平面图像,然后显示在屏幕上。
  一些概念:像素、纹理、图像、透明度
  纹理混合
  要想正确地排序网格以在3D图形中进行纹理混合,必须先绘制离相机最远的对象,最后绘制最近的对象。Iphone上的OpenGL ES实现能轻松地排序几何对象并获取正确的复合纹理。
  旋转     2D图形中大多数无需旋转而直接渲染为目标。在3D图形中,旋转的计算方式类似于灯光,是作为硬件渲染过程的一部分的。如你要开发的2D应用,需要大量的对象旋转,那么你可考虑使用3D引擎并且只建立正交相机以便场景看起来像是2D的。在iphone上着并非必要的。Iphone上的Quartz2D(2D Graphics API)已经内置了非常棒的旋转系统,因此旋转就变的很容易处理了。你可以按照计划继续使用纯2D来开发游戏。
  剪裁:图像的裁剪、纹理的裁剪;关于看板的概念,粒子系统就是数以百计的微小看板并以半随机的方式一起。
  动画
  动画的优化技术包括拣选、纹理排序、智能纹理文件、资源管理以及细节渲染。
  二维动画:精灵   通过连续的帧来实现,帧与帧之间仅在移动处有差别。为了保持这些帧的整体性,我们需要将他们放到相同的纹理中,这种纹理叫做精灵。
  三维动画:模型   3D中,只存储最有特点的关键帧,根据数学来重新创建其他的帧。一些概念:插值、骨骼动画或骨骼装配
  动画控制器:作用提取出诸如渲染哪个帧、渲染多长时间、之后替换成哪个新帧等低层次任务。他是连接游戏逻辑和与动画密切相关的图形引擎的黏合剂。
  粒子系统:与控制器类似,绘制一些非常零碎的元素。
  拣选:拣选就是从绘制路径中剔除掉不必要的对象。比如:封闭房间中的用户是看不到隔壁房间中的物体的,这样就不需要绘制那些物体了。
  纹理排序:每次将对象渲染到屏幕上时,图形硬件都需要将源纹理装载到局部内存中。这就是所谓的上下文切换的一部分。根据共享相同纹理的对象来对渲染过程进行排序会减少不必要的上下文切换次数,这会提高渲染速度。
  纹理文件:从一开始就规划好纹理组织有助于你以最佳的方式对纹理进行排序。假如你要绘制的各个层级都用到了所有的生物,那么将他们放到一个纹理中将是最优方式。然而如果第一个层级有吼猴和鼹鼠,但第二个层级只有林鼠和青蛙,那么前两个动物放到一个纹理中,将后两个动物放到另一个纹理中。
  资源管理:大多数游戏每次只会渲染整个图形内容的一小部分。将所有的纹理同时加载到内存中是非常低效的做法。游戏设计通常会指定在游戏的不同部分要显示哪些资源。通过加载必要的且移除不再使用的纹理,你可以最大限度地使用有限的内存。
  细节层级:特别用于3D图形,在内存中存放的是最简单的多个物体副本,图形引擎可以根据物体与相机之间的距离来决定使用哪个副本。
  物理引擎
  物理引擎是游戏引擎的一部分,用于处理距离、移动及与游戏物理学相关的内容。并非所有的游戏引擎都需要物理引擎,然而所有基于图像的游戏都在某些层次上具有物理学相关的代码。
  碰撞检测与碰撞决议:游戏代码中,检测是独立于决议的。游戏中的物体并不是都以同样的方式与其他物体发生碰撞的。此外,并非检测出来的所有冲突都会使用同样的决议方式。比如:
  1、玩家-外界碰撞:玩家偏移墙体一个位置
  2、动物-外界碰撞:动物偏移墙体,并且通知AI动物已经与墙体发生了碰撞,这样控制动物的逻辑就会使其改变方向。
  3、玩家-动物碰撞:不同动物会做出不同的反应,比如:眼睛猴跑开,狮子攻击玩家,小鸡对玩家置之不理,蚱蜢会发出嘎吱声……
  4、玩家-目标碰撞:目标不同于外界、玩家和动物场景,它没有图形化的表示,只是无形的触发区域,玩家进入会触发目标,目标通知游戏逻辑,将游戏状态变为“You Win!”。
  二维碰撞检测:总的来说归结为一下几种检测方式:矩形对矩形、点对矩形、圆对矩形、点对圆以及圆对圆(线段的检测也是必要的,但通常可以采取其他方式代替线段的检测)。
  由于每一秒可能会进行多次检测,因此提高检测的效率是刻不容缓的。要想做到这一点,可在对象发生碰撞前进行一系列简单的测试来证明两个对象之间是不可能发生碰撞的。
  Bool cd_rectangleToRectangle(Rect r1, Rect r2) {
  If (r1.x+r1.widthr2.x+r2.width) return FALSE;
  If (r1.y+r1.widthr2.y+r2.width) return FALSE;
  Return TRUE;
  }
  虽然这会导致对象发生碰撞时执行更多的代码,但大多数的对象之间是不会发生碰撞的。针对经常发生的情况(对象没有发生碰撞)进行优化更具效率。还要注意高速的碰撞检测。
  由于计算机的计算能力是有限的,很难进行详尽的物理模拟。基于这一点,游戏物理代码有这样一个传统:只提供恰到好处的精确度,玩家感到游戏能够正常运作就行。比如玩家跟动物之间的碰撞只需要检测玩家所处的矩形与动物所处的矩形边界就ok。
  三维碰撞检测:3D碰撞检测得需要一些数学知识,如线性代数等。可使用某些近似技术来降低计算量,同时还可以保持必要的精确度,使玩家感觉游戏还是真实的。在进行代价更高、更精确的测试前使用一系列代价更小的失败测试。还可以运用拣选,减少检测的物体数量,提高效率。
  碰撞决议:碰撞决议要考虑的第一件事是发生哪个层次的动作或者同时响应多个层次的动作。低层次动作可由物理代码进行决议,高层次动作是发送给游戏引擎中游戏逻辑部分的信号。在测试低层次碰撞决议代码的结果时,请特别注意细节信息。最终,由游戏设计者决定游戏玩法的正确性,而程序员的职责在于让这一切发生。
  音频引擎
  在正确的时间使用正确的声音能够极大提升游戏的价值,同时也不需要程序员付出太多的工作量。基本的音频特性包括加载与卸载声音样本、播放声音以及停止、暂停、继续和循环播放声音,音量的改变。需要3D声音(即位置声音)的游戏可使用iphone的OpenAL库。
  声音样本:iPhone支持AAC与MP3格式的高质量音频,同时支持PCM与IMA4格式的第采样声音及其他很多不常用的格式。
  多通道声音:iphone上所有的MP3与AAC样本只能播放其中一种格式。然而PCM与IMA4则可以同时播放多个(同时还可播放MP3或AAC中的一种)。
  音乐与SFX:背景音乐采用MP3或AAC,音效采用PCM与IMA4或其他格式,iphone至少支持32个采样通道,因此一般不需要考虑设定SFX优先级。
  玩家输入:对于iphone来说,触摸和陀螺仪事件。
  触摸事件:触摸开始、触摸移动、触摸结束和触摸取消。
  解析高层次事件:典型模式:1、根据操纵杆控制头像的移动,跳跃;2、玩家与游戏世界本身的交互,将玩家的触摸位置从屏幕坐标转换为完全坐标来确定玩家实际所触摸的物体。2d中倒转y轴并减去2D相机的偏移,3d中执行相机射线的碰撞检测。
  游戏逻辑:记录玩家的状态、负责AI代理、决定何时会接触到目标,通常会执行所有的游戏规则。
  高层次事件:尽可能确保游戏逻辑只处理高层次问题。它不关心玩家何时触摸屏幕,按照什么顺序绘制屏幕、两个矩形是否相交之类的问题。只关心玩家何时向前移动、何时创建新的游戏对象、何时销毁游戏对象以及当两个物体之间发生了“碰撞”时该如何处理。要保持这种概念上的分离,处理低层次概念的代码(比如玩家输入和物理引擎)应该创建高层次消息,然后向游戏逻辑代码发送消息,有后者进行处理。这有助于代码的分离与模块化,有助于调试。发送高层次消息的一种基本技术是发送一串有意义的字符串。更高效的方式是发送带有“类型”和“值”的对象。
  人工智能:游戏逻辑的另一个职责是管理AI代理。有两类游戏通常会使用AI系统:一类是匹配玩家与计算机对手,另一类则会创建包含了游戏世界中的半自治实体的系统。在这两种情况下,AI代理都会接受到输入并提供控制着游戏世界中物体动作的输出。第一类游戏中,AI称作专家系统。它模拟人类的动作,能理解游戏规则并使用各种策略向玩家发起挑战。第二类游戏中有很多AI代理,有些只提供某些有限的行为,有些很复杂,能按照组的方式来调整自己的行为。如果能够恰当地选择AI代理的输入,我们就可以模拟“意识”并提升其真实性。无论AI多么简单,通常我们都会使用状态机。
  透明的暂停与继续:选择要保存的数据,使用紧凑、一致的格式将其写到磁盘上,这种结构化数据的保存叫做序列化。
  基于帧与基于时间的逻辑:基于帧的逻辑会根据每个帧的变化更新游戏中的物体。基于时间的逻辑就有些复杂了,但与游戏实际状态更紧密,它根据发生的时间更新游戏中的物体。注意这两者的区别,其中第二种做法更好。
  游戏逻辑的组织:游戏逻辑的核心功能在于管理游戏状态的规则与过程。

猜你喜欢

转载自ttl04ttl.iteye.com/blog/1571572
今日推荐