使用cocos2d-x的console实现远程调试

使用Lua开发有一个很爽的地方就是可以从控制台实时输入Lua指令来进行调试,但是之前该方法仅在windows下有效,之前也介绍过,见这里。研究了下发现cocos2d-x是有一个console类来支持远程调试的,哈哈,从此真机调试也可以很方便了。

这里先介绍下console的关键API先:

listenOnTCP(number) 这里参数是监听的端口号
addCommand(tb, funciton) 这里第一个参数是一个表,内容如下:{name = "指令名", help = "指令介绍"},第二个参数就是执行的函数了,传入参数为(句柄,字符串参数)

继续阅读

Cocos2d-x 3.2 Lua 在Android设备闪退问题解决记录

描述:iOS设备运行正常,windows环境下模拟器程序运行正常,但是Android设备大多数都有运行一段时间闪退的问题。

第一次运行android设备上时使用版本3.0,后来升级到3.1.1,再到3.2,Android闪退问题一直存在,尤其是在红米系列设备,几乎必现。
因为对Android开发不是很熟悉,没法直接定位到导致crash的地方,于是请教了同事,后发现是打包的API版本过高,修改后闪退问题有明显好转,但是依然存在,最近项目进度不是那么赶,于是决定要彻底追查这个问题。
继续阅读

cocos-lua Scene介绍

cocos-lua里的Scene是对cocos2d的scene进行进一步的逻辑封装,增加常用的功能及方便管理,整个游戏都由一个个Scene来构成,所有的表现代码都应该在Scene里完成,而所有的Scene都由SceneMgr来管理,

SceneMgr

管理场景模版。

管理场景实例。管理结构为由Scene构成的栈,通过LoadScene和UnloadScene完成进栈和出栈,其中第一次加载需要用FiresLoadScene。

接口列表:

继续阅读

cocos-lua 架构简介及使用

Github:https://github.com/yestein/cocos-lua

基础接口:

Class:New(base_class, class_name) :用于实现面对对象的类,base_class 若为nil则为完全定义一个新类。

一切的基础--LogicNode

cocos-lua里头所有对象的基础类,也就是所有cocos-lua里的对象都具有它的功能,它包括以下功能:

  • 拥有child和parent
  • 监听事件
  • 查询调用指定名称的函数,用以实现COM
  • 可以接受消息执行,并将消息继续向child传递
  • 打印日志

接口如下:

  • GetParent() --获取父节点
  • AddChild(child_name, child_node, order) --添加子节点
  • RemoveChild(child_name) --删除子节点
  • GetChild(child_name) --获取指定的子节点
  • ForEachChild(callback, …) --迭代遍历每一个子节点
  • DeclareListenEvent(event_type, func_name) --注册事件监听
  • QueryFunction(func_name) --查询指定名称的函数
  • QueryFunctionWithChild(func_name) --查询指定名称的函数(包括所有的子节点)
  • TryCall(func_name, …) --尝试调用指定名称的函数(包括子节点种,若全部没有,则返回nil)
  • ReceiveMessage(msg, …) --对node及其所有子节点都试图调用名为msg的函数
  • Print(log_level, fmt, …) --打印日志
  • AddComponent(child_name, component_name, …) --添加指定名称的组件

事件(event)和消息(message)的区别

event是一个全局的类似信号弹的角色,主要用于不同模块之间的通信。如逻辑模块抛出一个角色伤害事件,表现模块受到事件后对相应的角色做出受伤的表现,如受伤动作,飘出红色伤害值等。event的使用在于抛出event的模块并不知道哪个模块会去处理它,并通过这个来降低模块间的藕合度。

message更类似于一个定向的指示弹,主要用于模块内部的操作。模块收到一个message,首先模块本身对这个message要做出回应,是否要处理,然后继续将这个message传递给它的子模块。如表现模块给角色表现模块发送一个角色受伤的message,角色表现模块受到message之后做出对角色播放受伤动作,然后这个message继续传递给它的子模块如文字飘血模块,文字飘血模块播放一个跳动的数字。message的使用在于模块收到message的时候并不知道自己能不能处理这个message,而需要将message一层层逐级询问子模块,目的在于降低模块内部子模块之间的耦合,方便模块进行组装。
PS:cocos-lua里为了处理message方便,将message的名称定义为处理函数的名称,类似于obj-c。

综上所述,event和message的目的都是为了降低整体代码的藕合度,他们的区别如下:

  • 是否定向。event的发送者不关心谁会接收这个event,而message要求发送者必须知道对谁发送。
  • 是否有序。event的接收者处理顺序是无法预测的,message的可以按指定顺序发送给相应的接收者。

对象池(ObjPool):

Id对象池模版,可以方便的创建一个对象池,提供Add,Remove,Get操作,并返回自增长的对象Id,并会抛出对象诞生和消亡的事件。

PS:在初始化的时候需要指定Obj的Name,因为在有obj被添加和删除的时候会分别抛出“ObjName“Add和”ObjName“Remove的事件。

模块(Module):

Module继承自LogicNode,通过ModuleMgr这个对象池进行管理,若模块需要每帧进行的循环操作可通过自身的函数RegisterActive(module_name, fun_name) 来向游戏世界注册。

场景管理概述:

SceneMgr:
管理场景的对象池,并提供简便的加载和卸载场景接口。

SceneBase:
继承自LogicNode的每个场景模版的基类,内置一些常用操作,如场景的拖动及限制范围,缩放是否加载物理世界等等。

Layer:
每个cocos2d的scene下会有多个Layer,这里对cocos2d的Layer进行了一个管理,可通过指定的name取到指定的layer。
提供接口:AddLayer(创建好一个layer后按指定name往里加入),CreateLayer(直接创建一个指定name的layer),GetLayer
PS:每个场景建立后都会有一个默认的名为“main”的layer。

场景UI

提供2种方法,基于Cocos2d和基于CocoStudio的方法。

CocoSudio:

根据Scene的cocos_ui列表来加载对应UI的JSON文件,格式如下:

Scene.cocos_ui = {
    [JSON文件地址] = {
        name = UI名称(不可重复),
        hide = 0, --加载完成后是否隐藏
        button = {逻辑变量名 = 控件名, ...},
        label = {逻辑变量名 = 控件名, ...},
        labelbmfont = {逻辑变量名 = 控件名, ...},
        ...
    }
}

对于按钮类控件,Scene类会有一个OnCocosButtonEvent处理函数,在有按钮被按下等操作时少辉触发,函数内容自己实现,格式如下:

function Scene:OnCocosButtonEvent(ui_name, button_name, event)
    --body
end

其中ui_name就是刚才填入的UI名称,button_name是刚才填入的逻辑变量名,event有4个,定义在Ui.lua中,分别是

Ui.TOUCH_EVENT_BEGAN    = 0
Ui.TOUCH_EVENT_MOVED    = 1
Ui.TOUCH_EVENT_ENDED    = 2
Ui.TOUCH_EVENT_CANCELED = 3

如何创建一个新的场景模版

这里推荐首先为这个场景单独建立一个lua文件,便于以后管理。然后写入以下代码:

local Scene = SceneMgr:GetClass("场景名", 1)
Scene.property = {} --场景属性,如是否可接受触摸事件,是否可拖动,是否可缩放等

function Scene:_Uninit( ... )
 -- body
end

function Scene:_Init( ... )
 -- body
end

function Scene:OnCocosButtonEvent(ui_name, button_name, event)
    --body
end

这样一个基本的场景模版就创建好了,在需要加载的时候只需要调用 SceneMgr:LoadScene(scene_name) 这个接口即可加载这个场景,如果是游戏世界第一次加载场景则需要调用 SceneMgr:FirstLoadScene(scene_name)

cocos-lua 整体设计思路简介

最近对cocos-lua框架进行了一次整理,将文件重新划分文件夹存放,并对核心思路也做了框架化整理,这里记录下设计这套逻辑框架里的主要几个思路:

1. 这个框架除了提供对cocos2d进行一系列的Lua封装之外,还提供一套逻辑构建解决方案。

2. 画面渲染部分与游戏逻辑部分要区分开,最严格的标准就是逻辑代码里不应该有一行与cocos2d相关的代码。

3. 模块之间的协同工作的模块尽量通过事件通信,以此降低耦合。这就要求使用者在设计模块层面将此考虑进来,不然会很痛苦。事件名采用字符串(可采用一定规则来凸显,如“模块名.事件名”这种),契合Lua高效的字符串比对。

4. 模块内部采用消息机制,对一个模块发送消息,模块会将消息层层分发下去,除非中途有某个子模块处理完后宣布需要独吞此消息。

5. 尽量使用小模块的拼装组合来实现更大的模块,并借助消息机制来处理各自的问题。

6. 所有的逻辑都是由一个个的小逻辑节点层层堆叠出来,尽量避免大而全的自顶向下的逻辑设计。

一套基于Cocos2d-x的Lua快速开发框架

   最近半年一直都在研究cocos2d-x的开发,由于自身对Lua的喜好,所以基本从一开始都是使用Lua作为主要开发语言,在开发过程中,也对cocos2d-x有了一定了解,但是说实话cocos2d-x对Lua的支持还是不太友好,基本还是停留在“能”使用Lua开发的阶段,只是使用了tolua++将API都导出来了而已,没有对lua开发者做更进一步的帮助,这样其实并没完全体现Lua的优势。

    其实开发初期就听闻有一个“quick cocos2d-x”的项目,也是采用的Lua,顾名思义目的就是为了提高开发者的效率。对这个项目使用了一番,觉得它做的那个模拟器机制是个不错的想法,虽然还有很多bug。对它这个框架的有些核心思想不是太认同,主要是这个框架对cocos2d的源码进行过修改,而不是一个纯粹的lua级框架,这样做势必自己必须要有一个cocos2d-x的分支,这样会带来一个很要命的问题——在cocos2d-x进行功能增加或者bug修复的时候,需要做大量的工作来将他们合并入自己的分支,所以也就没太关心它的架构实现了。(另模拟器提供的重载不是脚本级的,而是重启进程这点也不是很满意)

    所以最后还是选择了自己来写一套基于cocos2d-x的纯粹的Lua级的框架,针对开发过程中开发者一般都会遇到需要解决的问题做了框架级的封装,使我们可以将更多的心思花在项目的逻辑上,而不用关心太多cocos2d的细节。(比如屏幕的拖拽,缩放,UI资源的加载管理这些等等)

    目前这个框架也在公司的项目里开始运用,表现的还不错,而且也在不断的完善中,但是要把它使用起来还是要花上几分钟来配置,所以今天花了点时间写了个python脚本来做配置。另这个项目本身就是寄放在github上的开源项目(https://github.com/yestein/cocos-lua),打算最近花些时间对这个框架写些说明文档将其正式开源出来,也希望它可以接受更多的检验,成长的更好。未来我也会在这里专门开辟一个专栏来对其进行说明。