cocos2d-x开发: 如何从项目中分离出接口范例
cocos2d-x开发,包括核心模块接口开发和脚本部分的业务逻辑实现.从上层应用需求开始说,脚本在做业务逻辑实现的时候, 很多时候都需要依赖底层的接口功能,但是不是所有的人都可以游刃有余的去明白该怎么使用下层的接口,这不仅仅是语言的区别,其中还包括接口开发者在设计之初就期望的使用方式问题,所以一般都应该提供接口使用demo,由于我都是使用lua,所以我习惯的称之为unittest,接口功能测试则是以testcase的方式呈现.其实也就只是一种叫法.
先来说一下为什么我会做这样子的区分,我见过一些项目,要不然就是不提供使用范例,就是将各种测试都写在项目的入口文件那里.假如我们的引擎进入luaEngine之后进入的是src/main.lua文件中.那么按照很多没有分离好的项目的做法就会出现在main.lua文件中做一个变量.然后判断是进入游戏,还是进入测试,还是进入工具模式等等.程序员嘛,我们可以不纠结于这个实现的过程,结果也算是实现了各个方面的功能.不过,我还是要来分析一下: 项目开发毕竟是多个部分合作开发的,我们并不希望策划在使用我们提供的工具的时候还要自己手动去改配置文件.另外,由于初期就是为了方便将各种测试都堆叠在项目的某个文件里面,当然好的习惯不一定会被大家学习,这种坏习惯就很容易传染.后面每一个人就都会习惯这种简单的测试方法,认为这种测试堆叠的方法是理所当然的.最后的结果就是,堆测试的文件基本就是没法看了.
最后也是最主要的一点,我认真思考了一下,做下层接口,写范例代码是为了什么?其实就是作为对api不足的补充,更好的是某种情况下,达成某正规范,是可以让大家很快的熟悉接口的使用方法.我始终坚信,接口的设计者在实现的时候就应该会想到该如何更好的去使用自己写的接口.上面说了很多,希望能够准确的表达我的意思, 如果看不懂, 可以看下面我的思路以及实现,相信还是很容易看得懂的.
我先想到的是将除了项目业务逻辑实现部分的其他相关,像是工具呀,接口范例呀这些都分离出来,要做到这样子并不难,无非是在项目脚本目录的同级目录穿件一个新的文件夹,另外提供一个新的入口文件.就像下面这样子:
frameworks
runtime
res
src
--main.lua --我们通常看到的游戏入口文件
--Tests
--TestsController.lua -- 测试入口
--Tools -- 如果需要,工具部分入口.
结合我前面的出发点,我不希望更改脚本或者是配置文件做到这样子.不过也好解决,我们都知道,无论是在win下还是在linux下面,应用程序在运行的时候是可以解析命令行参数的.当然在Linux下面就是解析main函数的argc和argv,而在win下面也是同样,我们可以解析lpCmdLine,或者是__argc,__targv(tchar.h).关于win下面的这部分因为涉及到unicode的问题,所以我才会写成这个样子的,不过大家应该都会明白的.说到这里,应该很好明白如何去实现这部分的功能了.我以win32为例,代码如下:
AppDelegate.h
public:
void setCmdLine(const std::string& cmdline)
{
this->M_cmdline_ = cmdline;
}
std::string getCmdLine() const
{
return this->M_cmdline_;
}
private:
std::string getCmdByFlag(const std::string& flag, const std::string& defaultValue);
std::string M_cmdline_;
这是引擎封装好的入口代理,这里我添加了一个私有属性,用来装从命令行读取的参数.不管读到了什么,都一并装过来.不过,既然是我写,我当然知道我希望的格式是什么样子的了. “xiaoyan.exe -esrc/Tests/TestsController.lua”
就像是这个样子的,解析的时候我只要去解析-e后面的flag属性字段,我就知道要运行什么模块的代码了.好了,我做了一下Unicode字符串到ansi的转换,如下:
win32 main.cpp
// create the application instance
AppDelegate app;
if(__argc > )
{
#if(UNICODE)
std::wstring wcmdLine(lpCmdLine);
const wchar_t* wparams = wcmdLine.c_str();
size_t size = wcmdLine.size() * + ;
char* tmp = new char[size];
memset(tmp, , size);
wcstombs(tmp, wparams, size);
std::string cmdline(tmp);
app.setCmdLine(cmdline);
delete[] tmp;
#else
std::string cmdLine(lpCmdLine);
app.setCmdLine(cmdline);
#endif
}
int ret = Application::getInstance()->run();
虽然我不懂win32 sdk,但是简单看看unicode处理,还是很容易写出上面的这些代码.现在,我拿到了我想要的命令行参数,也做了相应的跨平台转化处理,放在std::string,解析部分就简单了,直接给实现:
std::string AppDelegate::getCmdByFlag(const std::string& flag, const std::string& defaultValue)
{
if(this->M_cmdline_.empty()) { return defaultValue; }
std::size_t index = this->M_cmdline_.find(flag);
if(index == std::string::npos) { return defaultValue; }
std::size_t nextIndex = this->M_cmdline_.find("-", index+flag.size());
if(nextIndex == std::string::npos) { return this->M_cmdline_.substr(index+flag.size(), std::string::npos); }
else { return this->M_cmdline_.substr(index+flag.size(), nextIndex-index-flag.size()); }
return defaultValue;
}
经过上面的变动,我就可以去修改我的引擎入口实现了,不废话,直接看吧.
bool AppDelegate::applicationDidFinishLaunching()
{
auto engine = LuaEngine::getInstance();
ScriptEngineManager::getInstance()->setScriptEngine(engine);
std::string entranceFile = getCmdByFlag("-e", "main.lua");
if (engine->executeScriptFile(entranceFile.c_str())) {
return false;
} return true;
}
我这边只是添加了一个接口测试模块,所以并没有什么逻辑判断之类的,不过我相信,即使是再多添加一些功能,也是很容易做的,但是不是修改上面这里的入口,而是简单的在运行时候提供我们想要运行的模块入口文件就行了.因为涉及到工作目录的问题,我在测试的时候是使用vs做的,不过,我也写好了sublime text配置部分的,一并给出来.我先是修改了build system,添加了一个Test的子模块:(可以对照上一篇文章看一下,如果不嫌麻烦)
{
"cmd": ["C:\\Users\\Administrator\\Desktop\\xiaoyan\\scripts\\compile-win32.cmd"],
"working_dir": "C:\\Users\\Administrator\\Desktop\\xiaoyan\\xiaoyan",
"shell": true,
"encoding":"utf-8",
"variants":
[
{
"cmd" : ["start","C:\\Users\\Administrator\\Desktop\\xiaoyan\\xiaoyan\\runtime\\win32\\xiaoyan.exe"],
"name": "Run",
},
{ --添加一个Test,带有参数
"cmd" : ["start","C:\\Users\\Administrator\\Desktop\\xiaoyan\\xiaoyan\\runtime\\win32\\xiaoyan.exe","-esrc/Tests/TestsController.lua"],
"name": "Test",
}
]
}
如上面我在注释中给出的说明一样, 后面加入了Test附加的参数,也就是测试模块的入口.好吧,做到这里就只剩下最后的琐碎了.先去添加一个快捷键:
[
{ "keys": ["alt+f1"], "command": "toggle_side_bar" }, { "keys": ["f5"], "command": "build" },
{ "keys": ["f10"], "command": "build", "args": {"variant": "Run"} },
{ "keys": ["f8"], "command": "build", "args": {"variant": "Test"} },
]
好吧,做到这个份上了, src/Tests/TestController.lua的测试源码就不用给了吧? 我相信还是很容易想到如何做的.该说说我为什么要这样做,而这么做和分离又有什么关系?在说这之前,我先说一下如何用,一样的,知道如何用就知道优点在哪里,自然也就明白了好处.可以参照Lua-tests的例子,是一种很好实现Tests的方法,不过,当然我们不会写的这么复杂.做到这样,可能还不完善,但是分离的工作相信很容易就看到成效了,在开发中有什么不明白的,先去翻阅Tests下面的TestCase,如果需要添加接口,将写好的接口测试加入TestCase提交就好了.
到这里,分离部分我就做完了,对于分离后下面的测试实现,相信不同的有见解的程序员会有不同的做法,那些就自由发挥了.其实我这样做的目的,是为了测试下层模块接口使用的.在没有确定游戏类型和需求之前,盲目的去做下层架构设计相关的工作,会造成后期开发很多问题.
cocos2d-x开发: 如何从项目中分离出接口范例的更多相关文章
- 使用strtok_s函数从一个字符串中分离出单词
下面的代码从含有多个结束符的字符串中分离出单词来,需要对strtok_s有清楚的认识.这段代码是我在写一个处理文件中单词个数时用来分离读取到的字符串中的单词时写的,亲测可用~ 1 2 3 4 5 6 ...
- 如何在多个项目中分离Asp.Net Core Mvc的Controller和Areas
前言 软件系统中总是希望做到松耦合,项目的组织形式也是一样,本篇文章将介绍在ASP.NET CORE MVC中怎么样将Controller与主网站项目进行分离,并且对Areas进行支持. 实践 1.新 ...
- vue 项目中实时请求接口 建立长连接
需求:在项目中需要每隔五秒请求一次接口 第一种方法:直接在mounted钩子函数中处理 mounted() { window.setInterval(() => { setTimeout(thi ...
- 企业应用开发模式 ERP项目中应用到的技术和工具
一.基础技术选型 C# .NET 3.5/4.0 这两个版本的.NET已经相当方便(Linq, Lambda,Parallel),语法简洁,配合WCF和WF两项技术,可以满足快速开发,维护方便的目标 ...
- C#.NET常见问题(FAQ)-使用SharpDevelop开发 如何在项目中添加类文件
点击文件-新建-文件,然后再工程内创建文件 或者工程-添加-新建项 更多教学视频和资料下载,欢迎关注以下信息: 我的优酷空间: http://i.youku.com/acetaohai12 ...
- 在asp.net web form项目中添加webapi接口
我有一个支付宝服务网关是ASP.NET WEB FORM项目,但是最近这个网关需要对外提供几个接口,想了下,使用web api比较合适,实现很简单,GO 1,首先添加一个文件夹名字叫App_Start ...
- 【Loadrunner_WebService接口】对项目中的GetProduct接口生成性能脚本
一.环境 https://xxx.xxx.svc?wsdl 用户名:username 密码:password 对其中的GetProduct接口进行测试 备注:GetProducts.xml文件内容和S ...
- 【Jmeter_WebService接口】对项目中的GetProduct接口生成性能脚本
一.环境信息 https://xxx.xxx.svc?wsdl 用户名:username 密码:password 对其中的GetProduct接口进行测试 二.通过soapui获取soup请求信息 1 ...
- 如何在python项目中写出像Django中一样功能的settings
一 核心文件目录结构 二 实现代码 resdme: 在实现此功能主要用到的知识点及模块: 1.反射 3.内置方法dir # 全局配置 NAME = 'root' # 用户配置 NAME = 'pe ...
随机推荐
- JavaScript & jQuery & Bootstrap
一.前言 javascript 简称 JS 与java编程语言 没有什么关系 JavaScript: {核心(ECMAScript) 文档对象模型(DOM) Document object mode ...
- cf1090 I.Minimal Product(贪心)
题意 题目链接 给出长度为\(n\)的序列\(a\),序列中的元素取值为\([-2e9, 2e9]\) 找到两个位置\((i, j) (i <j, a[i] < a[j])\),最小化\( ...
- html基础概念
一.HyperText Markup Language 内容,html是弱代码语言,代码编写不严谨 1.超链接 <a href="#">超级链接(anchor)& ...
- Android BitmapFactory.Options
public Bitmap inBitmap 如果设置,解码选项“对象的方法,采取将尝试重用这个位图加载内容时. public int inDensity 使用的位图的象素密度. public boo ...
- windows php5.4,5.6,7.X添加redis扩展
首先下载php5.4对应版本的php_igbinary.dll,php_redis.dll扩展. 下载地址:http://download.csdn.net/detail/gejinbao357/ ...
- JpaRepository 查询规范
1.JpaRepository支持接口规范方法名查询.意思是如果在接口中定义的查询方法符合它的命名规则,就可以不用写实现,目前支持的关键字如下. Keyword Sample JPQL snippet ...
- miniblast_hash算法c语言实现
对于一组基因文件中的基因序列,选取一段基因片段,作为索引,利用hash表,查找固定的基因片段.有一定的并且容忍错误. 简单讲就是自己实现一个hashtable,将选出特定字符串建立索引,便于查询.输出 ...
- 初始python(三)
1. 循环 if, while, forbreak : 结束整个循环continue :跳出当前这次循环,但不结束整个循环else :结束整个循环后才执行,不能与break合用,但可以与continu ...
- c/c++ 中#ifndef和#endif的作用及使用
有时候我们在编程的时候,希望有些代码在我们需要时编译,不需要时不编译,也就是让它快速注释,这时候即可以考虑#ifdef和#endif,它们会使我们的编译器进行选择性编译.使用方法如下: #includ ...
- Windows平台下Android应用抓包挖掘漏洞方法
0x01 大体思路 在安卓75%的市场占有率下,形形色色的安卓应用层出不穷,随之而来的便是大波的漏洞.在各类市场中随意翻一下,几乎都是连接网络的应用,这在给用户惬意体验的同时也给我们漏洞挖掘带来了机会 ...