射击游戏项目开发笔记 (一)

目前我使用的引擎对代码的编码方式有了非常严格的控制,一般的C++写法已经无法在引擎中运行了,由于目前项目准备使用protobuf来作为通讯数据,所以我必须实现一个动态解析protobuf的库,考虑到已经有人做了一个事情,而且做得很好(https://github.com/cloudwu/pbc),所以我就把云风大侠的c版本移植到目前使用的引擎上来.这篇文章主要记录的是一些修改事项和protobuf的一些基本内容,并非使用教程.

简要说明

protocol buffers是google提供的一种将结构化数据进行序列化和反序列化的方法,其优点是语言中立,平台中立,可扩展性好,目前在google内部大量用于数据存储,通讯协议等方面。PB在功能上类似XML,但是序列化后的数据更小,解析更快,使用上更简单。用户只要按照proto语法在.proto文件中定义好数据的结构,就可以使用PB提供的工具(protoc)自动生成处理数据的代码,使用这些代码就能在程序中方便的通过各种数据流读写数据。PB目前支持Java, C++和Python3种语言。另外,PB还提供了很好的向后兼容,即旧版本的程序可以正常处理新版本的数据,新版本的程序也能正常处理旧版本的数据。

ProtocolBuffer是用于结构化数据串行化的灵活、高效、自动的方法,有如XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。

继续阅读

开发日志系列(十五)

在做游戏剧情展示的时候遇到一种需求把游戏对话逐字显示给玩家,效果如下:

malu

实现这种效果的方式就是把一个字符串逐个中文取出来刷新到屏幕上,研究了各种编码之后发现UTF8的编码非常简单 也很容易逐个/中文/英文/符号 读取.首先看看UTF8非常简单的编码方式:

  1. 对于单字节的符号,字节的第一位设为0,后面7位为这个符号的unicode码。因此对于英语字母,UTF-8编码和ASCII码是相同的。
  2. 对于n字节的符号(n>1),第一个字节的前n位都设为1,第n+1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进制位,全部为这个符号的unicode码。

UTF8编码规则

Unicode符号范围 UTF-8编码方式
(十六进制) (二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

继续阅读

C++Primer中并没有对const过多的解析,只说明为是一个使变量不可修改的限定符.但是仅仅知道这点对于我来说是远远不够的,const是怎么做到的限制修改?谁在帮const做这个限制?编辑器是怎么实现不可修改的?在认识const之前 我知道C++中唯一不可修改的就是常量,例如:

int i = 1000;

这个1000就是常量,除了修改生成的文件之外 任何方式都无法修改这个1000 .(修改生成的文件是怎么修改?例如生成了exe可执行文件,直接定位到代码区 找到这个变量定义的地方 把 1000的字节码E8 03 00 00改了..).

继续阅读

开发日志系列(十二)

环境: cocos2d-x 2.2.3 , win7

碰撞相信大家都不陌生了,无论在手游的游戏按钮对触摸事件的响应 还是页游时代游戏按钮对鼠标点击事件的侦听,都需要使用碰撞来判断.例如以下一个按钮,规格为:200X200,第二张图绿色部分原本为透明

按钮的原图

ButtonHasAlpha

绿色为透明部分

ButtonNoAlpha

坐标矩阵碰撞

类似这样一个按钮 如果是单纯使用坐标碰撞的话,只要坐标落在按钮图片内部,就会判断为点中,在cocos2d-x中坐标碰撞的一般做法是:

//pt 为鼠标 或者 触摸 击落时候的屏幕坐标
//cc  为按钮对象 继承CCNode
CCPoint pos = cc->convertToNodeSpace(pt);
CCRect rect = cc->boundingBox();
rect = CCRectApplyAffineTransform(rect, nodeToParentTransform());
if (rect.containsPoint( pos ))
{
    printf("用户点击了cc");
}

继续阅读

开发日志系列(十一)

目前我参与的项目中使用了大量的接口调用,大量的继承(多重继承,多重派生等),其中的大部分都是使用了C++语言的动态绑定特性.既然有动态绑定,哪就相应的肯定有静态绑定,今晚复习了下这个特性.

静态绑定与动态绑定

静态绑定又名前期绑定(early binding),绑定的是对象的静态类型发生在编译期.动态绑定又名后期绑定(late binding),绑定的是对象的动态类型,发生在运行期.简单的说就是:静态绑定在编译完成后已经确定,动态绑定则需要在运行的时候才确定.考虑如下继承:

继续阅读

项目开发日志(九)

在我参与的项目中的实体管理系统据说经过了很多游戏的磨练,本身已经很复杂,我只能记录我的理解,可能在往后的日子里有更深入的理解后会修改下面的一些认识.关于实体系统我可能会分比较多的部分来慢慢说,目前能想到的内容会有:实体对象的设计原则与继承关系,实体对象的属性分配,实体对象的消息.

  • 游戏实体对象

游戏实体系统在游戏编程系列著作< 游戏编程精粹四>中提及.以下摘抄一小段:


现代游戏充满各种各样的实体,玩家,敌人和发射的炮弹.这些要素在游戏世界里乱哄哄的跑来跑去,地形,建筑物,天空和云彩的定义环境.路径点(waypoint),触发器和脚本指导玩家体验.得分,破坏和无力方面组成游戏世界的逻辑和规则.不是对所有东西分别对待,作为特殊目的的要素,把他们结合为一个系统并且提供一个公用的结构和通信方法是很方便的,基于消息的方法来管理实体能够解决很多问题并提供一种方法统一大部分的关键游戏要素 – 摘自< 游戏编程精粹4> 第58页


继续阅读

项目开发日志(八)

今天给cocos2dx2.2.3的cocostudio GUI增加遮罩控件,发现步骤还挺多.这里记录一下(省去编写代码的部分):

增加控件相关pkg文件

代码编写完成后,我把代码放到extensions\CocoStudio\GUI文件夹下.这个文件夹是cocostudio用来存放UI控件的默认文件夹.然后在文件夹tools\tolua++中增加控件pkg文件,例如我增加了UIBigMap.pkg,把需要导出给外界使用的函数从控件头文件中复制到pkg中.pkg的写法参照同文件夹下的其他pkg.

继续阅读

项目开发日志(七) 模块逻辑解耦

(注:项目跨平台采用cocos2d-x,服务端 和 客户端游戏逻辑部分 采用C++,客户端UI部分采用Lua)

游戏项目一般模块众多功能庞杂,合理的逻辑解耦会让整个项目看起来结构清晰且易于维护,接口事件是逻辑解耦的常用方式,C++和C#,JAVA不同 并没有明确的接口化编程,也没有像AS3那种功能完备事件处理,但C++是一种高度自由的语言,我们可以通过C++的继承与动态绑定来实现接口化.下面是我参与的项目中模块与模块的关系设计原型.

继续阅读

项目开发日志(六)

定时器在游戏项目中使用非常普遍,特别是在游戏服务端项目中,定时器检查函数会在每一帧调用.而保证游戏性能的关键就是在每一帧尽可能的运行少的代码,我们知道系统运行每一行代码其实是有时间的.所以每帧必然调用的代码量越少越好,在定时器的设计上 就要求我们尽可能的追求性能的极致.

一般的定时器设计原理

假设把整个游戏注册的所有定时器都放到一个vector容器中,一般的做法可能是每帧搜索一下这个vector,然后拿出来对比时间,时间到了则触发.这种在处理定时事件少的情况下是没有问题的,但是如果定时事件非常多的话,则需要改进下算法了.

继续阅读