code++

Keep It Simple, Stupid

本文将详细阐述如何配置和使用 olua 自动导出脚本功能。

如果想了解 olua 的设计细节,请参见:

1. 使用示例

1.1. 创建

新建一个目录存放配置和 olua 脚本,结构如下:

tree -L 2 .
.
├── build.lua
├── conf
│   ├── clang-args.lua
│   └── lua-example.lua
└── olua -> [email protected]:zhongfq/olua.git

阅读全文 »

Cocos2dx 原生的 lua 绑定,c++ 对象与 lua 对象的生命周期不一致,c++ 对象基于引用计数,而 lua 对象基于 lua GC,生命周期不一致,容易产生各种不可遇知的行为。所以,我想重新设计一个绑定,使用得 c++ 对象与 lua 对象生命周期一致。起初考虑过在 tolua 的基础上实现,在仔细阅读源码之后,发现如果要实现这一目标,需要修改大量的源码,于是自己重新设计了一个绑定 olua

olua 设计之初,就定下了以 c++ 和 lua 对象生命周期一致为核心原则,所以在诸多接口的设计上都以此为目标。本文将阐述 olua 的核心设计要素与部分实现参考。

如果想了解 olua 导出工具的使用说明,请参见:

1. 类模型

lua class model
class A = {
class = class A
classname = A
classtype = native
super = class B
.classobj = userdata -- store static callback
.isa = {
copy(B['.isa'])
A = true
}
.func = {
__index = B['.func'] -- cache after access
dosomething = func
...
}
.get = {
__index = B['.get'] -- cache after access
name = get_name(obj, name)
...
}
.set = {
__index = B['.set'] -- cache after access
name = set_name(obj, name, value)
...
}
...__gc = cls_metamethod -- .func[..._gc]
}
阅读全文 »

cocos2dx 目前 lua 对应的 c++ 对象的生命周期管理,是基于 c++ 析构函数的,也就是生命周期可能存在不一致,比如 c++ 对象已经释放,而 lua 对象还存在,如果这时候再使用,会有宕机的风险,为此我开发了 cocos-lua 项目,基于 lua gc 管理 c++ 对象的生命周期。

cocos-lua 以 cocos2d-x 3.17.2 的 c++ 项目为基础,采用基于 lua gc 来管理 c++ 对象的生命周期,提供更丰富 cocos2d-x lua api,包括几乎除模版以外的所有 lambda(schedule、scheduleOnce…)函数回调,能够极大减少在 lua 层使用 c++ 对象的负担。

对比 cocos2dx-lua 目前方案,有以下几个优势

  1. lua gc 管理生命周期,更符合 lua 开发者,规避 c++ 现有生命周期问题。避免到处使用 tolua.isnull 判断,以及不知名的 crash。
  2. 导出代码相对 tolua 更精炼、高效率以及更友善错误检测机制。
  3. lambda 函数自动化的导出,tolua 是手动导出,
  4. 更优秀的第三方框架支持,如 fairygui、spine、dragonbone 之类的。
  5. 更加轻量和高效的 lua 绑定层。

项目地址:https://github.com/zhongfq/cocos-lua

在最近参与开发的 adobe air 项目中,前后端的通信协议从 XML、JSON 再到 protobuf,最后选择 protobuf 原因,主要是前后端维护 protobuf 协议就行了,同时还可以利用 IDE 做一些编译检查。

  目前我能找到的 protobuf as3 开源库,都存在一些问题:不支持嵌套类生成代码无法编译 等等。于是花了一点时间,参考 google protobuf 相关说明,编写 protobuf-as3 以及 protoc-as3,用于支持运行时及代码生成 Github

  protobuf-as3 库只支持 proto3 格式,proto3 列出的数据类型基本都支持。

1. Proto 定义

  以下 proto 文件将生成 5个 as3 类:Token.as、Token$Type.as、TokenBindingResponseCode.as、TokenBindingRequest.as、TokenBindingResponse.as。我们以 $ 作为分隔符以实现 protobuf 类的嵌套。

token.proto
syntax = "proto3";
package user.token;

message Token {
enum Type {
NONE = 0;
QQ = 1;
WEIBO = 2;
WECHAT = 3;
}

Type type = 1;
string value = 2;
}

enum TokenBindingResponseCode {
ERROR = 0;
OK = 200;
EXIST = 400;
}

message TokenBindingRequest {Token token = 1;}

message TokenBindingResponse {
TokenBindingResponseCode responseCode = 1;
Token token = 2;
}

2. 代码使用

阅读全文 »

最近的项目使用 adobe air 开发,不可能避免的要使用到 ane,项目初期的时候,使用了网上搜索到的了一些开源 ane,最后发现,很多都不完善,要么版本太久,要么 BUG 很多,无人维护,所以下决心自己开发一些目前用到的,有兴趣的可以一起完善一下 Github


1. ANE(iOS&Android)

1.1. 授权登录

方式 SSO WEBVIEW
微博
QQ
微信

1.2. 支付

方式 SSO WEBVIEW
支付宝
微信
阅读全文 »

Spine 是一个很好的制作 2D 骨骼动画的软件,其中提供的混合 (mix) 动画功能可以很柔和过度两个不同的动画,但在混合时期,稍有不善,非常容易出现各种错乱。在 Spine2D 骨骼动画群上,有人提出全 K 帧、K 透明轴等等方法,这些方法往往只是恰好解决了一些问题,但还有相当一部分潜在的问题还是可能发生的。


1. 问题原因

在使用过程中,我发现 Spine 的错乱问题主要表现在以下两个方面:

  1. Slot 位置下,A 动画中有 abcd 四个时间轴,而 B 动画只有 abc 三个时间轴,那么从 A 切换到 B 时,切换时 d 轴的状态(纹理或色彩)可能会残留到 B 动画上(如 A 是攻击动画,B 是行走动画,d 是特效轴)。如果是制作叠加动画(会同时播两个动画,比如边跑边打),那么可能不需要全部补齐,这种要视需要而定。
  2. Slot 位置下,A 动画与 B 动画混合时期(●表示关键帧):

    A:●—————————●——
    B:        ●——————————

              | 混合时期 |

阅读全文 »

lua 是一门简单的语言,不带类和属性封装,但可以使用 lua 强大的元表模拟实现:

1. 实现 class

local type = type
local rawset = rawset
local setmetatable = setmetatable

local traceCount = 0
local tracebacks = setmetatable({}, {__mode = "k"})

local function class(classname, super)
local cls = {}

cls.classname = classname
cls.class = cls
cls.Get = {}
cls.Set = {}

local Get = cls.Get
local Set = cls.Set

if super then
-- copy super method
for key, value in pairs(super) do
if type(value) == "function" and key ~= "ctor" then
cls[key] = value
end
end

-- copy super getter
for key, value in pairs(super.Get) do
Get[key] = value
end

-- copy super setter
for key, value in pairs(super.Set) do
Set[key] = value
end

cls.super = super
end

function cls.__index(self, key)
local func = cls[key]
if func then
return func
end

local getter = Get[key]
if getter then
return getter(self)
end

return nil
end

function cls.__newindex(self, key, value)
local setter = Set[key]
if setter then
setter(self, value or false)
return
end

if Get[key] then
assert(false, "readonly property")
end

rawset(self, key, value)
end

function cls.new(...)
local self = setmetatable({}, cls)
local function create(cls, ...)
if cls.super then
create(cls.super, ...)
end
if cls.ctor then
cls.ctor(self, ...)
end
end
create(cls, ...)

-- debug
traceCount = traceCount + 1
tracebacks[self] = traceCount

return self
end

return cls
end

return class
阅读全文 »

vim 是一个终端代码编辑器,是 SSH 开发利器,但是配置较为繁琐,我基于 网上 的加以改进,配置地址Github

1. 使用终端 clone 代码

cd ~
git clone https://github.com/zhongfq/vimrc .vimrc.git
ln -sf .vimrc.git/vim .vim
ln -sf .vimrc.git/vimrc .vimrc
cd .vimrc.git
git submodule init
git submodule update

2. vim 中执行下面命令安装插件

:BundleInstall

3. YouCompleteMe 插件要单独编译

cd ~/.vim/bundle/YouCompleteMe
python3 install.py --all
阅读全文 »