专注于互联网--专注于架构

最新标签
网站地图
文章索引
Rss订阅

首页 »游戏开发 » ogre引擎:高层游戏引擎——基于OGRE所实现的高层游戏引擎框架 »正文

ogre引擎:高层游戏引擎——基于OGRE所实现的高层游戏引擎框架

来源: 发布时间:星期四, 2009年2月12日 浏览:300次 评论:0


  这是意念自己毕业论文个具体实战的中意念主要负责是物件和GUI的外其他游戏系统意念才学疏陋望众位前辈不吝赐教由于代码质量不高、环境很难于配置、资源包过大等问题意念暂先不提供代码和未来有时间时候组织下这些曾经代码再向外发布

  文过 3月也有些新想法以后会慢慢跟大家聊欢迎拍砖哦^_^



关键字和术语:

 游戏、 游戏引擎 、高层引擎、规则 、场景、物件、Terrain(地形)、解释器 、Application Framework(应用框架)、GUI(Graphics User Interface 图形用户界面)、Manager(在本文中特指管理器)、触发器、
 设计模式(Design Patterns)、
 Singleton(单件模式种设计模式使某个类在某个生存期内有且只有份例子而且可以在任何时候得到这份例子)、
 Adapter(适配器模式种设计模式个类接口转换成客户希望另外个接口)、
 Factory(工厂模式种设计模式提供个创建系列相关或相互依赖对象接口而无需指定他们具体类)、
 Thanatos(死本能代表恨和破坏力量死本能投射于外则表现为求杀希望表现为侵犯和仇恨根源;如死本能外投受挫则为“自杀倾向”包括自我谴责自我惩罚对敌手嫉妒和对权威反抗等)、
 OGRE(Object-Oriented Graphics Rendering Engine)面向对象图形渲染引擎

Abstract:
    The abstraction of game engine is an important question in game programming, and the kernel of the question is “How could we give the game engine more adaptability?” In the paper we attempt to deduce the form which our game engine must be from our daily-lives. With the help of OGRE, I completed the game engine which has the form that we have just deduced.

    The major questions of this paper are: First, why we make game engine? Second, how we make a game engine? The first question was answered in Part1, while the second in Part3. And the Preview gives us a theoretic conclusion to the second question. At the end of this paper, we used the game engine which has just been completed to make a simple game.

    The  idea of the paper is to take game engine as a combination of the high-level game engine and the low-level game engine. We use the high-level game engine to support game logic, and low-level game engine to support device and platform API.

摘要:

  游戏引擎和框架抽象直是游戏制作中个关键问题其核心问题是如何令抽象好引擎具有更好适应性本文尝试使用演绎法从我们所生活世界推导出了高层引擎为了适应游戏需要所需要保持形态并通过实做利用OGRE完成了满足这个形态个简单高层引擎

  本文关键问题有两个:是为什么要有游戏引擎 2是我们怎样来构架个游戏引擎在第部分和第 3部分我们分别回答了这个问题绪论则作为对第 2个问题所进行演绎和推导在本文最后我们利用完成游戏引擎制作了个简单游戏

  游戏引擎应分为为高层逻辑提供支持和为底层功能提供封装两个部分这是本文中心论点

 
目录

绪论 游戏形态和其所决定形态

电脑游戏本质是模拟现实

被电子竞技现实形态所决定形态

部分 游戏引擎技术介绍

引擎概述

高层引擎概述

第 2部分 OGRE图形引擎基本构成

第 3部分 实作:基于OGRE图形引擎游戏框架

场景系统:OGRE场景体系分离和重新合成

场景:游戏舞台

规则:脚本系统

零件组装:具体游戏层构建过程

第 4部分 结论和展望

附录

Terrain Example

参考

Preview 游戏形态和其所决定形态
电脑游戏本质是模拟现实
“游戏是先于人类许多学者在关注游戏时候发现在自然界哺乳类动物里存在着大量游戏行为……

“尽管游戏历史是悠远久长但人类把它当作种理论研究对象却是在近代才开始德国诗人和剧作家席勒在研究艺术起源问题上曾以‘艺术起源于游戏’大胆说而语惊 4海他认为人类在现实生活中要受到精神和物质双重束缚在这两种束缚中常常失去了理想和自由人们就设法用剩余精神创造个自由世界这个自由世界就是游戏

——游戏的王·游戏文明论
 

  人类对于游戏研究起源于近代有关游戏起源问题自近代而来就有了多种理论:例如席勒“本能论”斯宾塞“剩余能量论”谷鲁斯“练习理论”弗洛伊德“宣泄理论”等等
  然而什么是游戏?游戏本质是什么呢?我们先看看下面几种游戏形态看能否获得些启发
  棋牌似乎是所能列举出人类最早纯智力游戏形态;而当游戏规则开始和体力结合时就诞生了诸多体育项目;自上世纪年代的后伴随着芯片处理能力提高又产生了电子游戏这种新游戏形态抛开这么多游戏存在形态不说精神是物质映射游戏这种人类精神产物所反映是如何客观存在呢?


  象棋、军旗和围棋是从人类战争中找到了灵感战争是人类所能接触和理解到事物
按此在新窗口浏览图片500)this.width=500\" src=/upload/article/a2005111022173353.jpg>


图0-2 象棋很可能来自于人类对战争理解和认识

 按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022175147.jpg>

现代战略战术类电脑游戏规则大多始祖于近代出现军事推演这个军事推演可以准确说是从战争中找到灵感

 

图0-3 左:文明截图    右:1894年清政府派人参加美国军方军事推演时照片

图0-4 左:地球帝国截图    右:1910年美国海军军事学院场海战推演 

图0-5 左:帝国时代2截图        右:近代图版战争游戏包装盒

 

最早电子游戏是1962年在PDP-1型电子计算机上个名叫斯蒂夫·拉塞尔大学生开发出来Space War单从名字我们就可以看出这个游戏所立足是人类对于空间幻想和对于战争体会

 按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022183413.jpg>

图0-6 左:在这台电脑上诞生了人类历史上第款电子游戏  右:利用计算机绘制太空幻想图 

图0-7 左:战术FPS游戏CS  右:提出了Thanatos和Eros奥地利心理学家弗洛伊德

图0-8 左:传统图版RPG游戏人物属性表格  右:玩图版RPG能激发玩者丰富想象力 

图0-9 左:某网络RPG游戏场景截图  右:正在玩图版RPG游戏玩者右下为裁判 

  而被冠以“暴力”等罪名FPS尤其是万人瞩目Quake和HalfLe似乎也是为了满足弗洛伊德所说人类对于Thanatos本能追求其表现形态往往来自于真实杀戮场面这些杀戮场面在些网站WebSite、文学、新闻和电视剧中比比皆是 

  下面来看看另种游戏类型——RPG游戏欧美RPG始祖是托尔金名著指环王作为部文学作品指环王似乎是从人类各个集团政经军事交互中寻找到灵感同时在这的中体现出了个幻想世界和幻想世界观此后发展而成龙和地下城规则更是继承和发扬了这个体系刻画了个世界各个集团的间政治、经济、哲学和战争体系幻想事物也作为人类所能接触到事物成为了游戏开发者赖以开发游戏灵感龙和地下城远在电脑游戏出现的前就已经被做成了图版游戏后来电脑游戏介入了这个规则体系种崭新面貌重现着以往图版游戏中刻板教条和变化无穷世界

  由上面叙述我们可以看到游戏开发都离不开“人类所能接触到事物”这中间包括人类所能接触到客观世界和精神(艺术、幻想)世界电脑的王·游戏文明论中说到:“电脑游戏本质就是模拟现实”这也是图灵所揭示计算机本质特征:“模拟人类思维”


被电子竞技现实形态所决定形态

  游戏既然是对客观世界认识和理解那么就可以站在最为抽象角度来分解这个认识和理解

  是远古以来就业已存在世界:山水、森林……诸如此类他们有个共同特点是很少或几乎不会人类精神活动而发生变化基本上可以认为在整个游戏期间很少或没有变化部分我们用个词语来描绘就是地图或地形般在 3维中都叫地形 2维中都叫地图

   2是这个世界居住者以及他们所使用各种工具:人、动物、汽车……他们有个共同特点是会发生强烈相互影响相互制约关系由于变动明显部分物体经常会发生变动部分我们也用个词语来描绘就是物件在另外分类中往往也把地图和地形当作种物件但在大部分游戏中这两者属性和思路方法都区别因此我们在此将地图独立出来考虑

  第 2世界组合就成了我们肉体可以感知到物质世界而这个世界在我们心灵中映象就叫做场景换句话说广义场景就是地形和地形的上物件集合个简单角度来考虑我们可以把场景看作是舞台布景舞台背景等等就是地形而舞台上演员和些杂物等等就是物件

  第 3世界是种比较难于感知世界它肉眼无法看见但却在很长时间期限内处于相对静止状态规律集合例如 “生命体失血过多会死亡”、“在其他条件相同前提下有效率人比没效率人在单位时间内收益要大”等等等等部分很大可能会在暗中影响到“第第 2部分世界”我们用个词语来描述它就是规则或者规律部分还有个重要内容就是人类精神领域活动包括思维世界和情感世界我们可以把这种活动认为成种特殊规则和规律

  游戏作为种交互娱乐手段还有层层面就是交互交互中首当其冲被大家接受是通过这个人切可能方式来向游戏系统输入来从游戏系统接收输出因此I/O控制是个游戏系统所必须系统例如我们下象棋时我们手可认为是游戏系统输入设备可见棋盘和棋子从游戏系统向我们发送输出可认为是游戏系统输出设备

  另方面在电脑游戏中I/O系统除了键盘鼠标显示器这些基本设备的外还有个交互重要组分就是GUI界面对于现在越来越复杂游戏系统个仅通过鼠标和键盘靠输入命令来维持I/O是很难想象因此GUI用它强大功能弥补了标准I/O设备不足GUI系统重要性因此在这次我们也必须把它考虑在内

  通过上面论述我们可以得出结论是:个游戏可分解为地图、物件、规则、I/O控制和GUI集合作为棋牌类游戏可以考虑的为地图、物件、I/O和GUI部分退化而规则相对进化游戏古代没有那样强大系统来完美体现地图、物件因此规则就相对强大得多近代出现军事推演已经是种有完整地图、物件和规则游戏系统了而作为GUI似乎只有电子游戏才有这样东西它是为了方便交互而产生



  大部分游戏引擎中会把第部分映射为地形(地图)系统来处理对其支持至少有:地图文件读取、导出、渲染等

  而第 2部分各个区别游戏实现也不尽相同般引擎对物件支持除了渲染外至少会提供如下支持:物件碰撞检测、模型编辑等

  第 3部分这有很大部分是受游戏类型限制而且即便是在相同游戏类型里面由于个人划分不也会出现区别结果比较基本技术包括状态机等

  第 4部分GUI和控制则有很多参考MFC等都是很好参考因此这般不是经常会被拿来讨论技术

  本文所主要讨论就是利用个现有底层引擎来构架高层引擎并借的讨论高层引擎构架般思路


 

部分 游戏引擎技术介绍
部分所需所有图片
按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022185616.jpg>
引擎概述

  曾经有段时期游戏开发者关心只是如何尽量多地开发出新游戏并把它们推销给玩家尽管那时游戏大多简单粗糙但每款游戏平均开发周期也要达到8到10个月以上方面是由于技术原因方面则是几乎每款游戏都要从头编写代码造成了大量重复劳动渐渐地些有经验开发者摸索出了条偷懒思路方法他们借用上款类似题材游戏中部分代码作为新游戏基本框架以节省开发时间和开发费用于是就慢慢产生了游戏引擎人对于游戏引擎概念是逐步深入理解这个过程类似于其他技术进步过程——毕竟游戏引擎也是这个理解所立足就是对“封装性”理解实际上在引擎这个概念下面更多是每个人对引擎各自区别理解:游戏引擎只是个说法至今为止没有个公认定义

  近几年部分初学者所理解引擎是“对底层功能简单封装”这个底层功能包括平台API、渲染API、音频API、流媒体API等这样引擎往往是种C语言时代思路其划分是来自于各个区别部分的间“功能”关系而非“逻辑”关系经典概念包括:渲染核心、内存管理、骨骼动画、帧动画、文件操作、物理库、网络库等等这个在广为传诵网文游戏引擎剖析(参考4)里面有最为明确体系划分:

  1、“渲染和构造3D世界3D环境光照和纹理”渲染永远是引擎最具有技术含量部分就不说那动辄千百块钱图形卡了单是图形渲染相关技术进步速率就已经足以让人瞠目结舌了“什么是渲染器为什么它又这么重要呢?好吧如果没有它你将什么也看不到它让游戏场景可视化让玩家/观众可以看见场景从而让玩家能够根据屏幕上所看到东西作出适当决断”渲染所需主要底层功能就是来支持OpenGL和DirectX最新技术由于这些技术不断更改导致渲染器更新换代也相当明显好在OGRE本身就是个很巧妙渲染器它为我们隐藏了很多渲染器复杂性让我们可以用近乎自然语言方式来进行图形处理

  2、“内存使用特效和API”图形研究到高层次就不得不考虑到芯片些特性:例如显存和内存管理、Shader和其它重要参数这也是属于引擎必须染指内容

  3、“模型和动画细节级别LOD”游戏引擎应该支持常见模型文件格式并很好地渲染他们如果游戏引擎需要用到自己数据格式那么它需要为几个主要模型文件格式做导出插件以满足美工需要

  4、“物理运动效果”物理系统可以让游戏尽可能地逼真“作为游戏开发者来说无论我们做什么我们需要能够检测墙壁检测地板在世界中处理和其他对象碰撞这些是现代游戏引擎必备”先进物理系统如ODE可以在保证效率前提下精确处理物理和运动学理论和公式其中甚至包括流体力学

  5、“声音系统音频APIs”耳朵也是人个重要感觉和信息获得器官点应该很好理解

  6、“网络和连线游戏环境”网络游戏必备如今大多数真正有长久生命力游戏都至少有些连线成分“最纯粹单人游戏容易玩也许两次或者甚至 3次如果它是非常好游戏旦游戏结束就被束的高阁了如果你想要有任何长久生命力那么多人连线游戏就是形势核心所在

  7、“脚本系统”你可以把游戏脚本认为是电影脚本它们两者实质上是相同

  8、“人工智能和导航”

  当按照这个思路建立了自己引擎后我们引擎只是个功能引擎它没有任何逻辑关系包括场景、地图、物件、规则等系列游戏逻辑所直接相关东西它都没法直接提供这个时候我们所具有引擎大约是如同下图所示:
 

图1-1 基本底层引擎核心结构
 

  种可怕平铺性结构互相的间没有关联或很少关联也就是说它基本什么逻辑都没有实现个游戏你可以重用这些底层功能除此的外你需要重新写所有逻辑即便两个游戏在基本逻辑上基本相同国外游戏引擎已经可以让你脱离代码只用脚本和编辑器就可以做游戏了(这种开发手段叫做MOD)这种简单平铺结构没有纵深根本无法架起这样栋充斥了逻辑大楼!


高层引擎概述

  我们拿2D地图来做个例子在这样引擎思路下地图只是诸多图元拼接、Blt(发音Blit位图位块传输)和互相遮挡这个思路确实反映出来了地图本质但是对于游戏逻辑来说它太细了游戏逻辑是不需要管你地图图元如何拼接、Blt和遮挡下图左就是针对这种设计思路而下图右则是提供了高层引擎设计思路通过对比可以发现右边设计思路更符合OO封装原则而左边主要是比较古老过程式填鸭
 

图1-2 左边是直接在应用里硬编码底层功能右边是在应用和底层引擎的间建立个抽象层有这个抽象层划分和承担游戏基本逻辑在OO大行其道今天你会用哪种思路方法?
 

  而在这里我们理解引擎除了功能元素的外同时包括些逻辑意义部分即部分开发者交流中所说“游戏层引擎”或“高层引擎”为何会存在这部分引擎呢?答案是为了方便我们表达游戏上层逻辑底层游戏引擎所立足都是平台API是和API严格相关就是为了要让外界看不见API专心做外界逻辑部分但底层引擎只完成了个目就是通过封装API来完成定功能封装好API是否就表明定适应上层逻辑要求呢?这根本不可能它不是为了这个目而存在例如骨骼动画和上层逻辑有什么关系呢?因此人们又提出了高层引擎概念这就回答了刚刚问题骨骼动画是应当包含在物件逻辑内部实现对外部应该是透明如果游戏逻辑需要细化到“谁谁谁按照骨骼动作‘Walk2’来行走”那就太麻烦了这种情况下比较普遍做法是我们由来实现个物件然后为其设置种状态叫做STATE_WALK2在物件自己逻辑里面当发现物件是处于这种状态时候就开始引发“Walk2”动作这样最后游戏逻辑只用简化到说“那个谁向前方走步”就可以了实际处理是引擎层获取到了这个消息以后向物件“谁”发送个TranslateState(“走”)消息而物件“谁”获得这个消息后根据当前状态自动进行状态机切换对于逻辑开发者来说切都是封装好透明他们只需要知道“当我说‘A向前走’A就会向前走”就可以了这样引擎就不再简简单单是功能平铺平房而是具有定逻辑保障大厦了STATE_WALK2到Walk2对应关系在区别游戏引擎里面可以通过区别方式实现最初也是最简单思路方法是硬编码(Hard-Code)这种思路方法速度快然而牺牲了维护性会给测试带来很大麻烦现在大部分游戏引擎可以通过配置文件甚至是编辑器来解决此问题以及和此类似问题这种数据驱动方式使编码逻辑更加简单同时也使设计者和导演工作更加方便



  下图是我们使用款外国引擎编辑器时场面在这个编辑器里面既有物件编辑器也有场景编辑器同时也包括脚本——这个编辑器里用它来实现我们所说规则——编辑器:
 

图1-4 看着很像3DMax款游戏编辑器中国目前大部分游戏
工作室还没有自己实力开发这种高度集成编辑器
 

  把话题引回来对比前面我们得出结论个游戏实际上就是在做场景(地图+物件)、规则系统、GUI系统和I/O控制系统那么我们该如何做呢?构建个过于集中把所有功能都实现了高层系统只会降低高层引擎可适应性因此属于高层引擎更多是对它们提供支持这些支持包括:基本数据结构和组织方式(例如物件链表及查询操作、特殊文件数据)、工具集等通过这存在最高层逻辑只需要写:在场景中放置几只飞鸟按照Sin路线飞行至于飞鸟飞行中是如何振翅如何偏航这是在物件系统具体物件类——这里是飞鸟——里可以决定为了最终产品逻辑需要我们迫不及待需要个“高层游戏引擎”这是源自于个很重要思想同时也是软件Software工程基础思想:“软件Software产生于需求”底层引擎层次划分完全来自于平台和API限制毕竟我们要做游戏必须跟某个平台相关而高层次引擎结构则是跟需要达到严格相关这是它存在动机

  实际上现在大部分引擎都是或多或少地包括了高层引擎部分然而高层引擎划分却并不容易大部分引擎所面向还是FPS这种游戏类型款普遍适应引擎是难上加难区别游戏所需要高层不

  我们这篇文章基本目就是试验当拥有个现有底层引擎时候如何构建个高层引擎以及如何让这个高层引擎具有更强适应性

现在我们具有引擎构造大抵如下:

按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022193026.jpg>

 

图1-4 按照现在划分诞生高层引擎层基本框架 

第 2部分 OGRE图形引擎基本构成
第 2部分所需所有图片

按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022200439.jpg>

  OGRE(Object-oriented Graphics Rendering Engine面向对象图形渲染引擎)是国际上比较知名开源图形渲染引擎OGRE是用C开发面向对象且使用灵活3D引擎是让开发者能更方便和直接地开发基于3D硬件设备应用或游戏引擎中类库对更底层系统库(如:Direct3D和OpenGL)全部使用细节进行了抽象并提供了基于现实世界对象接口和其它类

  OGRE系统主要包括:Render系统和Render插件、Material系统和Material脚本、Entity(主要是物件系统)、GUI系统和Overlay脚本、Texture和图片解码器、Archive系统和文件解码器、Scene插件(主要是地形系统)、粒子系统、日志、Dll动态导入和插件系统等等而最后所有系统全部归个总管管理这个总管就是Ogre::Root

下图是Root关联关系 Root是整个OGRE核心部分它关联着其他所有组件并把这些组件封装其中

图2-2 OGRE核心部分框图(引用自OGRE开发框图)
图2-2是整个OGRE核心成分框图下面我们引用Mage小组Ogre使用指南里对这个框图描述:


Root:整个Ogre系统入口点和管理器它必须第个被创建最后个被消毁通过Root对象你可以配置系统还可以获得系统内其它对象
Render:3D API抽象层它负责设置所有渲染属性3D API执行渲染操作
SceneManager:场景管理器它负责组织组织场景包括场景中Material、Light、Movable Object(Entity)和场景本身
Material:定义场景中几何体表面属性
Entity:场景中可运动物体
SceneNode:代表位置和方向Attach到SceneNode上Entity可以继承其位置和方向场景中SceneNode以树形式来组织
Camera:场景中视点


  使用OGRE很简单OGRE提供了自己Application Framework如果有兴趣可以参考下附录里面段使用OGRE Application Framework标准代码:(举例来自OGRE自带地形Demo:Terrain)

  但细细分起来使用Application Framework开发需要写代码主要还是集中在下面 3个方面:化、处理输入以及运行时帧循环大部分时候我们所需要做主要是化和输入处理而对于帧循环几乎不必要改动

  既然Application Framework本身封装就这么好为什么不能直接使用Application Framework来做游戏呢?来看看Application Framework里面都是些什么吧:

图2-3 Ogre Application Framework 工程

  我们从中可以看到高层封装包括有:些物件类(AppBox、AppBall等)、物件碰撞检测支持(ODE个国际知名开源物理引擎)、以及个简单到不能再简单RefAppWorld(这里面World类似于我们前面讨论场景系统)这种封装很难以满足我们要求不过看来OGRE作者似乎也察觉到了OGRE本身场景系统不能满足需要因此在Application Framework中又重新构建了我们意义上场景系统这种场景系统对于单个场景演示和Demo是够用了但是在游戏普遍要求多场景、甚至是大量场景前面这种构架似乎又缺乏说服力而且把ODE和OGRE放在这层次硬性结合实际效果也并不好经常出现碰撞检测导致穿墙、撞飞尴尬场面曾经我们准备在其基础的上建立自己游戏框架最后发现越来越陷入到OGRE为我们框死条框的中毕竟OGRE是为了OGRE开发者而开发不是为了游戏而开发更不是为了我们而开发

  现在我们准备彻底抛弃这个构架转而制作自己新构架来亲手实战前面纯理论推导“高层引擎”当然我们用思路也并不超前同样是Application Framework中已经利用过“场景=地形+物件”思路但是我们构架需要考虑到更多情况我们所要做游戏并不只是“第第 2世界”(场景)同时它还包括“第 3世界”(规则)点是OGRE没有重点支持



 

第 3部分 实作:基于OGRE图形引擎游戏框架
第 3部分所有图片
按此在新窗口浏览图片500)this.width=500\" src=/upload/article/2005111022203891.jpg>


场景系统:OGRE场景体系分离和重新合成
  首先我们发现OGRE场景系统似乎现在和我们所理解场景系统有点不合OGRE是用种渲染方面理解来考虑场景而作为个游戏似乎需要考虑得更远“游戏需要渲染但游戏不仅仅是渲染”

  要融入OGRE图形系统需要结构和习惯调整而且所写所有代码都需要受限于OGRE以至于我们依照OGRE来写高层游戏引擎很有可能会成为离开了OGRE就什么都做不了东西而且即使我们不离开OGRE框架那么当OGRE以后翻新版本、做大体系调整时候我们所做高层游戏引擎也需要作极大调整这当然不是我们想看到高层引擎是立足于需求OGRE底层改动了只要需求没有改动就应该保证高层引擎尽量不要改动这首先是软件Software工程原则

  如何办呢?我们先从表面上来推导下OGRE引擎和我们前面层次化引擎体系接合关系

  在现有接合下我们有很多框架安全方面问题都没有考虑到如果OGRE中某个组件迫使我们更改上层架构那将是危险事情上层架构即游戏逻辑不是为了OGRE而存在应该把这些事情都封装到底层来做我们最希望是让最终使用这个框架人看不到点跟OGRE相关东西他只需要考虑他自己东西:游戏逻辑就是为A送B封情书会如何样以及D被C车撞了下会如何样诸如此类问题如果在这最高层还迫使使用者考虑OGRE——把C和D包围盒进行检测——那么只能说我们没有划分好、搭建好我们引擎换句直接话说我们实作以失败告终了这是我们对自己所做框架最起码要求只有当高层引擎留不下底层引擎点痕迹我们最上层需求和最底层平台才是被高层引擎完全隔绝也就是说无论底层平台如何变更具体游戏逻辑是不需要改动需要作出改动只是高层引擎如图:


  如图理论上高层引擎将底层和应用层完全隔离对底层修改将牵动高层修改但不会牵动应用层修改这对于引擎是很关键当引擎改动时候如果使用这个引擎所有应用层都需要修改那么不知道全世界会有多少工作室、甚至是公司会发出鬼哭狼嚎叫声因此模块化、层次化思路早就是软件Software工程界个共识

  在我们现有划分下高层引擎需要完成下面工作:

图3-2 基本高层引擎结构

  我们把OGRE本身提供功能列举全部提供用黑色块部分提供用浅绿色块

图3-3 基本高层引擎结构和OGRE切和关系

  在这个划分中我所负责主要是地形系统、地形、场景和规则系统而GUI和I/O控制系统、物件和物件系统、应用主要由另位同学负责在这里我主要也只讲述场景、地形、地形系统和规则系统

场景:游戏舞台

  场景中舞台是地形系统所支持而赋予场景生机活力则是物件系统物件系统和场景系统间组织是有所联系例如超大场景管理器和普通室外场景管理器所要求物件系统数据结构也是不前者由于可能存储海量物件因此可能对物件做分区处理;而后者则区别因此可能会用统张表(Map)或者哈希表(HashMap)来管理物件和地形系统相关性可以在场景这层次来解决当场景调入是这样地形系统它就需要调入合适物件系统什么样物件系统最适配于某某地形系统?这是个仁者见仁智者见智问题没有唯答案物件系统最耗费效率无非两点:自身逻辑和搜索算法物件系统每帧都会走自己逻辑而且外界经常会从物件数据结构里索引某个具体物件甚至是帧索引十几遍物件这两者对于物件系统数据结构都有很高要求

  OGRE对于地形支持比较庞大实际上OGRE本身是没有具体地形系统但我们可以通过写Plugin为原有OGRE系统增添帮助现有几个Plugin包括:BSP管理器(plugin_BspSceneManager)、超大场景管理器(plugin_NatureSceneManager)、和我们这次用来作试验 4叉树室外场景管理器(plugin_OctreeSceneManager)OGRE由于抽象度很高因此在高层代码层面上几乎察觉不到各个的间区别这当然方便了我们抽象只是OGRE地形系统是集成在Root里面没法随便打破这样我们所提供地形系统相当于个“壳”只是重新封装了OGRE场景管理功能这就是设计模式中Adapter(适配器)模式

  因此这次所写出Terrain就相当于OGRE::SceneManager的上层Adapter基本上没有什么新功能这也是在图2-3中说这个系统已经是OGRE完全处理原因

  Scene个功能是用来管理Terrain般发生在多Terrain情况下需要对诸多Terrain资源统管理Scene掌管Terrain生杀大权正如舞台形态决定了布景如何摆放实际上OGRE::SceneManager中也有部分功能是用来做这些事情由于需要功能比较少因此Scene掌握了下面这些基本思路方法:包括载入Terrain、销毁Terrain和更换Terrain等

  利用Adapter模式将Terrain上升为个接口类以后无论OGRE内部对于SceneManager变动有多大Terrain由于是接口只需要更改接口实现就可以了而Scene则成为了这部分管理类和底层OGRE在逻辑上无关至此我们Scene-Terrain结构简单场景系统就算是构架完毕现有部分类和接口如下:

  有关Scene个重要部分物件系统由另位同学向大家细细介绍说明这里只是稍稍提些基本物件设计思路前面说过物件是个比较难于划分体系物件属性比较多而且无论何种属性都可以成体系例如“生物体还是非生物体”、“生命期长还是短”等等举个例子来说对于般生命期比较长物件来说可以按照Map或者Vector来存储这样由于不会经常从数据结构中调入调出而且查询算法又相对要快使得这种数据结构显得比较有优势;但是生命期非常短物件就区别了例如子弹碰到墙上溅出火花火花存在时间往往在1/10秒而且同时可能出现很多火花如果用Vector或者Map那将是件非常恐怖事情且不说疯狂调入调出会有多大时间损耗本身火花根本就没必要对其进行查询操作Map和Vector相对于List优势就此不复因此对于这种生命期非常短物件用List就比用Map等数据结构优势要明显这个划分仅仅是来自于“生命期长短”这个属性而物件所具有属性何止着种呢?!即便是都按照Map或者MultiMap存储也有按物件名称存储、按物件属性存储等等很多种存储方式如何抽象个适用于游戏物件系统这是很多人心目中共同问题有关这个系统也有很多现行思路方法但是很难统毕竟物件规则体系太复杂了



规则:脚本系统

  规则系统虽然并不难划分但却是个比较难于把握系统如前所述规则系统是个肉体所无法感觉到世界这样只能用意识去感知这个世界就充满了诸多变数实际上规则系统并不是个成形系统而是所有“游戏逻辑”统称这些逻辑或自成系统或分布在其它系统内构成了个游戏严密而严谨逻辑体系

  从功能上理解这个系统是个普遍思路方法无论规则是多么多变最终我们需要关注那些总是会对感官世界产生影响这个影响就是这些规则功能但这种划分办法并非是规则系统构建全部而仅仅是种方向用白话文说就是:“无论你怎样划分这个系统最后只要完成这个功能就可以了

  在做引擎时候很少有人会知道这个引擎会用到哪里更不用说引擎应该满足哪些逻辑和哪些功能了因此这些功能大部分是最后开发者拿到了引擎开始写游戏时候才会考虑到对于引擎开发人员来说它无形、充满变数因此这是规则系统难于把握重要原因大部分游戏逻辑都是在引擎的外写而且中国很多游戏DEMO逻辑都是靠硬编码实现

  但是这并不表明引擎开发人员就无事可做你要对规则系统予以底层支持有些东西是缺不了这主要包括:消息系统、游戏脚本、寻路算法和状态机等等其中大部分是人工智能标志性研究课题这中间我认为最为重要是脚本系统和消息系统对于国外游戏引擎来说强大脚本系统早已成为了个必备利器而国内开发者还是处于脚本系统教材和资料都很难找阶段

  这里我们引擎将为规则系统提供套脚本支持在后面组装中你将会看到这个脚本是如何作为规则应用在游戏中对于规则系统也有其他很多种支持例如状态机等等好在各个逻辑体系的间是相对独立因此以后可以陆续增加

  脚本分为编译型脚本和解释型教本对于外国很多游戏引擎所提供都是编译型脚本分析器我这里所提供套解释型脚本分析器开发个编译型分析器往往所需时间过长; 2是对于我们DEMO解释型已经足够用了而且速度不慢

  脚本分析器提供基本功能就是分析脚本这就牵扯到了编译原理词法分析和语法分析在读入行并对本行文本中注释和空格成分予以消除后剩下部分转入词法分析步被断为个个独立有意义单词最后通过语法分析来解释这些单词意义这里我们语法比较简单个独立语句都类如下面语句:

    Index:
    Funciton( param1 , “ param 2” );

个语句是标号语句主要用于跳转例如Goto(Index)就可以从任何个位置跳转到Index因此在我们语法分析中当发现了单词“:”的前有独立存在单词时就把这个独立单词存储到张Index表里面以备跳转而如果发现了“(”则把的前独立单词作为Function个Function唯对应段C++从“(”到“)”的间部分按“”断开做多个Param不带””看作是常数参数被””所包裹串参数这些参数用做执行Function时些必须数据语法分析关键就是Function和C代码对应匹配这里我们可以使用来处理:

strCmd = ParseLine //分析
(strCmd  “Function”)
{
    doFunction( getIntParam1 , getStrParam2 );
}

使用可读性最好但是比较慢String比较会比常数比较要慢得多因此也有思路方法就是通过把脚本映射为唯数字再通过数字来做比较

例如我们建立如下对应关系:Function : 101并把这个对应关系存储到脚本解释器里面这样当解释器发现用作单词Function时候就会把他翻译为101然后再进行匹配:

nCmd = ParseLine //分析注意返回值区别了

switch(nCmd)
{
     101:
    {
        doFunction( getIntParam1 , getStrParam2 );
    }
}

这样就比原来快了很多只是麻烦步就是需要个个为脚本预先对应上这些数字这些实际上都是在解释器Run里面运行在需要地方只需要Run(脚本文件名)Run就会自己去检测区别脚本名称然后实现各自功能

  脚本分析器还需要有个功能就是“功能注册”开发引擎时候我们几乎没有办法写出具体脚本功能做游戏人拿到引擎后需要写些具体脚本功能这时候需要提供给他们个注册机制来把脚本名称和功能对应起来这里我们提供注册机制就是这个switch(nCmd)如果添加了什么新脚本就需要为对应编号增添新实现例如我们除了Function以外又添加了个新Walkto对应编号102文法是Walkto(param1 , param2 , param3)那么我们需要做就是:

switch(nCmd)
{
     101: // Function
    {
        doFunction( getIntParam1 , getStrParam2 );
    }
     102: // Walkto
    {
        WalkTo( getIntParam1 , getIntParam2 , getIntParam3 );
    }
}

现在注册机由于是隶属于引擎代码层面次添加新脚本都会引起引擎更改和变动前面我们说了应该尽量避免引擎变动如何解决这个问题呢?有关脚本注册机更好实现就是通过C多态这样我们可以把Command实现为个抽象类各个具体Commond继承的并实现相应接口例如:

 Command{ virtual void do = 0; }; //抽象类

 Function : public Command{ //具体个Command



    virtual void do
    {
        doFunction( getIntParam1 , getStrParam2 );
    }
};

但这些新加类如何注册到解释器里面呢?在做解释器时候我不可能知道会加哪些类进来啊!有办法设计模式工厂模式(Factory)给我们提供了明确行动指南我们可以另外实现套Factory并指明Factory类型:

 CommandFactory{virtual  getType = 0; virtual Command* create = 0;};

 FunctionFactory : public CommandFactory{
    virtual  getType {  “Function”; }

    virtual void create  Function;} //用Factory生成具体Command

};

最后我们需要在Run里面通过std::Map注册Factory把Type和具体Factory关联起来这里我们就通过std::Map把“Function”和FunctionFactory关联起来最后在进行匹配时候我们只需要:(伪代码)

//分析得到strCmd

strCmd = ParseLine;

//从map里寻找对应strCmdFactory假设strCmd是”Function”it->second里面就会存放FunctionFactory

iterator it = Map.find(strCmd);

(it != Map.end )
{
    // 通过Factory生成Command对象
    Command* Cmd = it->second->create;
    // 执行Command对象do思路方法
    Cmd->do( );
    // 销毁Command对象
    Delete(Cmd);
}

OK现在无论如何往里面加Factory和具体Command这段属于引擎层解释器代码都不需要改动了!Great我们把这套流程画成图:


图3-6 利用工厂模式解决解释器匹配图会发生改变用黑色标出可见现在这套引擎几乎不会发生变动以后需要在别地方写就可以了健壮性相当高!


好了到这里脚本解释器本身就基本解决了剩下工作就是不断根据需要注册新脚本功能了

脚本怎样最终应用于规则呢?在我们现有解释器下谁想用脚本就保留脚本文件名称然后Cscript::Run( const & filename )就可以完成任务这样我们需要为需要走脚本个类都挂接个成员:std:: m_strFile来存储脚本文件名称而且在这些类Logic里面我们需要手动Cscript::Run来运行所储存脚本:

( m_strFile != “” )
{
    Cscript::getSingleton.Run(m_strFile);
}

如果切无误脚本就会运行对于我们这个脚本机个提速手段我们脚本机每次Run都会调入次文件分析后再关闭文件如果帧需要有10个物件走脚本逻辑那么每帧就起码会有10次磁盘操作对于大量物件尤其是触发器(后面会提到)存在情况这是件严重事情提速手段就是在最开始就按照文件名把文件内容次提取到个缓冲区内这样走脚本逻辑时候就不会走磁盘操作了而是从内存缓冲区读取数据对于动辄个场景几十个物件游戏来说这种提速已经是普遍做法但每帧都进行磁盘操作也并非无是处在调试时候有时候需要经常改动脚本文件对于次调入情况次修改后必须重新启动游戏而每帧重新读次磁盘就不会遇到这种问题如何选择合适运行方式这就需要看是在什么情况下运行了

零件组装:具体游戏层构建过程

框架搭完后需要个具体东西来证明我们框架是否达到了预期目标综上我们对这个框架要求是:

1、 利用框架开发开发者不必要关注框架底层细节不必要关注OGRE只需要关注各个组分的间逻辑关系和存在方式即满足框架良好封装性
2、 上层逻辑允且只允许和框架打交道同时框架中可以包含OGRE中无法绕开重要组分
3、 如果是框架没有完成功能应该可以通过对框架临时扩展很好完成任务如果实在需要修改框架结构接口也应该尽量避免改动即满足接口安全

  这里有点例外就是所未完成功能是OGRE未实现功能这个情况需要交给OGRE维护人员去扩展OGRE库或我们自己来扩展OGRE库除此的外如果我们测试没有完成既定目标我可以认为自己失败了

先看看我们需求:
1、建立个室外场景即我们有个地图体系
2、有个Player即我们有个物件系统和起码个物件
3、有若干怪物怪物具有智能这个智能我们将用挂接在怪物身上脚本来处理即我们可以为怪物挂接怪物规则体系
4、当Player杀死所有怪物时候游戏成功结束否则当Player被杀死时候游戏失败结束即我们为世界挂接世界规则体系

  首先我们建立Application类其主要功能是管理应用运行时所有重要组件化和删除工作所有Singleton单件都会在Application最开始时候创建并分配堆内存并在Application结束时候销毁这个Application就类似于Ogre总管Root而后是些游戏层物件准备工作例如Player类、怪物类等等并将这些类和类工厂注册到ObjectManager物件管理器里面去这些工作都是立足于扩展不会修改原有代码Player类重点在于对键盘和鼠标控制作出响应使摄像机等随这些控制运动而Monster则重点在于实现些基本AI逻辑例如“搜索”、“索敌”、“攻击”以供状态机或者脚本需要

  在Application时候我们在Scene创建时为其载入Scene.cfg场景配置文件这个文件里包括了Terrain.cfg地形配置文件和object.cfg物件配置文件以及些其它和场景相关内容例如雾和Light等Terrain.cfg就是Ogre地形配置文件而Object.cfg则确定了每个物件所挂接规则体系这些规则体系关键就是作为物件成员脚本文件



下面是个标准脚本文件:

ObjectNumber=1

#Object-1

ObjectType=7

ObjectPositionX=220

ObjectPositionY=220

ObjectPositionZ=220

Objectscript=Insanity.AI

这里Objectscript=Insanity.ai就是为物件挂接了“疯狂”规则体系(AI)

通过更改Terrain.cfg和Scene.cfg我们创建出来了个室外场景然后通过更改object.cfg为场景添加个Player和几个怪物并为每个怪物挂套AI规则这样前 3步就满足了

那么世界规则体系应该挂接到哪里呢?挂接到Scene里吗?

  很多人是这么做而且这样做很简单但是我并不决定采用这种思路方法Scene功能很明确就是“管理”物件和地形Scene应该厚厚道道地作个管理员而不是游戏逻辑参和者因此我决定采用另种思路方法:就是物件系统所提供触发器

  触发器思路来自于句论述:“肉眼所看不见客观实在”就是说不能用肉体感知但是却在暗地里起作用客观规律对于我们员而言触发器说白了就是表面上不可感知在合适时候检测当前条件当满足条件时候按照预先设定反馈给系统特殊物件使用触发器个原因是在原来作品中曾经使用过它触发器所体现出来移植性和模块化比直接挂在场景上要好而且性能影响并不多

  从唯理论调中离开回到我们实战中由于触发器属于物件系统因此它每帧都会检测自己内部条件情况并根据条件产生出相应结果我们这里条件有两个个是( Player杀死了所有Monster )结果就是“游戏成功结束”个是( Player生命值低于0 )结果就是“游戏失败”这两个条件我们通过物件脚本系统挂接到触发器上这样触发器每帧都会来检测自己是否满足条件当满足条件时候:“BANG!”

  当把触发器加上并注册到物件系统里面后我们需求第4点也就满足了最后工作就是不断测试和调试了切无误时候就可以让它和大家见面了

第 4部分 结论和展望
  通过对游戏世界演绎对游戏逻辑归纳以及对游戏底层工具融合逐步诞生了我们现在框架为了使框架更能经得起检验我们使用了些设计模式提供思路方法来保证框架安全性现在高层游戏引擎介绍说明了对于这个游戏我们框架达标了但用这个框架开发个新游戏是否也会达标?答案是否定如果用这个框架去开发个RPG游戏那我们还缺技能、道具等诸多系统;如果去开发个纸牌游戏似乎我们框架对于规则支持还不是太方便;如果去开发个足球游戏似乎我们框架对AI支持太差劲……而且就OGRE本身也在不断更新、提供新功能甚至有时候否定原有类和接口不过把话说回来现在什么游戏引擎没有这种问题呢?写底层引擎容易但是写个通用高层引擎层却很复杂底层引擎只是跟变化缓慢平台技术相关但高层引擎层却是跟丰富多彩游戏相关不仅如此高层引擎存在同时受底层引擎功能限制

  需要走路还很长即便是对于国际知名大公司也是在不断探索和实战中但这并不表明前途就是渺茫我们通过这次实战作出了次从底而上和自上而下归纳和演绎过程在变化多端具体游戏和变化缓慢引擎中间寻找到了个引擎层契合点内容繁复、采用表现手段多姿多彩游戏世界即便是再复杂也可以通过定程度归纳演绎得出适应其规则和表现契合点和高层引擎层架构

 

附录
Terrain Example
/*

-----------------------------------------------------------------------------

This source file is part of OGRE

    (Object-oriented Graphics Rendering Engine)

For the latest info, see  border=0>http://www.ogre3d.org/

 

Copyright ?2000-2003 The OGRE Team

Also see acknowledgements in Readme.html

 

You may use this sample code for anything you like, it is not covered by the

LGPL like the rest of the engine.

-----------------------------------------------------------------------------

*/

 

/**

    \\file 

        Terrain.h

    \\brief

        Specialisation of OGRE's framework application to show the

        terrain rendering plugin 

*/

 

# "ExampleApplication.h"

# "OgreStringConverter.h"

 

# FLOW_SPEED 0.2

# FLOW_HEIGHT 0.8

 

 TerrainListener : public ExampleFrameListener

{

  public:

    TerrainListener(RenderWindow* win, Camera* cam) :ExampleFrameListener(win, cam) { };

 

 // Override frameStarted event to process that (don't care about frameEnded)

    bool frameStarted(const FrameEvent& evt)

    {

        float moveScale;

        float rotScale;

        float waterFlow;



         float flowAmount = 0.0f;

         bool flowUp = true;

 

        // local just to stop toggles flipping too fast

         Real timeUntilNextToggle = 0;

 

         (timeUntilNextToggle >= 0)

            timeUntilNextToggle -= evt.timeSinceLastFrame;

 

        // If this is the first frame, pick a speed

         (evt.timeSinceLastFrame  0)

        {

            moveScale = 1;

            rotScale = 0.1;

            waterFlow = 0.0f;

        }

        // Otherwise scale movement units by time passed since last frame

        

        {

            // Move about 100 units per second,

            moveScale = 10.0 * evt.timeSinceLastFrame;

            // Take about 10 seconds for full rotation

            rotScale = 36 * evt.timeSinceLastFrame;

            

            //  a nice waterflow rate

            waterFlow = FLOW_SPEED * evt.timeSinceLastFrame;            

        }

 

        // Grab input device state

        mInputDevice->capture;

 

        SceneNode *waterNode = _cast<SceneNode*>(

            mCamera->getSceneManager->getRootSceneNode->getChild("WaterNode"));

        (waterNode)

        {

            (flowUp)

                flowAmount  waterFlow;

            

                flowAmount -= waterFlow;

 

            (flowAmount >= FLOW_HEIGHT)

                flowUp = false;

             (flowAmount <= 0.0f)

                flowUp = true;

 

            waterNode->translate(0, (flowUp ? waterFlow : -waterFlow), 0);

        }

 

         Vector3 vec;

 

        vec = Vector3::ZERO;

 

         (mInputDevice->isKeyDown(KC_A))

        {

            // Move camera left

            vec.x = -moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_D))

        {

            // Move camera RIGHT

            vec.x = moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W))



        {

            // Move camera forward

            vec.z = -moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S))

        {

            // Move camera backward

            vec.z = moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_PGUP))

        {

            // Move camera up

            vec.y = moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_PGDOWN))

        {

            // Move camera down

            vec.y = -moveScale;

        }

 

         (mInputDevice->isKeyDown(KC_RIGHT))

        {

            mCamera->yaw(-rotScale);

        }

         (mInputDevice->isKeyDown(KC_LEFT))

        {

            mCamera->yaw(rotScale);

        }

 

        ( mInputDevice->isKeyDown( KC_ESCAPE) )

        {            

             false;

        }

 

        // Rotate view by mouse relative position

        float rotX, rotY;

        rotX = -mInputDevice->getMouseRelativeX * 0.13;

        rotY = -mInputDevice->getMouseRelativeY * 0.13;

 

 

        // Make all the changes to the camera

        // Note that YAW direction is around a fixed axis (freelook stylee) rather than a natural YAW (e.g. airplane)

        mCamera->yaw(rotX);

        mCamera->pitch(rotY);

        mCamera->moveRelative(vec);

 

        // Rotate scene node  required

        SceneNode* node = mCamera->getSceneManager->getRootSceneNode;

         (mInputDevice->isKeyDown(KC_O))

        {

            node->yaw(rotScale);

        }

         (mInputDevice->isKeyDown(KC_P))

        {

            node->yaw(-rotScale);

        }

         (mInputDevice->isKeyDown(KC_I))

        {

            node->pitch(rotScale);

        }

         (mInputDevice->isKeyDown(KC_K))

        {

            node->pitch(-rotScale);

        }

 

         (mInputDevice->isKeyDown(KC_F) && timeUntilNextToggle <= 0)

        {

            mStatsOn = !mStatsOn;



            //Root::getSingleton.showDebugOverlay(mStatsOn);

            showDebugOverlay(mStatsOn);

 

            timeUntilNextToggle = 1;

        }

 

 

        // Return true to continue rendering

         true;

    }

 

};

 

 

 TerrainApplication : public ExampleApplication

{

public:

    TerrainApplication {}

 

protected:

    virtual void createFrameListener(void)

    {

        mFrameListener=  TerrainListener(mWindow, mCamera);

        mFrameListener->showDebugOverlay(true);

        mRoot->addFrameListener(mFrameListener);

    }

 

 

    virtual void chooseSceneManager(void)

    {

        // Get the SceneManager, in this  a generic one

        mSceneMgr = mRoot->getSceneManager( ST_EXTERIOR_CLOSE );

    }

 

    virtual void createCamera(void)

    {

        // Create the camera

        mCamera = mSceneMgr->createCamera("PlayerCam");

 

        // Position it at 500 in Z direction

        mCamera->Position(Vector3(128,25,128));

        // Look back along -Z

        mCamera->lookAt(Vector3(0,0,-300));

        mCamera->NearClipDistance( 1 );

        mCamera->FarClipDistance( 384 );

 

    }

   

   virtual void createViewports(void)

    {

        // Create one viewport, entire window

        Viewport* vp = mWindow->addViewport(mCamera);

        vp->BackgroundColour(Colourvalue::White);

    }

 

    // Just override the mandatory create scene method

    void createScene(void)

    {

        Entity *waterEntity;

        Plane waterPlane;

 

        // Set ambient light

        mSceneMgr->AmbientLight(Colourvalue(0.5, 0.5, 0.5));

      

        // create a water plane/scene node

        waterPlane.normal = Vector3::UNIT_Y; 

        waterPlane.d = -1.5; 

        MeshManager::getSingleton.createPlane(

            "WaterPlane",

            waterPlane,

            2800, 2800,

            20, 20,

            true, 1, 

            10, 10,

            Vector3::UNIT_Z

        );

 

        waterEntity = mSceneMgr->createEntity("water""WaterPlane"); 

        waterEntity->MaterialName("Examples/TextureEffect4"); 

 

        SceneNode *waterNode = 

            mSceneMgr->getRootSceneNode->createChildSceneNode(

"WaterNode"); 

        waterNode->attachObject(waterEntity); 

        waterNode->translate(1000, 0, 1000);

 

        // Create a light

        Light* l = mSceneMgr->createLight("MainLight");

        // Accept default tings: po light, white dfuse, just  position

        // NB I could attach the light to a SceneNode  I wanted it to move automatically with

        //  other objects, but I don't

        l->Position(20,80,50);

 

        mSceneMgr -> WorldGeometry( "terrain.cfg" );

 

        mSceneMgr->Fog( FOG_EXP2, Colourvalue::White, .008, 0,  250 );

        //mRoot -> showDebugOverlay( true );

 

    }

 

};

 

 

/*

-----------------------------------------------------------------------------

This source file is part of OGRE

    (Object-oriented Graphics Rendering Engine)

For the latest info, see  border=0>http://www.ogre3d.org/

 

Copyright ?2000-2003 The OGRE Team

Also see acknowledgements in Readme.html

 

You may use this sample code for anything you like, it is not covered by the

LGPL like the rest of the engine.

-----------------------------------------------------------------------------

*/

 

/**

    @file 

        Terrain.cpp

    @brief

        Shows OGRE's terrain rendering plugin.

*/

 

# "Ogre.h"

# "Terrain.h"

 

# OGRE_PLATFORM  PLATFORM_WIN32

# WIN32_LEAN_AND_MEAN

# "windows.h"

#end

 

# OGRE_PLATFORM  PLATFORM_WIN32

INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )

#

 ( argc, char *argv)

#end

{

    // Create application object

    TerrainApplication app;

 

    SET_TERM_HANDLER;

    

    try {

        app.go;

    } catch( Ogre::Exception& e ) {

# OGRE_PLATFORM  PLATFORM_WIN32

        MessageBox( NULL, e.getFullDescription.c_str"An exception has occured!", MB_OK | MB_IConERROR | MB_TASKMODAL);

#

        std::cerr << "An exception has occured: " <<

            e.getFullDescription.c_str << std::endl;

#end

    }

 

     0;

}

 

参考
(1)游戏的王——孙百英主编科学普及出版社ISBN:7-110-04493-9
(2)设计模式——Erich Gamma等机械工业出版社ISBN:7-111-07575-7
(3)OGRE文档和源代码——Ogre制作组(英国)
(4)游戏引擎剖析——Jake Simpson
(5)圣剑群英传文档和源代码——金点工作室(中国)
(6)Ogre使用指南——mage工作室(中国)
0

相关文章

读者评论

发表评论

  • 昵称:
  • 内容: