WIP(Working In Progress)是我初学游戏引擎开发时候开发的一个2D游戏引擎,当时计划为它实现类似Unity一样的编辑器,具有和Unity相似的工作流,但是由于水平不够,走了很多弯路,闭门造车,做了很多错误的设计,导致很多地方反人类和难以维护,加之时间有限,所以已经停止了对它的继续开发。由于停止了开发,又不想把所有资料都全部搞丢,所以把在开发中学到的东西,和一些自己的思考都记录一下。以便后可以参考。

他最后可以实现这些功能,不过实现起来远比成熟的引擎蛋疼得多:

  • 脚本游戏编程
  • 基本的2D游戏(我曾经用这个东西做过flappy bird和一个简单的RPG游戏(由于没有写编辑器,制作起来非常耗时特别是帧动画和布置场景的时候))
  • 一些2Ddemo(之前上课的几个作业一直用这个做)
  • 简单的OpenGL shader
  • 简单的3D呈现

当时就选择了脚本流,因为之前接触过一段时间的Lua,所以脚本语言也直接选择了Lua。脚本的嵌入采用了很简单的思想,没有去导出c++类,而是简单实现了lua中的类,再把所有的c++对象都映射为一个lua对象中的指针,这样做的效率也许不高,但是后来也没有遇到什么大问题,只是有的时候会不方便,而比较棘手的就是对象销毁问题,我在哪些对象需要自动销毁,那些对象不需要上,想了很久,最终也没有理出一个完全彻底的方案。另外,我的脚本系统仅仅是执行游戏逻辑,我在主循环中使用一个函数每帧都调用Lua脚本的入口函数,从而驱动整个脚本系统。

至于基于组件的游戏对象,和数据驱动基本上全靠Lua和XML。场景保存到XML文件中的,每个场景中的对象就是一个XML结点,而读取场景则选择了在lua中实现,一切的一切都全仰仗于这个函数:

function System.genertate_component_by_name(component_name)
s = "local _ = require \""..component_name.."\";return _:new()"
return loadstring(s)
end

也就是说全靠lua的loadstring函数。我的每一个组件都是一个Lua脚本,这些脚本继承于一个基类,当然也都是Lua实现的,这些,我都是借鉴自Unity的脚本系统中我看得懂的部分,所以部分看起来和Unity的很类似。虽然简单,但是应该说,我从这次实现尝试中学到的东西还是不少,至少解了了一些很有用的概念。对Lua的了解也深入了一步。

渲染是我这次尝试中最失败的部分,因为首先我并不熟悉OpenGL,而且在此之前我基本只使用Opengl的老渲染管线渲染图像。所以最开始的时候,我的渲染系统中导出都是glbegin,glend,后来随着我的深入学习,我将那些地方全部改成了gldrawelements或者gldrawarray来渲染,但是思想依然是固定渲染管线的思想。在我的渲染系统中,每次渲染一个四边形,都会绑定一个纹理上去,然后把这个东西的顶点数据和纹理坐标以及纹理id打包存到一个容器v中,直到一帧结束,将v中的所有东西全部取出来,一个一个的调用drawelements,然而这对渲染的效率并没有什么提升,多次drawcall依然是多次drawcall,固定管线依然是固定管线,对于所谓的多线程也完全没什么用处。后来我准备在这个系统上开刀,试图把所有的drawcall合并,然而这将会直接导致整个系统的重写。后来逐渐深入学习了Opengl,想使用可编程管线来渲染3D网络,强制加入了Shader功能,然而这样的行为并不好,而且很多时候如果2D3D一起渲染会产生问题,也就是说,这个渲染系统仅仅只支持2D渲染,如果想渲染3D图形,对不起只能用OpenGL,连封装都没有……而当时使用在渲染2D对象的时候,幸好用了mesh的概念,而不是直接拉四个点去……

场景管理其实那时候是没有那个概念的,2D游戏计算量没到,当然不会去考虑场景管理优化之类的,Scene类唯一有的功能就是分了3个层,一个层用来装object,一个用来装UI,剩下的用来装volumes。因为当时考虑到,object的更新和UI的更新并不是一样频繁的,至于volumes,本来是想用来存放一些阻挡体积,碰撞体积,就和UE里面的volume差不多的,但是由于一些硬伤,这些东西知道最后也没有能够加进去。

关于物理,我并不太懂物理,wip当前仅支持基本的刚体物理,物理部分主要是我的一个同学帮助我完成的,我仅仅介入他写好的功能。物理上,我遇到的问题就是更新。物理引擎为我提供的东西主要就是一个body,我把这个body作为我的object的一个组件。于是在更新的时候,我就要不断地将当前的位置写入body更新后在写出到object,这样做我一直觉得特别低效。不过还好这个东西并不会涉及到lua交互而是批量更新。

动画方面,我实现了帧动画,以及尝试嵌入了spine这个骨骼动画插件。帧动画就是很简单的将一张纹理上的各个区域一直做变换,不停的播放。帧动画我实现了一个叫做clip的文件,这个文件记录一个动画clip的每一帧的信息,包括uv和帧数等等。然而在实际使用的时候,没有编辑器,手动修改大批这样的数据是及其痛苦的。关于骨骼动画,我使用了spine来嵌入,但是这个嵌入由于渲染部分的设计问题,效果并不是很好,由于我的每一个对象渲染出来都是一个矩形区域,所以我只能先将骨骼动画结果渲染到一个fbo上,然后由这个fbo渲染到矩形上,而问题就在于这个矩形区域又和碰撞矩形挂钩,而一个骨骼动画对象在运动时往往需要一张最大的矩形来容纳他的所有运动范围,所以这个矩形应该尽量能够框住整个运动对象,但是碰撞却不是,骨骼动画的碰撞需要拆分到各个部件来计算!所以无论我怎么修改骨骼动画的嵌入方式,也无法改善碰撞和渲染的耦合,唯一的方案就是重写。而这也是我放弃了wip的主要原因之一。后来我心血来潮在其中自己实现了一个骨骼动画系统,但是这个系统的设计是不完备的,也就是它只能播放骨骼动画,而没有考虑动画数据来源。

声音部分其实我不是很懂,我使用了OpenAL来驱动声音,而声音文件解析则采用了libogg。声音我基本上参考来参考去实现了流播放和整体加载播放的基本能力。剩下的研究就不多了。

其实在整个实现中遇到的最大问题还是文本渲染,首先我完全不懂文字的造型什么的,所以我使用了freetype,借助freetype造型好文字后,我则将其加载到纹理进行渲染。这个系统应该是最不完善的一个系统把。

UI系统本来最开始是没有的,但是我有段时间跟着老师做东西,做了个基于of的简uii系统。想了一下直接就把能用的控件移植到引擎中来了。UI部分还是基于回调的UI,思想比较老旧,但是基本能用。我在demo里面就展示了几个可用的UI控件。

其他的一些比较基础的库,算法数据机构上我一开始还在考虑要不要使用stl还是使用boost,但是后来发现一使用起stl就停不下来。数学库,则是我之前参考UE的数学库自己半抄半写的,因为总是读书少瞎想多,所以当年还真的特别担心完全自己瞎写数学库会拉低效率,然后想到UE的源代码,于是乎想到,UE用的方法应该不会低效吧,抄一个算了,也能学习学习,于是有段时间我就真的专心的去抄数学库了,不过恰好那段时间在学习3D数学,还是获益不少。然后是图片的解析我没有自己去折腾,而是采用了freeimage,这个库唯一的缺点就是大,其他的是还很方便全面。最后关于内存管理自己实现了一个简单的内存分配器,但是比较搞笑的是,这个管理器,我在我自己写的这些代码中并没有怎么使用,反而是我同学写的物理引擎用的多……但是后来出事了,在macos上这个内存管理器不能使用。

后来,我也曾今思考过将这个引擎移植到安卓或者ios上,有相当一段时间我都在做尝试,和一个懂苹果开发的同学搞了几天,解决了无数傻逼问题,最后在macos上跑了出来,但是却终究没有在osx上跑出来,安卓上,我也自己尝试了一下,感觉是还不如基于安卓重写来的快……

总之一句话,读书少而瞎想多

当初在做这个东西的时候,由于太年轻想的是将这个东西做成一个2D交互应用开发套件,最好的效果是能做做成一 个和Unity2D一样的东西。而当时看过的唯一一本书就是《Game Engine Architecture》,知道一个游戏引擎大概有哪些东西,但是这些东西具体怎么实现,则完全是一篇空白。尽管在后来的开发中,参考了cocos2d 和UE4,但是对原代码的解读都只是浅尝则止,没有深入的理解,往往是拿到一个概念,自己望文生义就乱实现。比如当时不知从什么地方了解到了多线程渲染这 个概念,于是想当然的设计了wip的多线程渲染系统,但是就是这个所谓的多线程系统导致现在整个渲染系统都像一只面目全非的怪兽。

WIP的Github

OSC镜像

【2D游戏引擎】WIP反思的更多相关文章

  1. 配置JDKAndroid 2D游戏引擎AndEngine

    配置JDKAndroid 2D游戏引擎AndEngine JDK全称为Java Development Kit(也即Java开发包),是用于支持Java 编程的基础.无论是什么编程,只要用到了Java ...

  2. Android 2D游戏引擎AndEngine配置环境

    Android 2D游戏引擎AndEngine配置环境 1.2  配置环境 在任何编程中,都需要一些软件或者硬件的支持.否则,没有硬件软件是不可能存在的,而想要编写对应语言的的程序,这需要对应语言库和 ...

  3. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:VisualStudio 2015 Language:VB.NET/C# 图形API:Win2D MSDN教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面 ...

  4. 发布HTML5 2D游戏引擎YEngine2D

    关于YEngine2D YEngine2D是一个开源的.采用HTML5技术和Javscript语言创建的2D游戏框架,用来构建web二维游戏. GitHub地址 最新版本 v0.1.2 浏览器支持 C ...

  5. UWP简单示例(三):快速开发2D游戏引擎

    准备 IDE:Visual Studio 图形 API:Win2D MSDN 教程:UWP游戏开发 游戏开发涉及哪些技术? 游戏开发是一门复杂的艺术,编码方面你需要考虑图形.输入和网络 以及相对独立的 ...

  6. 【2D游戏引擎】那些年对游戏对象的思考

    WIP源代码: Github OSC镜像 对象系统以对象为中心,对象系统的最基本设计策略是基于组件的设计.对象系统将尽量避免使用继承方式来拓展游戏对象,恰当的使用Mix-in来来最属性做拓展,单个属性 ...

  7. 变态版大鱼吃小鱼-基于pixi.js 2D游戏引擎

    之前用CSS3画了一条

  8. 八款常见的Android游戏引擎

    原文地址:http://bbs.csdn.net/topics/380203732 1.Angle  Angle是一款专为Android平台设计的,敏捷且适合快速开发的2D游戏引擎,基于OpenGL  ...

  9. 2016年 最火的 15 款 HTML5 游戏引擎

    HTML5游戏从2014年Egret引擎开发的神经猫引爆朋友圈之后,就开始一发不可收拾,今年<传奇世界>更是突破流水2000万!从两年多的发展来看,游戏开发变得越来越复杂,需要制作各种炫丽 ...

随机推荐

  1. Bash编程(3) 命令行解析与扩展

    $@表示脚本输入的全部参数,在bash脚本中,若$@增加引号("$@"),则包含空格的参数也会被保留,若不增加引号($@),则包含空格的参数会被拆分. 例: # sa脚本内容如下: ...

  2. 【STL】count_if

    功能 返回满足条件的元素个数 模版 template <class InputIterator, class Predicate> typename iterator_traits< ...

  3. Java 字符串(String)格式转json格式

    json是前后端传输数据的一种文本格式,json其实就是字符串,因为前后端传输数据时,只能传输字符串,我们又想传一些对象或者列表信息,这都是很常见的应用场景. 所以,我们需要在java代码中,把jav ...

  4. Firebird 条件函数

    1.iif  IIF (<condition>, ResultT, ResultF) 示例: select iif( sex = 'M', 'Sir', 'Madam' ) from Cu ...

  5. Magento 2开发教程 - 如何添加新产品属性

    添加产品属性是一种在Magento 1 和 Magento 2最受欢迎的业务. 属性是解决许多与产品相关的实际任务的有力方法. 这是一个相当广泛的话题,但在这个视频中,我们将讨论添加一个下拉类型属性到 ...

  6. linux环境的基本搭建

    1.准备Linux环境(我的是centos系统) 如果你是hadoop用户在使用sudo之前需要配置一下:获取sudo权限 切换到root vi /etc/sudoersroot ALL=(ALL) ...

  7. JavaScript数组循环遍历之forEach

    1.  js 数组循环遍历. 数组循环变量,最先想到的就是 for(var i=0;i<count;i++)这样的方式了. 除此之外,也可以使用较简便的forEach 方式 2.  forEac ...

  8. HDU 4283 (第k个出场 区间DP)

    http://blog.csdn.net/acm_cxlove/article/details/7964594 http://www.tuicool.com/articles/jyaQ7n http: ...

  9. express组件学习

    一.express 可以做:web application.api... 特性: 适合写简单的路由系统 集成很多模板引擎 中间件系统 二.请求与响应 var express = require('ex ...

  10. JavaEE之动态页面技术(JSP/EL/JSTL)

    动态页面技术(JSP/EL/JSTL) JSP技术 jsp脚本和注释 jsp脚本: 1)<%java代码%> ----- 内部的java代码翻译到service方法的内部 2)<%= ...