《游戏引擎架构》读书笔记(四)

《游戏引擎架构》读书笔记(一) 最近在读《游戏引擎架构》这本书,虽然感觉理论颇多,而且很多很多东西都看不懂,不过还是简单的把一些感觉很好的思想和方法或者概念记录下来。 1.      关于各个部件初始化,一个最简单粗暴的办法就是将各个部件按顺序排列起来,不但可以方便的看到初始化顺序,而且修改也十分容易。 2.      关于内存分配: a)        游戏中最常见的法则是-维持最低限度的堆分配,并且 阅读详情

一.游戏性系统

(1)游戏世界一般分为静态元素和动态元素,静态元素和动态元素有时候没有特别明显的分界线。但是静态元素消耗资源较少,可以用笔刷等工具绘制静态元素。

(2)游戏世界一般分为各个组块,如关卡,地图,地区等。建立在这之上的是高级游戏流程,即玩家的目标,比如任务。

(3)游戏动态元素通常以面向对象的方式进行设计,通常称为游戏对象(Game Object),实体(entity),演员(actor)或者代理人(agent)等。

         a)游戏对象通常会扩展引擎本身的语言,加一些高级功能比如反射,并且会提供脚本语言比如lua的访问。

         b)对象模型在有的引擎中可能会分为工具方对象模型和运行时对象模型,不过这两者一定有联系,甚至是相同的实现。

(4)数据驱动游戏引擎:当游戏的行为可以全部或者部分由美术和策划所提供的数据所控制,而不是由程序员编写的软件完全控制,该引擎就称为数据驱动。数据驱动可以减少迭代次数,不需要修改游戏本身的代码。但是数据驱动也有很大的代价,需要提供足够强大的编辑工具以及容错能力。但是不管怎么样,数据驱动也是为了使游戏开发更简单,而不要过于盲目的复杂化,记住Kiss原则。

(5)游戏世界编辑器,游戏世界编辑器包括但不限于下面的功能:

         a)世界组块创建及管理:levelsystem

         b)可视化的游戏世界:所见即所得的编辑最适合美术和策划的开发啦。

         c)导航:在编辑器中必须要有灵活的摄像机,有绕物体旋转和自由飞翔等不同模式。

         d)选取:一般是以光线投射的方式进行拾取。最好支持框选多选,然后以视图的或者树形图表示出来。

f)图层:在一些编辑器中支持自定义分组,能够独立载入一组图层,在不同的图层安排不同的内容。

g)属性编辑:选中游戏世界中的物体后,可以通过编辑器调节对象的属性。可以考虑增加公共属性修改,修改一个,相同类型对象的对应属性值全部修改。

h)特殊对象模型:比如光源,粒子发射器,区域,样条等本来在游戏世界中不可见的东东,我们可以给其增加一个实际的包围盒等,让其在世界中可见,方便移动操作等。

i)读写世界组块:当然,编辑这么多,还是要把编辑完的东西存起来,供引擎读写。有的引擎使用二进制文件,有的引擎使用XML等文本格式,有的引擎将所有信息存储在一个文件中,也有的分组块存储。

j)快速迭代:当我们修改游戏世界后,越早能看到修改的效果越好。这点感觉CE3做的很好,CE3的编辑器中按下Ctrl + G后可以立即进入游戏模式,测试效果。感觉这个真的是灰常灰常好的设定!!

k)集成的资产管理工具:游戏中所有需要使用的资源最好可以随时浏览,方便查看与编辑,更高级的就是可以直接在这个资产管理工具中直接进行相关修改。

 

二.   运行时游戏性基础系统

(1)运行时对象模型架构:

         a)以对象为中心的架构:每个游戏对象都是单个类实例,每个对象含有一组属性及行为,被封装在对象中。

          这种类型的架构最简单的就是单一庞大的类层次结构,一个基类,向下派生出N多子类。不过随着派生的层数越深,整个系统就越难理解维护和修改。(这里涉及到一个冒泡效应,即本来是下层类需要的功能,但是又增加了另一个类需要这个功能,为了适应这个功能,即把这个功能提到上层的类中,导致上层的类越来越庞大。)

         进一步的话,可以不仅仅扩展类的深度,而是从派生的宽度来扩展。不过这种情况容易造成多重继承,这个就比价麻烦了。

         更好的办法是使用聚合,而不是传统的继承方式。即使用Has a来代替Is a。将一些对象具有的功能提取出来,作为一个单独的类,然后游戏对象只要包含这个类的对象就具有了这种功能或者特性。

         聚合再进化一下,就变成了传说中的组件模型。各种功能和性质都属于一个组件,而GameObject是由若干个这样的组件构成。每个组件可以独立的维护扩充或者重构,而不影响其他功能。最简单的就是GameObject含有所有可能有的组件的指针,在初始化的时候可以根据参数甚至是配置文件来决定这个对象需要哪些组件。

         组件的终极进化的话就是只有组件没有GameObjec,或者GameObject中只包含一个GUID,这些组件中也包含GUID,不过还是有GameObject好一点,如果没有这个,组件间的通信等问题就会比较棘手。

         b)以属性为中心的对象模型架构:

这种的话,主要就是存储各个对象的各个属性,这些属性都存储在同一个地方,通过对象的唯一索引来获得这个属性。与对象为中心的架构的区别在于:这种情况为数组的结构,即整个游戏的对象属性为一个结构体,而该结构体的每个子项都是一个数组,通过各个对象的索引获得该值。而对象为中心的情况则为结构的数组:每个对象的属性为一个结构体,整个游戏世界是有这个结构体的数组构成的。

(2)世界组块的数据格式:

对于游戏世界中的各种东东,我们在编辑器中编辑好之后,都需要存储起来,并且在游戏引擎中重现出来。有二进制的序列化方式,但是更好的方法是只存储游戏状态属性到文本文件中,比如XML文档。

由于C++没有反射机制,所以对于创建对象通常采用类工厂等方式,根据数据表创建不同的类对象。

         在编辑器中需要和游戏中有相同的表现,有时候是将引擎的接口直接暴露给编辑器,这样的好处是编辑器和游戏世界中完全一样,而且减少了工作量,更有可能直接在编辑器中开启模拟游戏的方式(比如CE3)。有时候,如果不需要其他的功能,也可以直接使用生成器,即将引擎中的对象的一部分属性等提取出来,不必要的不添加到编辑器中。

         对于各种对象的属性最好添加一个默认的属性,而且需要提供一次性修改所有对象属性的方法。

(3)游戏世界的加载和串流:

a)  简单的关卡加载:一般使用堆栈分配器,进入一关前,集中加载本关的资源,使用完后,直接全部清除,然后进入一个过场画面(loading界面),等资源加载完成后,继续游戏。

b)  阻隔室:这个是为了避免加载动画使用的一种简单的方法,不过需要配合游戏的玩法。最简单的办法是将为资源分配的内存分为两块,一块为当前场景的,然后在后台加载下一个关卡的。而如果玩家返回原来的场景就会穿帮…而阻隔室就是应对这种情况的。当玩家进入阻隔室后,原来的资源卸载,加载新的资源,让玩家在阻隔室不要闲下来就好。

c)  游戏世界的串流:这个技术赶脚吊炸天啊…

串流需要做的是一方面保证玩家要玩的资源在内存中,另一方面还需要保证资源加载不能出现内存碎片的问题。这时就需要更细的粒度,设置多个缓冲区,循环加载。

在每个组块设置一个包围盒,保证玩家不会看到穿帮镜头。

 (4)对象生成和内存管理:

         游戏资源载入内存后,需要管理世界对象中的对象生成。而动态分配内存可能很慢,而且游戏对象大小不同,可能会造成内存碎片。所以内存管理是很重要的。

a)  对象的离线内存分配:说离线其实是一种极端情况,这种分配的特点是一次性全部分配内存,然后不需要的对象保持为休眠状态或者不可见。使用时再激活,模拟生成的情形。但是这种方法比较死板,不能真正的动态生成对象。

b)  动态内存分配:主要要对付的问题就是内存碎片的问题。

对于相同大小的对象,可以采用池分配器。但是游戏对象各种各样,所以一种方法是采用多种池分配器,为每种对象设置一个池分配器。不过这个需要把握好,防止有的对象内存池不够,而有的对象内存池剩余。

另一种方法是采用类似操作系统的内存分配模式,设置一组内存分配器,从小到大,遇到需要分配的时候,先从小的找起,直至大的,如果还没有,直接转堆内存,因为大块内存碎片问题相对小块内存碎片还不是那么严重。

最残暴的一种方法就是内存重定位,隔一段时间,将内存整理一下。

(5)游戏存档:

a)存档点:这个的好处在于玩家到达该存档点时,游戏状态是确定的,所以存档的内容可以相对较少。

         b)任何地点都可以存档:这个难度就要比上个大了,存储的状态也要多许多。

不过不管是哪种情况,都要注意尽可能的不存储无关信息。

(6)世界查询:

游戏对象需要提供某种唯一标识符,使各种对象能够区分,并且能在运行时找到对象。而找到对象的需求也不同,比如直接查询,搜寻范围内的敌人等等。

a)  以唯一标识符搜寻游戏对象:将游戏的指针或句柄存储于以游戏的唯一标识符为健值的散列表或者二叉查找树中。

b)  将游戏对象预先排序,存储在不同的链表中。比如玩家周围的怪物链表。

c)  搜寻投射路径碰撞物体:通常使用碰撞系统实现。

d)  搜寻空间中的某区域范围内的对象:可以使用一些空间散列数据结构去存储游戏对象,或者使用传说中的四叉树,八叉树等等。

(7)对象引用:

a)最简单的就是使用指针,不过指针也有危险的地方,容易造成孤立对象,或者空指针异常,无效指针等等问题,所以在使用指针的时候要格外小心。

b)更保险的做法是使用智能指针,智能指针一般采用引用计数,并且添加了一些判空操作。智能指针实现比较简单,但是要实现得完整却比较复杂,强烈不推荐自己实现。使用boost库为我们提供的智能指针也可以。

c)更加高级的办法是使用句柄,句柄其实就是一个索引表,内部保存的还是游戏对象的指针,不过这个索引表可以加入更多的东西,而且这个索引表也可以作为游戏世界的索引表。

(8)实时更新游戏对象:

         游戏运行时需要实时的更新游戏内部的对象的状态,一般就是对象的属性。说是实时更新,其实还是连续的离散的时间点。

a)  最简单的方式是遍历:每个对象有一个update()的虚函数,通过多态调用,将游戏对象的状态更新到下一个离散的时刻。并且传递给其一个距离上一帧的时间差,使对象可以考虑已经流失的时间,对将要做出的操作进行判断。

而怎样管理游戏对象也是一个问题,一般的游戏都有一个GameObjManager单例,如果有动态生成对象的功能,则就需要用类似链表的数据结构管理对象,而如果没有动态生成对象的话,就用数组就可以管理游戏对象。

使用直接遍历的方式,所有的操作都集中在对象的update函数中,但这不是一个好办法。

b)  性能限制及批次更新:将对象的逻辑属性更新,各个子系统的功能不在对象的update中更新,对象仅仅更新关于子系统功能的状态值,然后所有对象更新完后。按照顺序,更新各个子系统。

这样做的好处在于:子系统缓存一致性,进行最少的重复计算,减少资源的再分配,高效的流水线。

对于更新时,有可能会有对象间的相互依赖,这时候就需要按照批次顺序来更新,或者将一组相关的对象一起更新。

但是有个问题就是有可能这个对象的状态是上一帧的状态,但是在本帧状态还未更新,比如现在更新状态,更新到A了,B还没有更新,A需要查看B的状态,B的状态是上一帧的状态。一个好的方法是加上时间戳,让对象查询对象的时间戳,来判断是上一帧还是本帧。

关于游戏更新还有要注意的就是不要使用阻塞型函数,要尽可能使用非阻塞型函数,把阻塞的功能放到另一个线程去做。

(1)      事件与消息泵:游戏是由事件驱动的,事件是游戏过程中发生,希望关注的事情。事件处理系统很重要,主要做的是两件事:第一是将事件通知给那些关注该事件的对象,即所谓的消息分发。第二是安排对象回应所关注的事件,即所谓的事件处理。

 

a)  最简单的办法是采用函数绑定:给每个对象加一个对应事件的响应函数,在基类设定一个虚函数(或者空实现的),子类继承这个虚函数,然后轮询每个子类,看是否需要响应这个消息。但是这样做弊端很大,基类需要对所有类型的事件都有对应的函数,扩展十分困难。再者,不是所有消息都需要轮询的,所以这样做也不合适。

b)  更好的方法是把事件封装成对象:事件对象由两部分构成,一部分是事件类型,另一部分是参数。有些引擎将事件称之为命令,事实上,将事件发给对象,实质上就是向对象发送命令。

将事件封装成类有很多好处:第一是单个是事件处理函数,仅需要一个虚函数OnEvent就可以处理所有的事件。第二,像上面的函数调用是瞬间的,而事件有持久性,可以存储在队列中,稍后处理,也可以用于广播。第三,事件可以被转发,而转发的对象可以不需要知道事件的具体内容。

c)  事件类型:最简单的事件类型定义的方法就是在一个文件中,把所有游戏中需要的事件类型定义了,用一个枚举类型映射至唯一的整数。这样做一是方便统一管理,二是比较简单,三是开销小。But也有很多缺点,第一,破坏了封装性,第二,事件类型是硬编码的,不利于扩展,第三,枚举的索引是次序,如果添加了新的事件类型(在中间插入的),那么次序就会改变,如果在游戏中对应的话那是没有问题的,但是,如果还有文件中存储与之对应的内容的话,次序就会错乱。所以,枚举类型统一定义事件类型,在小型程序中很好,但大规模或利于扩展的程序中不适合这种。

另一种事件对应方式是字符串,这种方式扩展很自由,但是有几个问题,第一,开销大,第二,容易产生命名冲突,第三,容易出现拼写错误。解决性能问题的话,可以采用字符串散列标识符。但是命名冲突的话,就需要额外注意了。或者增加一个判断重复的操作。

d)  事件参数:事件的参数和函数参数类似,可能有多个,也可能有不同类型的参数。

最简单的方式是基类木有参数,仅有消息的类型,对应无参数的命令。而其他类型的消息作为该类的派生类,然后将参数硬编码到其中。

第二种方式是使用variant集合,存储多种数据类型。最麻烦的方式是使用键值对作为参数,可以避免参数顺序的问题。

e)  事件处理器:当游戏对象接受了一个命令,就要以某种方式进行回应,称为事件处理。事件处理器通常是一个原生的虚函数或者脚本函数。能处理所有的事件,通常包含一系列的switch语句。

事件处理器需要取出事件提供的参数,参数有两种方式,第一种是由消息包本身附带提取参数的函数,不过这样做不太好,因为基类的消息包需要含有所有消息包的提取虚函数,换句话说,消息包本身需要对功能结构了解。第二种是处理函数手工提取消息,并将其转化为需要的类型,这样有可能会有安全问题,但是既然知道是什么消息包了,处理好就不会有问题。

职责链:游戏对象几乎都要有依赖关系,对象关系中转发事件是一种常用的设计模式,称之为职责链。职责链要处理这样一件事:当一个事件发给链头时,链头先自己进行判断,自己是否需要处理,然后判断是否需要向下转发,可以进行继续转发,也可以把消息包吃掉,不再转发。

事件转发也用于多播,比如爆炸发生时,需要把事件传递给范围内的多个对象。过程是先查询范围内的对象,然后把事件发送给这些对象。

登记对事件的关注:大部分对象都不需要接受所有的事件,只会关注一小部分事件的集合,所以多播或者广播就是很低效的事。进行登记的话,简单的方式是事件类型包含一个链表,内部维护关注该事件的对象,或者每个对象维护一个数位组,每一位表示该对象是否关注某种事件,再或者要发送事件前的查询缩小范围,仅查询要关注该事件的对象。

关于事件队列:引擎要提供立即处理刚刚发出事件的机制,除此以外,还有的提供了事件队列,可以将事件缓存起来。这样做增加了灵活性,但是也增加了复杂性。不过个人感觉事件队列还是很有用的。好处如下:第一,可以控制事件处理的时机,有些需要立即处理,而有些则不着急,那么可以搞一个慢速队列存储这些不着急的东东,而且处理的顺序我们也可以根据权值进行排序,或者插入的时候直接按照顺序插入。第二,甚至可以向未来投递事件,消息包中设置一个投递时间,可以延后几帧或者几秒处理,甚至可以处理完再发送一个相同的包达到周期性的效果。这需要在事件包中加入一个时间戳,仅当游戏时间大于等于该时间,才进行处理。使用优先队列或者插入时进行排序,这样,处理完前面需要处理的事件之后,后面的就不需要处理了。每帧至少调用一次事件分发队列,至少会处理一次。而事件的优先次序也是很重要的,因为时间会量化为帧数,那么在同一帧的事件就是相同时间了,消除这个歧义的方法是设置事件的优先次序,可以更好的控制事件处理顺序。

         当然,事件队列也会带来一系列的问题。第一就是复杂,这个没什么说的了。第二,正常我们处理一个事件,可以在产生事件时,设置一系列参数,然后传递这个对象的引用到事件处理系统,由于没有出作用域,在处理完事件后,事件本身才会被销毁,但是,如果放到队列中,就涉及到一个问题,函数作用域结束了,队列中的事件也就没了,保留的仅是一个空的引用,所以就需要进行深复制,这就涉及到动态内存分配,而动态内存分配又有可能导致内存碎片,需要内存池分配器。(不过我在想,可不可以在事件处理队列中,不使用引用,直接采用值传递进行呢?虽然会有开销的问题,但是把事件直接建立在队列中,不是和之前的在外部建立一个对象一样嘛,而且还省去了管理内存的麻烦)第三,就是调试困难,事件的发送和处理不在一起,甚至不在一帧,这个肯定调试起来麻烦得多。

         而非排队的事件处理系统也是会有问题的,就是可能会导致堆栈调用非常深,甚至达到栈溢出的情况。

         总之,事件处理系统非常非常的灵活,比直接使用C/C++的对象关联能做的事多得多,也灵活得多,但是上面的那些做法还是不够灵活,更加强大的是真正的使用数据驱动事件传递系统,不使用硬编码,在编辑器中对对象,提供各种选项,使之能响应不同的事件。一种做法是提供脚本语言接口,可以定义不同的事件类型,提供脚本回调等等,更加牛的一种方式是提供流程图,连接流程图来定义对象流程。这种流程图的话,一个事件可能对应很多响应对象,但是事件本身可能并不知道,一种方法是将事件类型去掉,给对象提供一个输入端口,然后事件连接这个端口,如果端口中输入了特定的消息,那么就进行相关的处理操作。

f)  脚本:

脚本可以让引擎用户进行简单编程,来控制引擎,比如加个Mod之类的,是很方便的一种方法。

脚本分为两种,一种是定义数据的,用于读取数据,相比硬编码更加灵活。而另一种才是真正的脚本,可以控制程序的流程,脚本可以在游戏流程中执行。

脚本语言一般采用解释型语言,由一个虚拟机解释脚本语言,这种虚拟机一般比较轻量,支持快速迭代,不需要重新编译程序,修改之后立刻就能看到效果,而且比较简单易用。

         脚本所需要的架构:

1.      回调脚本:在这种架构下,引擎的主要功能大部分是由原生编程语言硬编码的,只有关键部分的小功能设计成可定制的,这些部分一般设计成回调脚本,即脚本写出来的函数,由程序调用。比如更新对象的时候,写一些可选的功能,这些功能采用脚本回调。这个回调函数可以由原生语言写,脚本控制用不用,也可以直接用脚本语言回调。

2.      事件处理器脚本:也是一种特殊的钩子函数,作用是令游戏对象回应游戏世界发生的相关事件,或者回应引擎本身的事件。

3.      以脚本扩展游戏对象类型或者生成新类型:把脚本绑定到游戏对象上,根据继承或者聚合来控制游戏对象类型。

4.      组件或属性脚本:在基于组件模型的对象模型中,需要用脚本来决定对象需要哪些组件,这样才能灵活的控制生成对象的类型和拥有的属性。

5.      脚本驱动的引擎系统:可以用脚本驱动整个引擎的运作,比如对象模型完全用脚本编写,仅当需要一些底层功能时才使用原生引擎代码。

6.      脚本驱动的游戏:原生代码仅作为程序库,脚本代码是游戏运行的主体。

脚本需要的功能:

1.      和原生语言相互调用:脚本语言调用原生语言,原生语言也能调用脚本语言,这样就能非常灵活的控制游戏的进行。

2.      游戏对象的句柄:由于脚本语言不能直接操作原生语言中的指针,所以怎样获得一个游戏对象就需要考虑了,一般是使用句柄来引用游戏对象。句柄的话,之前也提到过,一种是使用数值型GUID,虽然占用空间小,但是不够直觉,比如想直接用脚本操作某个对象,找不到GUID就比较麻烦。另一种是字符串型句柄,这种就很直接了,想要用脚本进行某个操作的话,直接使用对象名称即可操作对象。但是这样做就有性能的代价,字符串肯定慢得多,而且如果有人修改了编辑器中的对象名,而没有修改脚本中的名称的话,就有可能出现问题。还有一种折中的办法,就是使用字符串散列标识符,既能像字符串那样阅读,又能有整数那种运行时的性能。

3.      接收及处理事件:事件处理是引擎的核心功能之一,如果将事件处理交给脚本的话,那么就能更加灵活的控制游戏的流程。事件通常关系到一个对象,有的引擎采用一类对象绑定一类脚本的办法,但是这个是灵活的,比如一类对象用同一种脚本,然后每个对象可以绑定特定的脚本,提供各种脚本作为组件供调用。脚本当然不仅仅是绑定在对象上的,绑定在引擎本身处理引擎的事件,或者绑定在一个区域,或者作为独立的Trigger等等。更加灵活的就是,采用状态机的思想,脚本分为不同的状态,进行不同的操作。或者当有事件发生时,可以考虑采用原生的语言处理,也可以选择使用脚本,通过状态机进行判断,如果是这个状态,执行脚本,否则忽略脚本。

4.      发送事件:引擎调脚本处理已经很灵活的了,那么脚本反过来调用引擎无疑是更加灵活。脚本可以向引擎传递引擎中定义好的消息,然后引擎进行处理。甚至可以这样,脚本完全定义新的事件类型,另一个对象的脚本定义接受这个事件类型的方法,那么就完全实现了脚本之间的控制,灵活度更高。

最后一种就是一个高层次的脚本,说是高层次其实也不算,不是控制引擎的,而是控制任务系统的脚本,这个系统通常实现为一个状态机,每个状态表示玩家的任务目标,这种脚本控制游戏在失败时或者达成任务时会发生什么。更高层的就是并行任务系统,这种就不能用简单的状态机来实现了。

 

 

三.其他内容:

最后一章了,这章主要介绍了一些其他的引擎需要的部件,虽然不如上面那些重要,但是也是必不可少的部件:

a)音频系统:游戏世界的第四维度

b)视频接口:CG动画棒棒哒

c)网络接口:网游辣么火,当然必不可少了

d)玩家机制:游戏是很多对象的集合,但是我们控制的人物才是最重要的,也是最核心的部分。

f)摄像机:摄像机是我们观察游戏世界的窗口,其重要程度可想而知。游戏一般有这几种摄像机:

         1.注视摄像机:围绕一个物体旋转,并且可以拉远拉近

         2.跟随摄像机:常用于平台游戏,第三人称游戏,赛车类游戏,聚焦于玩家本身,需要注意的就是摄像机本身的碰撞,不要出现穿过物体的穿帮镜头,而且还要给玩家一定调节摄像机操作的灵活度。

         3.第一人称摄像机:这个是第一人称游戏的必备之物,固定于角色的眼睛位置,可以通过鼠标进行控制摄像机的方向。

         4.即时战略类摄像机:传说中的上帝视角,可以模拟浮于地形上的摄像机,角度朝下,玩家可以控制摄像机在地形上水平移动,但是不能控制摄像机的偏航角和俯仰角。

5.电影摄像机:track view,比如播放剧情时,运镜效果。

g)人工智能:这个也是游戏中的一个大头。AI主要包括:寻路,感知系统,视线系统,环境理解,记忆功能等等。

h)其实游戏世界远远不止这些,我的感觉,游戏就是一个世界,现实中有的,游戏中都可以有,游戏开发永无止境!

 

 

 用了一个半月时间,终于把这本书读完了,感觉真的是一本好书,让我真正知道了游戏引擎都包含哪些内容,感觉游戏真的是深不可测,真的由衷的佩服那些写出引擎的大牛们。

 

《游戏引擎架构》读书笔记(二) 一.调试技巧及工具 (1)基础调试 a)   日志及追踪,有些bug难以用VS自带的调试来进行单步调试,最好的解决方案就是printf调试法,打印一组数据,观察情况。之前我的做法是单独生成一个控制台,不过VS自带了一个OutPutDebugString()的方法,可以打印调试信息。不过这个只支持char*内容,我们可以将这个函数加工一下,使其支持不同类型的数据,甚至可以使其接受可变参数个数。 阅读详情

相关推荐

[读书笔记]<游戏引擎架构>|仿射矩阵

仿射矩阵

菜鸟的试炼 949

游戏引擎架构【笔记二】

1.5 的部分是关于游戏引擎的介绍

packdge_black的博客 1117

VisionMaster位置修正功能深度解析:如何让找圆工具自动跟随移动目标?

本文深度解析海康威视VisionMaster平台的位置修正功能,重点介绍如何通过模板匹配与找圆工具的智能联动实现移动目标的动态追踪。文章详细阐述了工业视觉检测中的坐标系同步原理、模板匹配配置技巧及异常处理策略,为工程师提供了一套完整的工业级解决方案。

uu89012的博客 281

UE4(一):游戏起点流程图

UE4游戏流程图,来源于UE4官网

weixin_44200074的博客 2610

Halcon图片拼接避坑指南:特征点匹配常见问题与解决方案

本文深入解析Halcon图片拼接中特征点匹配的常见问题与解决方案,涵盖特征点提取、匹配优化及变换模型选择等关键环节。针对工业视觉检测中的拼接错位、重影等问题,提供参数调优、图像预处理和算法选择等实战技巧,帮助开发者高效避坑并提升拼接精度。

weixin_28694169的博客 198

RK3588嵌入式开发:从零构建Rockit多媒体处理引擎的实战指南

本文详细介绍了如何在RK3588嵌入式平台上从零构建Rockit多媒体处理引擎的实战指南。涵盖开发环境搭建、工具链配置、源码编译流程、硬件加速优化及典型问题解决方案,帮助开发者高效利用RK3588的NPU和VPU加速特性,实现高性能多媒体处理应用。

mango的博客 186

【GAMES104】Lecture2-游戏引擎五层架构

游戏引擎由工具架构和运行时组件组成(Tool+RunTime),继续细分又可以把运行时组件分为4层。故总体是五层架构。本文通过对这五层架构的功能进行简要概括和举例说明的方式来阐明游戏引擎的基本架构

Talk is cheap. So look at my blog. 6666

Unity中5自由度机械臂运动控制与夹爪交互仿真实践

本文详细介绍了在Unity中实现5自由度机械臂运动控制与夹爪交互仿真的完整流程。从模型导入、物理组件配置到关节运动控制算法(包括逆运动学IK),再到夹爪抓取逻辑和工业分拣案例实战,提供了可落地的代码示例与性能优化方案,助力开发者快速掌握机械臂仿真核心技术。

weixin_29021757的博客 446

游戏引擎架构-学习笔记

5 游戏支持系统 5.1 子系统的启动和终止 5.1.1 c++的静态初始化次序 5.2 内存管理 5.2.1 优化动态内存分布 5.2.2 内存碎片 5.2.3 缓存一致性 7 游戏循环及实时模拟 7.1 渲染循环 7.2 游戏循环 7.2.1 游戏循环的架构风格 1. 视窗消息泵 2. 回调驱动框架 3. 基于事件的更新 7.3 抽象时间线 7.3.1 真实时间线 7....

XIANG__jiangsu的专栏 4828

逆向实战:如何绕过iTunes 12.6.5.3的反调试机制(附X64dbg插件配置)

本文深入剖析了iTunes 12.6.5.3的反调试机制与登录协议。通过X64dbg动态调试与IDA静态分析,详细演示了如何绕过其反调试检测,并定位到核心的登录协议加密函数,揭示了其请求签名(X-Apple-ActionSignature)的生成逻辑与依赖关系,为客户端安全研究与协议分析提供了实战思路。

weixin_29202213的博客 740

用Python+OpenCV给斗地主做个‘外挂’:手把手教你写个桌面记牌器(附源码)

本文详细介绍了如何使用Python和OpenCV开发一个智能斗地主记牌器,包括环境搭建、图像采集与预处理、扑克牌识别技术及PyQt5界面设计。通过实战案例,帮助开发者掌握图像处理与界面开发的结合应用,提升游戏辅助工具的编写能力。

weixin_29079643的博客 543

如何开发一款游戏:游戏开发流程及所需工具

本文来自作者goto先生在GitChat上分享 「如何开发一款游戏:游戏开发流程及所需工具」,「阅读原文」查看交流实录。「文末高能」编辑 | 哈比游戏作为娱乐生活的一个方面,参与其中的人越来越多,而大部分参与其中的人都是以玩家的身份。他们热爱一款游戏,或是被游戏的故事情节、炫丽的场景、动听的音乐所艳羡,亦或是被游戏中角色扮演、炫酷的技能、有趣的任务所吸引,然而他们中的大多数可能并不了解如此

技术杂谈 10万+

24届数字IC设计/验证秋招总结贴——先看这个

为方便快速进行查找该专栏的内容,将所有内容链接均放在此篇博客中整理不易,欢迎订阅~~

qq_42135020的博客 8406

《游戏引擎架构》读书笔记-游戏引擎中的C++

《游戏引擎架构》在两年前就买了,而且自己也大体的看过一遍,因为自己想学习引擎的底层知识,所以重新又找出了这本书再读一遍,并把根据自己的理解写一些读书笔记在这里与大家交流。       闲话少续,开始本篇的内容,这本书的第一部分是基础篇,第一章概述了一些引擎概念,第二章讲解了一些工具的用法(Visual Studio等),第三章介绍了C++,和一般的C++书不一样的是,本书讲解的C++应该更多的是引

手机游戏开发学习笔记 4015

如何在 R 中执行 Kruskal-Wallis 检验

Kruskal-Wallis 检验用于确定三个或更多独立组的中位数之间是否存在统计学上的显着差异。它被认为是单向方差分析的非参数等效项。本教程介绍了如何在 R 中执行 Kruskal-Wallis 检验。示例:R 中的 Kruskal-Wallis 检验 假设研究人员想知道三种不同的肥料是否会导致不同水平的植物生长。他们随机选择 30 种不同的植物并将它们分成三组,每组 10 株,每组施用不同的肥料。在一个月结束时,他们测量每株植物的高度。使用以下步骤执行 Kruskal-Wallis 检验以确定三个组的中

Mrrunsen的博客 3796

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

《游戏引擎架构》读书笔记(三)

一.动画系统 (1)动画系统的演变: a)传统的帧动画:2D游戏中,将动作逐帧播放。好吧,我只停留在这个水平。 b)动画纹理:与帧动画差不多,使用面向摄像机的四边形,贴上一连串的纹理。虽然很挫,但是现在仍有应用,特别远距离的物体还是可以使用这种动画方式的。 c)刚性阶层式动画:将角色拆分为各个部分,可以按照关节运动,但是由于是刚性运动,三角形不会有所拉伸,因而会有“裂缝”,看起来不是很真实

puppet_master的专栏 1100

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

游戏引擎架构 读书笔记(一)第一章 导论

游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些交互式实时图像应用程序的核心组件。 游戏引擎包含以下系统: 渲染引擎(即“渲染器”,含二维图像引擎和三维图像引擎)、 物理引擎、 碰撞检测系统、 音效、脚本引擎、电脑动画、人工智能、网络引擎以及场景管理。 对于游戏开发者来说,引擎可以理解为一个封装好的盒子,它的功能是提供调用接口,好让一些复杂的事情通过这个盒子之后变的简单。 常见的游戏引擎有...

【黑键】 1783

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

《游戏引擎架构》

《游戏引擎架构》 基本信息 作者: (美)Jason Gregory(杰森.格雷戈瑞) 译者: 叶劲峰 出版社:电子工业出版社 ISBN:9787121222887 上架时间:2014-1-20 出版日期:2014 年1月 开本:16开 页码:800 版次:1-1 所属分类:计算机 > 游戏 > 综合 更多关于》》》《游戏引擎架构》 编辑推荐...

weixin_30791095的博客 285

游戏引擎学习笔记:介绍,架构,设计及实现

By Long Luo 从小到大,虽然玩过的游戏不少,但是从写程序开始,目前为此仅仅写过2个游戏。其一是2011年在MTK平台下写的贪食蛇,其二是2010年在嵌入式开发板上写过一个迷宫的游戏。第一个代码量大概有3000行左右,第二个有2000行左右。 这2个游戏都很简单,而且网上有很多现成的例子可供参考,因此难度也比较低。 这2天把拖延了好久的《Android应用开发揭秘》的游戏

TCP/IP协议栈学习ing 9419

Unity3D脚本编程读书笔记——第1章 Hello Unity 3D(认识Unity3D游戏引擎)

本文的核心内容在于纵览Unity3D游戏引擎的发展历史,以及介绍作为一款通用游戏引擎,Unity3D的引擎架构是怎样的。

xcinkey的博客 2357

[读书笔记]游戏引擎需要关注什么?

一、游戏引擎的几大块 1、光影效果,即场景中的光源对处于其中的人和物的影响方式。游戏的光影效果完全是由引擎控制的,折射、反射等基本的光学原理以及动态光源、彩色光源等高级效果都是通过引擎的不同编程技术实现的。 2、动画,目前游戏所采用的动画系统可以分为两种:一是骨骼动画系统,一是模型动画系统,前者用内置的骨骼带动物体产生运动,比较常见,后者则是在模型的基础上直接进行变形。引擎把这两种动画系统

【石】黑水晶 1302

游戏引擎架构 个人笔记 2.2.1-2.2.3章节

[游戏引擎架构 个人读书笔记 2.2.1-2.2.3章节] 个人读书笔记:只根据自己的情况写下自己关心的部分。 => 编译器(compiler): 每次只翻译一个cpp => To Object File i: 可重定位:未决定代码的内存地址 :p ii: 未链接:未解决外部函数和全局数据 :p 我(Object File)~ 只...

weixin_30824479的博客 86

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

Koan《iphone游戏开发》 读书笔记之一:游戏引擎揭秘 2011年09月01日   本人做的读书笔记,版权归《iphone游戏开发》作者:[美]Paul Zirkle Joe Hogue 著 张龙 译,如作者及译者认为侵犯版权,本人马上删除该笔记,另外,转载慎重,因为版权非本人。。   游戏引擎的组成:应用框架、状态机、图形引擎、物力引擎、音频引擎、游戏输入以及游戏逻辑等。 ...

ttl04ttl 278

[读书笔记]<游戏引擎架构>|管理器的启动与终止

每个游戏都会包含一些底层支持系统, 例如资源管理器、日志系统、对象池、动画管理器、音乐/音效管理器等。这些管理器通常是一个单例类,如下面这段代码:class ResourceManager { private: static ResourceManager* m_pInstance; public: static ResourceManager* get() {

菜鸟的试炼 506
上一篇: GitHub使用详解
下一篇: 在VS2012中使用GitHub
puppet_master
puppet_master 领域专家: C/C++技术领域 领域专家: C/C++技术领域
博客等级 码龄12年 2695粉丝 161原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值