开源3D游戏引擎irrlicht(鬼火)Example讲解——CustomSceneNode
- 格式:doc
- 大小:232.00 KB
- 文档页数:7
ygopro源码分析3:解剖本⽂简单的整理⼀下ygopro是如何运⾏的1.core的运作core维护了⼀场duel,是ygopro的核⼼.源码⼤概分为4部分:第⼀部分是card duel effect field group等类的定义⽂件第⼆部分是lua解释器,负责运⾏lua函数,interpreter源⽂件和头⽂件第三部分是card duel effect field group等类的lua库函数第四部分是核⼼处理⽂件processor.cpp等还记得这个游戏最开始的名字是ygocore.主循环和所有游戏⼀样,core也⼀样有⼀个主循环,由于是卡牌游戏,core的主循环是磕磕绊绊的运⾏的.简单来说是这样的:core与server直接交流,server在掌控core的主循环core给server传数据使⽤buffer,server给core传数据使⽤results,⼆者都是固定长度的内存core会⼀直运⾏,直到产⽣buffer,buffer交给server后,core会停⽌运⾏,等待server答复server收到buffer会发送给对应玩家的client,交给玩家操作,玩家操作后会产⽣results,由server向core转告如果是sing mode运⾏的话,每次的results都会被设置成⼀个固定值,(DUEL_SIMPLE_AI)处理core通过"处理单元unit"来运⾏,每⼀个unit都有若⼲步骤,⼀步⼀步的进⾏,需要玩家操作的时候会停⽌,玩家操作后会继续运⾏.就像调⽤函数⼀样,unit可以运⾏到⼀半去运⾏新的unit,xinunit调⽤完之后还会接着在原来的unit处接着运⾏.每个unit都带着⼀个明确的⽬的.+------------+| unit3 |+------------+| unit2 |+------------+| unit1 |+------------+processor永远只会优先运⾏最上⾯的unit3,3运⾏完了就会去运⾏2中断的部分,或者在向上⾯加⼀个unit4.unit1永远都不会结束,它是⼀个loop.unit1是"PROCESSOR_TURN",它的功能是交替的运⾏每个玩家的各个流程.unit2可以是"PROCESSOR_IDLE_COMMAND",代表了main1流程和main2时可以只有操作的时刻unit3可以是"PROCESSOR_SELECT_IDLECMD",表⽰正在等待client那边操作.2.⽹络⽹络完全由libevent库实现ygopro的客户端是⾃带服务器和客户端的,类似早期的单机游戏CS 魔兽争霸红警等,只需要在同⼀⽹络下就可以联机.ygopro本地⾃带服务器,但联机并没有做成类似东⽅⾮想天则的模式,本地的服务器基本上没什么⽤,在本地建⽴服务器的端⼝号在配置⽂件⾥决定了,频繁的去更改这个⽂件也不现实,所以同⼀⽹络下基本上只能同时存在⼀个服务器,只能⽤于测试脚本使⽤.⽬前233服和Mc服使⽤的服务端是 ,配合[ygopro-server][]使⽤.搜索游戏房间只能在同⼀⽹络下进⾏,房主新建服务器, 会开启⼀个端⼝号为"7920" 的udp⼴播,当接收到任何信息时,会检查这条信息,如果该信息是"NETWORK_CLIENT_ID",该⼴播就会将房间信息发送给对⽅的"7921"端⼝另⼀边客户端处,点击刷新主机时,会⽴即使⽤"7922"端⼝的⾝份⼀直向"host地址"的 "7920"端⼝发送信息,信息内容是"NETWORK_CLIENT_ID",⼀共会发8次host地址是通过gethostbyname函数获取的地址,⼀般根据⽹卡情况和⽹络配置情况会获取到好⼏个地址,每个地址都是正确地址,都可以⽤于游戏,使⽤ipconfig命令可以看到这⼏个地址的详细情况8次⾥⾯肯定会有⾄少⼀次命中"host地址"的正确地址,也就是说,会有多条NETWORK_CLIENT_ID信息被发到server的"7920"端⼝中,server会⽴即将房间信息发送到客户端的"7921"端⼝.客户端收到之后会⽴即将房间信息打印到界⾯上(可能会有多条)服务器和客户端通信服务器和客户端之间通信的内容是packet,结构如下:16bit packet_len 8bit proto exdata_len exdata+------------------+---------------+-------------------------+|- data -|其中第⼀部分为packet_len,长度2个字节,数值是 exdata_len + 1,即后⾯内容的长度总和第⼆部分是 proto,长度1个字节, 表⽰后⾯ exdata 的类型第三部分是 exdata,⼀些特定的proto会附带这部分内容,长度不定.上⾯提到的core传出来的buffer在这部分中后⾯两部分统称为data这个packet的最终长度是packet_len+2.服务器和客户端处理packet之前跳过了前2个字节.客户端给服务器发送数据void SendPacketToServer(unsigned char proto)void SendPacketToServer(unsigned char proto, ST& st)void SendBufferToServer(unsigned char proto, void* buffer, size_t len)客户端连接服务器并设置读回调函数client_bev = bufferevent_socket_new(client_base, -1, BEV_OPT_CLOSE_ON_FREE);bufferevent_setcb(client_bev, ClientRead, NULL, ClientEvent, (void*)create_game);客户端收到服务器数据,触发读回调函数void DuelClient::ClientRead(bufferevent* bev, void* ctx) {evbuffer* input = bufferevent_get_input(bev);size_t len = evbuffer_get_length(input);unsigned short packet_len = 0;while(true) {if(len < 2)evbuffer_copyout(input, &packet_len, 2); //获取前2字节作为packet长度if(len < (size_t)packet_len + 2)return;evbuffer_remove(input, duel_client_read, packet_len + 2); //获取⼀个packet的所有数据if(packet_len)HandleSTOCPacketLan(&duel_client_read[2], packet_len); //从第[2]个字节开始处理,跳过了packet_lenlen -= packet_len + 2;}}服务器给客户端发送数据void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto)void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, ST& st)void SendBufferToPlayer(DuelPlayer* dp, unsigned char proto, void* buffer, size_t len)建⽴监听服务器当有客户端连接时,会触发ServerAccept回调函数,建⽴⼀个socket连接listener = evconnlistener_new_bind(net_evbase, ServerAccept, NULL,LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, -1, (sockaddr*)&sin, sizeof(sin));设置读回调函数当server接收到数据后,会触发ServerEchoRead函数void NetServer::ServerAccept(evconnlistener* listener, evutil_socket_t fd, sockaddr* address, int socklen, void* ctx)服务器收到数据会触发该函数void NetServer::ServerEchoRead(bufferevent *bev, void *ctx) {evbuffer* input = bufferevent_get_input(bev);size_t len = evbuffer_get_length(input);unsigned short packet_len = 0;while(true) {if(len < 2)return;evbuffer_copyout(input, &packet_len, 2); //读取数据的前2个字节作为 packet长度if(len < (size_t)packet_len + 2)return;evbuffer_remove(input, net_server_read, packet_len + 2); //将⼀个packet 的所有数据都存储在net_server_read ⾥if(packet_len)HandleCTOSPacket(&users[bev], &net_server_read[2], packet_len); //从第[2]个字节开始处理,跳过了packet_lenlen -= packet_len + 2;}}可以多个客户端连接服务器,多余的玩家会成为观战者.总结:服务器和客户端靠HandleXXXXPacket函数处理packet(跳过了前两个字节)3.其他3.1 irrlicht⿁⽕引擎这是⼀个⾮常⽼的游戏引擎,古⽼到其最新的源码⾥提供的是vs2012的sln⽂件,但也不是说消失在时间⾥了,2021年还有⼈使⽤其开发新游戏,还是个开放世界游戏,在ygopro⾥,主要应⽤就是主界⾯菜单卡组构筑界⾯还有游戏界⾯.GUI的编程风格挺像QT的.对于ygopro来说,了解以下两点就可以了:irrlicht初始化操作⾸先要获取⼀个IrrlichtDevice,这是irrlicht最根本的对象,有两种⽅法得到⾃定义params,也是ygopro使⽤的⽅法IrrlichtDevice* device;irr::SIrrlichtCreationParameters params = irr::SIrrlichtCreationParameters();//对params做⼀些⾃定义device = irr::createDeviceEx(params);或者使⽤默认params函数原型:IrrlichtDevice* createDevice(video::E_DRIVER_TYPE deviceType = video::EDT_SOFTWARE,const core::dimension2d<u32>& windowSize = (core::dimension2d<u32>(640,480)),u32 bits = 16,bool fullscreen = false,bool stencilbuffer = false,bool vsync = false,IEventReceiver* receiver = 0);使⽤IrrlichtDevice获取其他对象获取IVideoDriver,所有图形相关的接⼝IVideoDriver* driver = device->getVideoDriver();获取IGUIEnvironment,⽤于管理所有GUI组件IGUIEnvironment* env = device->getGUIEnvironment();获取ISceneManager,管理camera 等其他资源ISceneManager* smgr = device->getSceneManager();主循环while(device->run()) {//绘制GUI 绘制图形//接收玩家输⼊等}irrlicht的GUI还是⽐较落后的.ygopro⽤了七⼋百⾏,来添加GUI元素添加GUI的步骤⾸先去要预先定义⼀些宏来表⽰GUI的id(类似QT⾥的信号),如:#define BUTTON_LAN_MODE 100#define BUTTON_SINGLE_MODE 101#define BUTTON_REPLAY_MODE 102#define BUTTON_TEST_MODE 103添加btnbtnLanMode = env->addButton(rect<s32>(10, 30, 270, 60), wMainMenu, BUTTON_LAN_MODE, dataManager.GetSysString(1200));添加checkboxchkHostPrepReady[i] = env->addCheckBox(false, rect<s32>(250, 75 + i * 25, 270, 95 + i * 25), wHostPrepare, CHECKBOX_HP_READY, L"");初始化这些元素时都有⼀个参数是id,当GUI元素被操作的时候这些id就代表了不同的信号.如何使⽤GUI需要⼀个对象来接受这些信号,从⽽使这些GUI元素发挥作⽤.在irrlicht⾥,这个对象被称为EventReceiver.同⼀时刻,⼀个device只能有⼀个EventReceiver.这⾏程序为device设置了⼀个EventReceiverdevice->setEventReceiver(&menuHandler);任意⼀个类,只要重写了OnEvent(const irr::SEvent& event)⽅法,就可以成为EventReceiver声明class MenuHandler: public irr::IEventReceiver {public:virtual bool OnEvent(const irr::SEvent& event);};实现bool MenuHandler::OnEvent(const irr::SEvent& event) {switch(event.EventType){ //获取event类型case irr::EET_GUI_EVENT: //GUI事件//根据id判断是哪个GUI元素,然后做出相应操作s32 id = event.GUIEvent.Caller->getID();case irr::EET_MOUSE_INPUT_EVENT: //⿏标输⼊事件case irr::EET_KEY_INPUT_EVENT: //键盘输⼊事件//判断哪个健被按下switch(event.KeyInput.Key)}}3.2 sqlite数据库ygopro使⽤sqlite把所有卡⽚的信息存储在cards.cdb这个⽂件中.可以使⽤来⽅便的操作这个⽂件.card.cdb⽂件cards.cdb中有两个表,datas和textsdatas的内容是卡⽚的信息(⽤数字表⽰),texts的内容是跟卡⽚有关的字符串.datas的表头如下:idotaliassetcodetypeatkdeflevelraceattributecategory需注意:这些数值的⽤途⼤部分是在卡组构造界⾯搜索卡⽚id :表⽰卡⽚的官⽅代码ot :表⽰卡⽚的限制情况 0代表禁⽌ 3代表⽆限制alias:表⽰别名,有些卡⽚被科乐美复刻了多次,⽐如青眼⽩龙,复刻后的青眼⽩龙的alias就是初版青眼⽩龙的idsetcode :⼀个10进制数,表⽰卡⽚所属的字段,把这个数转换成16进制可得到字段, 每个字段4位16进制数.strings.conf⽂件中存储了所有字段举个例⼦:数据库中查到的setcode最⼤值的卡⽚是"希望皇拟声乌托邦",所属字段是"刷拉拉(0x8f)" "我我我(0x54)" "隆隆隆(0x59)" "怒怒怒(0x82)",这张卡⽚的setcode是36592129229979791,转换成16进制是82 0059 0054 008Ftype :⼀个10进制数,转换成2进制后,表⽰卡⽚类型.atk :攻击⼒def:防御⼒level: 等级 or 阶级 or link值race:种族attribute:属性category:⼀个10进制数,转换成32bit的⼆进制数,恰好对应卡⽚搜索的中的32个效果.举个例⼦:随机选择了⼀张卡"暗之⽀配者-佐克",其category值为134217730,写成⼆进制是00001000000000000000000000000010,倒着看,恰好对应第⼆个效果"怪兽破坏"和倒数第五个效果"幸运",⾄于为什么要倒着看,因为代码中是通过下⾯的⽅式设置过滤选项的long long filter = 0x1;for(int i = 0; i < 32; ++i, filter <<= 1)if(mainGame->chkCategory[i]->isChecked())filter_effect |= filter;texts的内容⽐较简单就不展开了.spmemvfs库是:A memory vfs implementation for SQLite,⽤于把整个cdb⽂件读到内存中,加快读取速度.3.3 replay回放replay的原理是记录下玩家的操作到rep⽂件,然后播放rep时再从⽂件⾥读出操作给到core,让其使⽤那些操作进⾏⼀场全⾃动duel,可以说跟东⽅project的⽅式⼀模⼀样.这个过程使⽤了lzma库来进⾏压缩和解压操作.。
最常用的开源游戏引擎开源即开放原代码(Open Source),游戏引擎好比赛车的引擎,是用于控制所有游戏功能的主程序,从计算碰撞、物理加速系统和物体的相对位置,到接受玩家的输入,以及按照正确的音量输出声音等等。
无论是角色扮演游戏、即时策略游戏、冒险解谜游戏或是动作射击游戏,哪怕是一个只有1兆的小游戏,都有这样一段起控制作用的代码。
下面将列出一些著名的且经常被使用的开源游戏引擎。
Delta3D:Delta3D是一个功能齐全的游戏引擎,可用于游戏,模拟或其他图形应用。
其模块化设计集成了其他的开源项目,如‘开放场景图’,‘开放动力学引擎’,‘人物动画库’和‘OpenAL’ 。
Delta3D把这些开源项目集成到一个易于使用的应用程序编程接口中。
下载Delta3D 2.1.0 127MB / Windows XP。
NeoEngine:NeoEngine是一个全功能的用C++编写的开源3D三维游戏引擎。
该引擎是多平台的,包括OpenGL和DirectX渲染功能,支持Windows ,Linux和Mac OS X系统,它提供了场景管理,顶点和像素着色,骨骼动画和物理,脚本以及一个完全集成的工具链。
NeoEngine 下载地址。
Irrlicht Engine:该Irrlicht Engine是一个开放源码的,高性能的实时3-D 引擎,用C++编写,也可用于.Net语言。
它采用跨平台设计,使用D3D ,OpenGL 与自己的软件渲染。
其功能特点可以与商业3D引擎相比。
Irrlicht Engine 下载地址。
OGRE(面向对象的图形渲染引擎):OGRE是用C++编写的,以现场为导向,灵活的三维引擎,它主要用于那些利用硬件加速的3D图形应用程序。
它的类库提取了所有基础系统库的细节,如Direct3D和OpenGL ,并提供了一个基于世界对象和其他直观类的界面。
OGRE 下载地址。
Bullet:Bullet是三维游戏多重物理库,提供最先进的碰撞检测,柔软身体和刚体动力学。
Unity3D游戏引擎的开发技术分享Unity3D是一款流行的多平台游戏引擎,它的开放性和易用性为开发者提供了极大的便利,可以用来制作桌面游戏、移动游戏、虚拟现实和增强现实应用程序等。
本文将分享一些Unity3D游戏引擎的开发技术,旨在帮助那些正在使用该引擎进行游戏制作的开发人员。
一. Unity3D游戏引擎的基本结构Unity3D游戏引擎的基本结构由场景、资源、组件等组成,让我们先来了解一下它们。
场景(Scene)是指游戏场景的基本单位,它包含了游戏场景中所有的元素,例如角色、地形、道具等等。
一般情况下,场景可以进行不同的组合和切换,实现多关卡或多场景游戏。
资源(Asset)是指Unity3D游戏开发过程中所需要的各种素材,例如音乐、声音、图片、字体、脚本等等。
这些资源可以在场景中被调用和使用。
组件(Component)是指可以挂载到游戏对象上的各种功能模块,例如摄像机、灯光、碰撞器、脚本等等。
组件可以给游戏对象赋予不同的功能,例如控制移动、发出声音、触发事件等等。
二. Unity3D游戏引擎的快捷键和常用命令熟练掌握Unity3D游戏引擎的快捷键和常用命令可以让开发效率大大提高。
下面给出一些常用的快捷键和命令:Ctrl+S:保存当前场景Ctrl+N:新建场景Ctrl+Shift+N:新建文件夹Ctrl+Shift+Alt+N:新建C#脚本Ctrl+Shift+O:打开场景Ctrl+L:加载上一次场景Ctrl+Shift+P:清除PlayerPrefsCtrl+D:复制选中的对象Ctrl+Alt+D:打开DLL的反编译工具Ctrl+Q:退出Unity编辑器三. Unity3D游戏引擎的动画制作技术制作游戏动画是Unity3D游戏引擎的一项重要特点,下面分享一些常用的动画制作技术。
1. 骨骼动画骨骼动画是用来表现角色动作的一种常见方式,它的原理是通过在角色模型上绑定骨骼节点,然后通过控制这些节点的移动、旋转和缩放来实现角色动作的变化。
OGRE(Object-oriented Graphics Rendering Engine)(Ogre, 食人魔) ,是一款成熟、稳定、可靠、灵活、跨平台、而且拥有丰富功能开源实时3D 图形渲染引擎( 并不是游戏引擎) ,由 社区维护,遵守LGPL(GNU Lesser General Public License ) 协议。
同类其他开源引擎:1. Irrlicht ( 鬼火)2. Nebula( 星云)3. klayGEOGRE 引擎特性:·全面并同等的支持OpenGL 和Direct3D·全面支持Windows ,Linux 以及Mac OS X 平台·其完全的面向对象设计,允许您通过插件和子类毫不费力地扩展引擎的功能。
在Ogre 3D 的名字中包含“3D ”是很贴切的,因为那就是它所能做的所有事情。
它不能处理用户输入,不能管理你的游戏状态,不能做网络通讯,不能播放声音。
它只是做为一个3D 渲染引擎被设计出来,并且那就是它唯一的应用。
因为专业,所以它总是能够很好的完成它本分的任务。
(虽然Ogre 引擎中也会包含比如输入系统等一些简单的实现,但官方的说法一般是:这只是为了支持演示程序所提供的,不建议你在自己实际的应用中使用。
你需要在Ogre 去中去寻找其他的库来完善你自己的工具箱。
)当今大多数软件都会依赖于其他软件或者开发包中提供的外部功能,这样可以让软件的开发在别人已经存在的成果之上,避免了重复制造轮子。
如果不需要对常用的功能重复实现,这样做最直观的好处就是促使工作团队更集中精力解决他们自身软件中所存在的问题,进而产生出更高质量的产品。
而且随着开源社区的发展,越来越多优秀的软件或者程序库可以从网络上免费得到。
不过更多的依赖项目也意味着需要相对更复杂的编译环境设置,甚至有时候要编译构建所依赖的项目源代码产生。
如果依赖了一些在活跃开发期的项目,就意味着有可能需要经常更新。
3D游戏引擎术语介绍作者:韩红雷1. 3D引擎(3D engine)、3D编程语言(3D language)和3D创作系统(3D authoringsystem)的区别是什么?3D引擎是3D图形函数库。
在因特网上有很多3D引擎,其中有一些还是免费的,有些商业化的引擎价格在50美元到25万美元之间。
3D引擎需要使用外部的开发系统来编写程序,使用最多的是是微软的VisualC++。
围绕3D引擎通过编程来开发游戏具有极大的自由度,但也需要很多的经验、工作和时间。
3D编程语言提供了一种更加容易的编写3D应用程序的方法,因为你使用的是一种专门为3D游戏设计的脚本语言来编写DirectX界面。
这种语言不受3D引擎速度和自由度的影响,并且避免了使用“真正”编程语言带来的问题。
很多3D 编程语言使用Basic——一种比较容易学习的语言,但由于其落后的语言结果,所以并不适合于编写大而复杂的游戏。
比较适合于当前游戏开发需要的是基于C 或者JavaScript的语言。
创作游戏最简单的方法是使用3D创作系统——它们有自己的3D引擎,并且具备可视化编辑器,可以很快地创作一个游戏原型。
当然了,只有很简单的游戏才可能绕开编程,创作系统一般都提供脚本语言来进行编程或定制游戏。
利用创作系统,再加上对独立3D引擎的编程,可以在很短的时间内创作一款游戏,很多大的游戏公司都开始使用创作系统来开发游戏了。
一些简单的创作系统针对FPS(First or third PersonShooters),不提供或者只提供有限的脚本编程。
尽管利用他们开发的FPS游戏并没有什么市场,但如果你不希望使用脚本或者不想让你的游戏商业化的话,也可以使用他们来开发游戏。
而多数的创作系统可以用来开发任何种类的游戏或者3D应用程序。
下面是一个当下流行的系统和引擎的对比表:**代表可以被显示,但需要第三方工具来创建。
$$$表示发行或者销售游戏需要额外收费或履行特定的条件。
简介物理引擎就是在游戏中模拟真实的物理效果,比如,场景中有两个立方体对象,一个在空中,一个在地面上,在空中的立方体开始自由下落,然后与地面上的立方体对象发生碰撞,而物理引擎就是用来模拟真实碰撞的效果。
如果需要让模型感应物理引擎的效果,需要将刚体组件或角色控制器组件添加至该对象中。
刚体(Rigidbody)刚体是一个非常重要的组件,新创建的物体默认情况下是不具有物理效果的,而刚体组件可以给物体添加一些常见的物理属性,比如物体质量、摩擦力和碰撞参数等,这些属性可用来真实的模拟该物体在3D游戏世界中的一切行为。
下面我们在unity中创建一个plane(平面),两个cube(立方体),蓝色cube默认状态是没有rigidbody,给红色cube添加刚体组件,选择要添加刚体的对象,通过“Component—>hysics—>Rigidbody”或者在Inspector窗口,选择“AddComponent—>hysics—>Rigidbody ”运行后可以发现,添加了刚体的红色cube感应到了物理效应,会从空中落下。
而蓝色cube 依然是静止不动的可以看到Inspector可以看到Rigidbody包含的属性,简单的看下几个属性的含义,详细的可以看手册力力是物理学中一个非常重要的元素,其种类有很多,刚体组件可以受力的作用,比如给刚体施加一个X轴方向的力,那么该刚体绑定的物体将沿X轴方向向前移动,这就好比用力将物体仍出去一样,该物体会以抛物线的形式移动,而不是呆板的做匀速平移。
力的方式有两种1:普通力,通过设定里的方向和大小,相当于把力施加在物体的重心上。
2:位置力,需要设定目标点的位置,该物体就朝向这个目标位置施加力。
AddForce和AddForceAtPosition还是拿之前的那个列子做演示。
在Hierarchy视图中创建两个Sphere,红色的添加普通力,白色的添加位置力红色Cube当作位置力的目标对象。
Irrlicht引擎源码剖析——第一天从今天开始,我要剖析Irrlicht(鬼火)3D游戏引擎的源代码了。
剖析的版本为Irrlicht 0.1,即Irrlicht引擎的第一个版本。
因为最初的版本相对来说是最简单的,从最初的版本开始剖析,然后再看之后的各个版本,可以更清楚的获知该引擎版本迭代更新的信息。
从而充分了解该引擎的发展变化,自己从中也能学得更多的知识。
我的基本剖析方法是:自己新建一个项目,Irrlicht源码看到哪,自己就写到哪,等把整个Irrlicht 0.1看完后,自己也把引擎写了一遍,这样对整个引擎的架构更加了然于心。
写的过程中,遇到问题并解决后,更能加深理解。
从Irrlicht的官方论坛(/)上可以下载到各个版本的源代码。
用VS 2008打开Irrlicht 0.1,如下图所示。
可以看到该项目包含7个目录和3个源码文件。
doc目录包含的是文档信息,不过该目录下包含的T odo.txt是无效文件。
因为在编程过程中,会在某问题暂时无法解决的地方用“//TODO”注释,所以T odo.txt应该是记载问题用的。
include目录下包含5个子目录和6个头文件,如右图所示。
从include包含的信息来看,整个引擎可分为6个模块:引擎模块(6个头文件)、引擎核心模块(core)、图形界面模块(gui)、输入输出模块(io)、场景管理模块(scene)、以及显示模块(video)。
根据6个模块的划分,可以清晰地得知6个实现:引擎初始化(3个代码文件)、图形界面(gui impl)、输入输出(io impl)、其它(other impl)、场景(scene impl)、显示(video)。
那么引擎核心模块(core)的实现在哪呢?在快速浏览一下include\core下的头文件后,发现在头文件中就对core进行了实现。
core部分就是作者自己写的一些数据结构的实现,比如向量、矩阵、字符串等。
在other impl目录下包含了jepglib库和zlib库,但是并没有包含有效的代码文件,我们要重新添加这两个库文件。
C++开源库,欢迎补充。
C++在“商业应⽤”⽅⾯,曾经是天下第⼀的开发语⾔,但这⼀桂冠已经被java抢⾛多年。
因为当今商业应⽤程序类型,已经从桌⾯应⽤迅速转移成Web应⽤。
当Java横⾏天下之后,MS⼜突然发⼒,搞出C#语⾔,有⼤⽚的曾经的C++程序员,以为C++要就此沉沦,未料,这三年来,C++的⽣命⼒突然被严重地增强了。
主⼒原因就是开源的软件、基础软件(⽐如并发原⽣⽀持,⽐如Android必定要推出原⽣的SDK)、各种跨平台应⽤的出现。
开源C++库必须具有以下特点:必须是成熟的产品、跨平台的产品、相对通⽤的库。
⼀、通⽤标准类STL:C++标准模板库,呵呵,它也是开源的嘛。
boost:C++准标准库,它是强⼤地,江湖称之“千锤百炼”。
-------若掌握,必横⾏世界。
deelx (轻量级的正则表达式解析类库,国产),boost⾥有强⼤的正则表达式解析库,但如果你只想要⼀个表达式解析,不想要拖上庞⼤的boost库时……⽀持⼀下国货。
iconv /iconvpp : (C形式的编码转换函数库,⼆、XML解析库C++的XML相关库不少,但是⼤部分其实都是C库,使⽤起来⾃然不那么轻便。
其中基于DOM的有TinyXml,基于SAX的当然是Xerces。
前者⼩巧快捷,便于使⽤,适合做数据交换。
后者则是全功能的XML解析器。
哥更倾向于TingyXml.⼩巧啊!xerces-c :最强⼤的XML解析库了,不是仅仅在开源库⾥,你尽管把商业的算在内。
当然,它的变体,被IBM拿去卖钱的那个版本,多了数百兆的东东来⽀持各国编码转换,是更强⼤,但我觉得有⼩⼩的,开源的iconv在前不就够了?对三个轻型xml解析开源库:SlimXml、TinyXml、RapidXml,对⽐如下:解析这个3.3万⾏,1.5M⼤⼩的xml,三个库分别花了SlimXml: 22msTinyXml: 54msRapidXml: 4ms!结论是,RapidXml果然很强悍,居然⽐SlimXml快5倍多。
开源3D游戏引擎Irrlicht(鬼火)Example讲解——CustomSceneNode赵刚Irrlicht引擎自带的第3个Example叫做CustomSceneNode,她演示了用户如何自己创建新的场景节点,如果用户对irrlicht里面已有的SceneNode都不满意,希望自己创建一个有特定功能的SceneNode可以参照这个例子做,这个例子创建的SceneNode很简单,只不过是一个四棱锥,但方法是可以参考的,用户理解后完全可以创建出复杂的SceneNode。
程序运行起来如下图:运行03.CustomSceneNode.exe的时候会先出来一个控制台窗口,按a,再按回车即可,表示选择OpenGL作为渲染API。
进入bin目录下的examples目录可以看到03.CustomSceneNode目录,双击CustomSceneNode_vc9.vcproj文件打开工程文件,工程文件中只有一个main.cpp文件。
内容如下(去除了英文注释):#include<irrlicht.h>#include"driverChoice.h"using namespace irr;#ifdef _MSC_VER#pragma comment(lib, "Irrlicht.lib")#endifclass CSampleSceneNode : public scene::ISceneNode{core::aabbox3d<f32> Box;video::S3DVertex Vertices[4];video::SMaterial Material;public:CSampleSceneNode(scene::ISceneNode* parent,scene::ISceneManager* mgr, s32 id) : scene::ISceneNode(parent, mgr, id){Material.Wireframe = false;Material.Lighting = false;Vertices[0] = video::S3DVertex(0,0,10, 1,1,0,video::SColor(255,0,255,255), 0, 1);Vertices[1] = video::S3DVertex(10,0,-10, 1,0,0,video::SColor(255,255,0,255), 1, 1);Vertices[2] = video::S3DVertex(0,20,0, 0,1,1,video::SColor(255,255,255,0), 1, 0);Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1,video::SColor(255,0,255,0), 0, 0);Box.reset(Vertices[0].Pos);for (s32 i=1; i<4; ++i)Box.addInternalPoint(Vertices[i].Pos);}virtual void OnRegisterSceneNode(){if (IsVisible)SceneManager->registerNodeForRendering(this);ISceneNode::OnRegisterSceneNode();}virtual void render(){u16 indices[] = { 0,2,3, 2,1,3, 1,0,3, 2,0,1 };video::IVideoDriver* driver = SceneManager->getVideoDriver();driver->setMaterial(Material);driver->setTransform(video::ETS_WORLD,AbsoluteTransformation);driver->drawVertexPrimitiveList(&Vertices[0], 4, &indices[0], 4, video::EVT_STANDARD, scene::EPT_TRIANGLES,video::EIT_16BIT);}virtual const core::aabbox3d<f32>& getBoundingBox() const{return Box;}virtual u32 getMaterialCount() const{return 1;}virtual video::SMaterial& getMaterial(u32 i){return Material;}};int main(){video::E_DRIVER_TYPE driverType=driverChoiceConsole();if (driverType==video::EDT_COUNT)return 1;IrrlichtDevice *device = createDevice(driverType,core::dimension2d<u32>(640, 480), 16, false);if (device == 0)return 1; // could not create selected driver.device->setWindowCaption(L"Custom Scene Node - Irrlicht EngineDemo");video::IVideoDriver* driver = device->getVideoDriver();scene::ISceneManager* smgr = device->getSceneManager();smgr->addCameraSceneNode(0, core::vector3df(0,-40,0),core::vector3df(0,0,0));CSampleSceneNode *myNode =new CSampleSceneNode(smgr->getRootSceneNode(), smgr, 666);scene::ISceneNodeAnimator* anim =smgr->createRotationAnimator(core::vector3df(0.8f, 0, 0.8f));if(anim){myNode->addAnimator(anim);anim->drop();anim = 0;}myNode->drop();myNode = 0;u32 frames=0;while(device->run()){driver->beginScene(true, true, video::SColor(0,100,100,100));smgr->drawAll();driver->endScene();if (++frames==100){core::stringw str = L"Irrlicht Engine [";str += driver->getName();str += L"] FPS: ";str += (s32)driver->getFPS();device->setWindowCaption(str.c_str());frames=0;}}device->drop();return 0;}程序很简洁,条理也很清晰,下面开始讲解代码。
首先每个使用irrlicht的程序都必须包含:#include<irrlicht.h>#pragma comment(lib, "Irrlicht.lib")表示要使用irrlicht SDK程序开头就定义了一个名为CSampleSceneNode的类,这个类从ISceneNode 接口(抽象类)派生,在irrlicht中,用户创建的SceneNode类都必须从ISceneNode接口派生。
CSampleSceneNode类包含下面3个成员变量:core::aabbox3d<f32> Box;video::S3DVertex Vertices[4];video::SMaterial Material;其中Box和Material所有的SceneNode类都会包含,Vertices用于保存网格顶点,数量和格式和用户创建的网格复杂度有关,这个例子中的网格是4个顶点的四棱锥,而且是很基本的网格类型(没有多层纹理,凹凸纹理等复杂特性),所以使用S3DVertex这种简单类型。
CSampleSceneNode在构造函数中建立了四棱锥。
Material.Wireframe = false;Material.Lighting = false;Vertices[0] = video::S3DVertex(0,0,10, 1,1,0,video::SColor(255,0,255,255), 0, 1);Vertices[1] = video::S3DVertex(10,0,-10, 1,0,0,video::SColor(255,255,0,255), 1, 1);Vertices[2] = video::S3DVertex(0,20,0, 0,1,1,video::SColor(255,255,255,0), 1, 0);Vertices[3] = video::S3DVertex(-10,0,-10, 0,0,1,video::SColor(255,0,255,0), 0, 0);Box.reset(Vertices[0].Pos);for (s32 i=1; i<4; ++i)Box.addInternalPoint(Vertices[i].Pos);这几行程序设置四棱锥的材质属性,4个顶点的位置,法线,颜色和纹理坐标,包围盒的尺寸。
接着CSampleSceneNode类重载了virtual void OnRegisterSceneNode()函数,该函数每帧循环中均会被irrlicht SDK调用,该函数决定了SceneNode是否会被加入到渲染队列。
CSampleSceneNode对该函数没有什么特别设计,只是简单的执行了SceneManager->registerNodeForRendering(this),表示将自己加入渲染队列。