有时候你不需要搜索代码

编程感悟

最近一段时间团队里新加入了一些小伙伴,我一直希望大家在参与具体项目功能开发之前,先好好熟悉框架熟悉代码熟悉流程,在开始某个模块开发之前,先好好熟悉产品文档,先构思一翻。奈何有的同学似乎还是按照他原本的工作套路做事,无奈。

今天主要说说代码里的搜索功能(主要是指微软的IDE神奇VS里的代码搜索功能)

Visual Studio里的代码搜索功能非常丰富,常用的有:

0x00. Ctrl+F 主要是当前源代码文件里的搜索或者替换
0x01. Ctrl+Shift+F 主要是当前项目或者当前解决方案全局的搜索或者替换
0x02. Ctrl+;(冒号) 搜索解决方案资源管理器,主要是搜索当前解决方案ListBox里的源文件名字
0x03. Visual Assits 中的Shift+Alt+O 快速打开源文件,其中每输入一个字符 可根据当前字符定位最接近的源文件
0x04. Visual Assits 中的Shift+Alt+S 和 Shift+Alt+F 等
注意 Visual Assits 是一款最常用的VS插件,本人是烂番茄的深度中毒者。。近几年还购买了正版,略贵但是却物超所值的一个插件。

使用上述的几个功能,极大的提升了开发效率,而且我也几乎每天都需要使用它们。但是,针对新加入项目的同事,或者对项目组成一点不熟悉对代码基本结构毫不了解的同学我真的严重不推荐使用。

继续阅读“有时候你不需要搜索代码”

Android拍照并添加进相册

最近有个小需求,在移动设备(iOS / Android)中应用调用拍照并把所拍照片存入相册。我原本以为这是一个很简单的事情,不就拍个照然后把照片丢进相册?心想最多100行代码即可解决问题,谁知还是踩中坑。且听我一一分解。

必备权限

<uses -permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses>
<uses -permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses>
<uses -permission android:name="android.permission.CAMERA"></uses>

添加入 AndroidManifest.xml 中

执行拍照

File destDir = new File(m_ImageRootPath);
if (!destDir.exists())
{
      destDir.mkdirs();
}

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT,Uri.fromFile(new File(m_ImageRootPath , m_ImageName)));
startActivityForResult(intent, 100);

代码中 m_ImageRootPath 为照片所存目录,m_ImageName为照片名。注意,若拍照不止一张 则照片名字最好每次不一样,否则你打开相册有可能每次都只能看到一张照片。

继续阅读“Android拍照并添加进相册”

独立游戏的数据分享

个人游戏杂谈(一)

今天,我的第二款游戏装机用户已经突破1000,这里统计的是启动并玩过的用户,只下载不启动的不算,在没有任何推广策略。没有任何商业运营手段的情况下,我觉得已经非常惊喜了。特别是锤子,从锤子商店过来的用户让我大大吃了一惊,看来我要把几年来黑过老罗的话收回去了。以后尽量不黑他了Orz。

以下是我后台收集的自然用户来源比率:

这张图让我大吃一惊,从平台用户基数(平台的总用户量)来讲。锤子商店是图中最少的。从锤子科技发布的锤子手机销售情况判断,注意 市面上并没有锤子商店这个APP 也就是说只有用锤子系统的用户才能够进入锤子商店APP,才能从锤子渠道下载到我的游戏,作为一个用户基数最少的平台 竟然是游戏里用户最大的来源渠道,真猜不透这是为何。按照一般的来说,在不买量不推广的情况下,上图的比率应该是各自平台用户基数比率才对。

继续阅读“独立游戏的数据分享”

把pbc移植到项目引擎中

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

目前我使用的引擎对代码的编码方式有了非常严格的控制,一般的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,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。

继续阅读“把pbc移植到项目引擎中”

3D基础编程笔记(一)

概念篇

DirectX 9.0,C++

作为3D编程菜菜,经同事指点若须打好基础,应从DirectX3D开始,因为D3DX对于3D编程的封装没那么高级.同样一个功能 D3DX往往需要几个函数,而OpenGL等则一个函数搞定,太高级的封装反而隐藏了原理.(大家都会用cocos2d-x,而且用得很溜,试问又有几个能拍胸脯说真正理解其内部原理呢.)下面记录一些常用概念,主要方便自己查询.

什么是引擎

引擎是什么?大家在游戏开发中肯定会遇到的,在日常同行交流中 首先问的估计也是:你们项目用的是什么引擎啊?用cocos2d-x?用U3D?用虚幻4?用CryEngine?用godot?那为什么要把他们叫做引擎呢?说到引擎一般有三种东西:

  • 机器发动机

汽车的引擎也叫发动机,因为那是整个汽车的动力源泉.

  • 搜索引擎

搜索引擎指自动从因特网搜集信息,经过一定整理以后,提供给用户进行查询的系统。

  • 游戏引擎

游戏引擎是指一些已编写好的可编辑电脑游戏系统或者一些互交式实时图像应用程序的核心组件。这些系统为游戏设计者提供各种编写游戏所需的各种工具,其目的在于让游戏设计者能容易和快速地做出游戏程序而不用由零开始。大部分都支持多种操作系统平台,如Linux、Mac OS X、微软Windows。游戏引擎包含以下系统:渲染引擎(即“渲染器”,含二维图像引擎和三维图像引擎)、物理引擎、碰撞检测系统、音效、脚本引擎、电脑动画、人工智能、网络引擎以及场景管理。

我们关注的显然是游戏引擎,一句话概括:游戏引擎就是一整高级编程组件.

继续阅读“3D基础编程笔记(一)”

Android NDK项目崩溃信息抓取

开发日志系列(十六)

cocos2d-x lua binding,android-ndk-r9c,eclipse,cygwin,window7 64bit,red mi,Thl9,htc one

项目最近进入高速迭代阶段,版本更新速度比平时加快了几倍,这几天出的版本 莫名的出现频繁崩溃闪退的问题(仅仅Android上),不得已停下逻辑开发工作去fix 这个问题.

问题重现

打开游戏进入场景 频繁切换模块界面的时候 有一定几率崩溃

初步猜测

很大可能是加载销毁UI资源的时候导致C++代码出错.而仅仅在Android上出问题 就有可能是挂在异步加载的线程上.由于 最近两周才做的UI资源分模块管理 和异步加载.所以 异步子线程出的问题非常大.

这个问题的难点在于,C++代码在android上调试比较困难,由于我们的项目(cocos2d-x lua)并非单纯的NDK项目 所以并不能完全用单步调试JNI的方式解决.需要知道问题的根源 还是必须从想办法抓取崩溃最后的打印信息开始.

继续阅读“Android NDK项目崩溃信息抓取”

字符串逐字刷新

开发日志系列(十五)

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

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

继续阅读“字符串逐字刷新”

回合卡牌的战斗模块

开发日志系列(十四)

cocos2d-x lua binding C/C++

在我目前参与的这款无操回合卡牌手游中,客户端战斗模块是由我实现的,在项目上线之前一直都生怕出现不可逆转的设计问题,所以我把模块流程描述给美术,别的程序同事听 同时尽量写出来.这个模块几乎全部使用C++实现.

战斗流程

解析服务端战斗数据创建战斗场景创建战斗对象进入场景按回合播放战斗特效对象退出场景显示战斗结果销毁回收内存/重播

  • 战斗数据解析器(parser)

这个解析器主要工作是解析和管理战斗初始数据.除此之外不做任何事情,目前项目中一般的战斗数据长度大概是1.5kb(1200~1600字节),在按数据结构(struct)解析数据的时候需要注意 服务端和客户端 的struct定义数据位对其的问题:

#pragma pack(1)
define some struct..
#pragma pack()

继续阅读“回合卡牌的战斗模块”

像素碰撞的一种实现

开发日志系列(十二)

环境: 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++静态绑定与动态绑定

开发日志系列(十一)

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

静态绑定与动态绑定

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

继续阅读“C++静态绑定与动态绑定”