Cocos2d-x lua学习笔记

20190220添加:
我的
https://gitee.com/Ivanhan2019/whry
别人的
https://github.com/weiDDD/whry_client

将某个文件回滚到指定版本
Administrator@HEMEI-20180102W MINGW32 /d/whry_client/run (master)
$ cd /D/whry_client/run/debug/win32

Administrator@HEMEI-20180102W MINGW32 /D/whry_client/run/debug/win32 (master)
$ git log GloryProject.exe
fatal: ambiguous argument 'GloryProject.exe': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'

Administrator@HEMEI-20180102W MINGW32 /D/whry_client/run/debug/win32 (master)
$ git checkout d4ad101 GloryProject.exe
利用hash回滚特定文件(文件名大小写敏感)时,使用hash的前六位就可以了
Administrator@HEMEI-20180102W MINGW32 /D/whry_client/run/debug/win32 (master)
$ git checkout d4ad10 libcocos2d.dll

GloryProject.exe依赖的其他dll:
msvcp140.dll
ucrtbased.dll
lua51.dll
zlib1.dll
config.json从D:\whry_client\client\base拷贝到D:\whry_client\run\debug\win32

利用IDA_Pro_v7.0_Portable和xxtea_decrypt工具解密lua代码:
输入签名:RY_QP_LookF_com
输入KEY:RY_QP_MBCLIENT_LookF_com
选择输入目录:D:\360安全浏览器下载\game\assets\base\src
选择输出目录:D:\game
解密模式:lua文件
解压client.zip到D:\360安全浏览器下载\
输入签名:RY_QP_LookF_com
输入KEY:RY_QP_MBCLIENT_LookF_com
选择输入目录:D:\360安全浏览器下载\client\src
选择输出目录:D:\game\client
解密模式:lua文件
 
修改yl.lua和WelcomeScene.lua:
https://www.9111813.cn/替换为http://ry.myqqgame.com
修改yl.lua:
61.160.247.37替换为114.55.250.18
E4954CD9-7089-4F7D-85F6-7B6EA082312E替换为8C3AC3BC-EB40-462f-B436-4BBB141FC7F9
登录端口8600不变

20170510添加:
whry6801
whry PC大厅需要修改并重新编译,因为登陆ip写死了
修改游戏广场工程中的函数CDlgLogon::GetInformation()
   //查找对象
  CEditComboUI * pEditServer = (CEditComboUI *)GetControlByName(szComboServerControlName);
  if(pEditServer!=NULL)
  {
    lstrcpyn(m_szLogonServer, pEditServer->GetText()/*szLogonServer*/,CountArray(m_szLogonServer));
  }
然后用VS2015重新编译得到Debug\Unicode\GamePlaza.exe和Release\Unicode\GamePlaza.exe

登陆服、协调服端口
netstat -nao
  TCP    0.0.0.0:8600           0.0.0.0:0              LISTENING       12684
  TCP    0.0.0.0:8610           0.0.0.0:0              LISTENING       2500

新建工程:
cocos new -p com.App.kaayou -l cpp -d D:\Project3.x App
cocos new -p com.lookf.rytest -l lua -d D:\rytest rytest

20170509:
luacompile       对 lua 文件进行加密和编译为字节码的处理。
usage: cocos luacompile [-h] [-v] [-s SRC_DIR_ARR] [-d DST_DIR] [-e]
                        [-k ENCRYPTKEY] [-b ENCRYPTSIGN] [--disable-compile]
通过 luacompile 命令对 lua 文件进行 XXTEA 加密以及编译为字节码的处理。
编译为字节码的功能基于 LuaJIT v2.0.3,所以目前编译成字节码的文件不适用于 iOS 64位设备。
输入目录:
H:\ly\Hall2
输出目录:
H:\ly\Hall
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\tools\cocos2d-console\bin>cocos luacompile -s H:\ly\Hall2 -d H:\ly\Hall -e -k jyx2auHc -b XXTEA --disable-compile
H:\ly\Hall1
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\tools\cocos2d-console\bin>cocos luacompile -s H:\ly\Hall2 -d H:\ly\Hall1 -e -k jyx2auHc -b XXTEA
没有加密,编译为字节码
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\tools\cocos2d-console\bin>cocos luacompile -s H:\ly\Hall2 -d H:\ly\Hall10 -k jyx2auHc -b XXTEA
没有加密,没有编译为字节码
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\tools\cocos2d-console\bin>cocos luacompile -s H:\ly\Hall2 -d H:\ly\Hall0 -k jyx2auHc -b XXTEA --disable-compile

用2dx自带的luajit编译lua脚本
C:\Cocos\Cocos2d-x\cocos2d-x-3.10\tools\cocos2d-console\plugins\plugin_luacompile\bin\luajit.exe
lua2luac.bat
文件夹内所有的lua脚本将被批量编译为字节码
http://www.cocoachina.com/bbs/read.php?tid=205802
http://blog.csdn.net/st_darkmoon/article/details/53168652

20170504:
xxtea_decrypt(lua脚本加密解密)V2.0 绿色版
http://www.greenxf.com/soft/147958.html
下载圣盛龙岩麻将的安卓包到电脑硬盘,apk后缀名改为zip,然后解压,打开这个工具,sign填XXTEA,key填jyx2auHc,输入目录填D:\lymj\assets\Hall,输出目录填D:\Hall1,解密模式选择lua文件,最后点击【开始解密】按钮,就可以得到解密后的圣盛龙岩麻将lua脚本资源了。
 

Cocos2d-x对于lua脚本提供了一种轻量级解决方案,加密算法是xxtea
打包脚本cocos2d.py加密参数的说明
主要就是两个部分,sign和key,sign是加密标记,用于判断脚本是否加密,
sign是XXTEA
用IDA载入libgame.so这个库
key是jyx2auHc

// 设置sign和key
LuaStack* stack=engine->getLuaStack();
stack->setXXTEAKeyAndSign("jyx2auHc",strlen("jyx2auHc"),"XXTEA",);

// 通过对比文件开头的字符串是否为所设置的sign判断是否加密,如果加密的话就解密,解密后才加载脚本
int r=0;
if(_xxteaEnabled && strncmp(chunk,_xxteaSign,_xxteaSignLen)==0)
{
// decrypt XXTEA
unsigned char* result=xxtea_decrypt((unsigned char*)chunk+_xxteaSignLen,(xxtea_long)chunkSize-_xxteaSignLen,(unsigned char*)_xxteaKey,(xxtea_long)_xxteaKeyLen,&len);
r=luaL_loadbuffer(L,(char*)result,len,chunkName);
free(result);
}

更加安全的加密方案:
1、应该使用luajit去编译自己的脚本,就算攻击者解密出来也无法获得源码。
2、不应该采用官方的加密方案,应该自己实现加密解密算法。
3、隐藏自己的加密密钥,不应该过分明显。
4、保护好自己的so库,加壳或者做混淆。
 

使用的源码和脚本: 

http://pan.baidu.com/s/1gfDVWS7
nl4s


大汉
sign:
Gongzhu!#$1356334~!@!#AADOM!@#faddafa
key:
Gongzi@#$~!AOFJNOEBM@!#$@!~fasfas@#!24

玄武娱乐
sign:
AA_BB_2017
key:
ME_ME_MECLIENT_!2017

宾果
sign:
convertToNormalSprite
key:
convertToGraySprite

1.1.3 Cocos2d-Lua的发展
2012年,网龙科技利用tolua++,将Cocos2d-x的C++接口转为了Lua接口(这层C++与Lua之间的胶水代码叫Lua Binding)。
2012年上半年,廖宇雷的公司开始使用Cocos2d-x+Lua来开发游戏。廖宇雷重写了整个Lua Binding代码,解决了内存泄漏和只能使用全局函数做回调等问题。
廖宇雷继续改进Lua代码并以Quick-Cocos2d-x为代号fork了一个新的开源引擎。
最终Quick-Cocos2d-x被Cocos2d-x并入主线,成为新的引擎版本:Cocos2d-Lua,而廖宇雷也成为这个版本的核心开发者。

chap3 Cocos2d-Lua基础
3.1 Windows下的Cocos2d-Lua开发环境配置
3.1.1安装Cocos2d-Lua
注:编写本教材时最新的版本为Cocos2d-Lua v3.3 Final。
3.1.2安装Sublime与QuickXDev
3.2引擎架构
Cocos2d-x与ThirdPart Library对外暴露C++ API,Lua Binding把C++ API映射为Lua API,而Quick Framework基于Lua API进行二次封装并扩展了接口。游戏在最上层,可以同时使用Lua API和Quick框架。
3.2.2引擎文件结构
quick目录下的Quick框架是本书的重点内容。
(1)bin:Quick框架相关的可执行脚本。
(2)cocos:cocos2d-x Lua binding接口。
(3)framework:Quick框架的Lua源码。
(4)lib:Quick框架的C++源码。
(5)player:模拟器的源码。
(6)samples:Quick框架测试案例。
(7)templates:项目创建模板。
(8)welcome:模拟器启动后显示的欢迎界面。
chap7 Cocos2d-Lua高级
7.1网络通信
Cocos2d-Lua提供了以下3个通信模块:
(1)network,http协议的客户端解决方案,包含了网络状态的获取。
(2)SocketTCP,基于LuaSocket封装的tcp协议客户端解决方案。
(3)WebSocket,WebSocket协议客户端解决方案。

chap8打包与发布
8.1Mac下编译Android版本
8.2Mac下编译iOS版本
8.3Windows下编译Android版本



20170506添加:
Cocos2d-x之LUA脚本引擎深入分析
http://www.docin.com/p-799461956.html
在Cocos2d-x中,有两个类来完成对于LUA脚本文件的处理。
cocos\scripting\lua-bindings\manual\CCLuaEngine.h/cpp
第54行:
class CC_LUA_DLL LuaEngine : public ScriptEngineProtocol
LuaEngine:Lua脚本引擎
cocos\base\CCScriptSupport.h/cpp
第773行:
class CC_DLL ScriptEngineManager
ScriptEngineManager:脚本引擎管理器

quick-cocos2d-x与cocos2d-x+lua调研
http://www.docin.com/p-1487322226.html

Cocos2d-x 3.3 Lua相关修改
问题1:
addSpriteFramesWithFile
cocos\scripting\lua-bindings\auto\lua_cocos2dx_auto.cpp
第91341行:
int lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile(lua_State* tolua_S)
但是,在Lua里面调用addSpriteFramesWithFile时,如果第二个参数传递Texture2D,就会报错。
这是个误报。
从上面lua_cocos2dx_SpriteFrameCache_addSpriteFramesWithFile的绑定代码可以看出,第二个参数是字符串的重载版本(版本1)是先调用的。当使用第二个参数是Texture2D的重载版本时,版本1也会被调用,但不会执行。
不过参数判断总是会执行,因此就出现了误报。

luaval_to_native_err
cocos\scripting\lua-bindings\manual\LuaBasicConversions.cpp
误报的输出发生在LuaBasicConversions.cpp的luaval_to_native_err函数中
第34行:
void luaval_to_native_err(lua_State* L,const char* msg,tolua_Error* err, const char* funcName)

终极解决方案就是取消这个方法的自动导出,改为手动导出。

问题2:
不能载入luac文件
cocos\scripting\lua-bindings\manual\Cocos2dxLuaLoader.cpp
找到Cocos2dxLuaLoader.cpp文件,找到其中的cocos2dx_lua_loader方法
第36行:
int cocos2dx_lua_loader(lua_State *L)
将下面这段删除或注释
第87行:
            chunkName = prefix.substr(0, pos) + filename + BYTECODE_FILE_EXT;
            if (utils->isFileExist(chunkName))
            {
                chunk = utils->getFileData(chunkName.c_str(), "rb", &chunkSize);
                break;
            }
Cocos2d-x的Lua载入代码会优先载入luac文件,然后再处理Lua文件。取消载入luac文件即可解决这个问题。

lua_print
cocos\scripting\lua-bindings\manual\CCLuaStack.cpp
第59行:
int lua_print(lua_State * luastate)
第96行:
CCLOG("[LUA-print] %s", t.c_str());
第138行:
log("[LUA-print] %s", t.c_str());

Cocos2d-x之Lua核心编程
刘克男 杨雍 著
2015年11月第1版
前言
本书基于Cocos2d-Lua v3.3 Final版本撰写,由于Quick框架对接口稳定所作的贡献,本书与引擎功能模块相关的章节适用于Cocos2d-Lua 3.x所有版本。
本书不适用于Cocos2d-Lua 2.x分支版本。
作者
2015年9月
chap2 Lua编程
2.1 Lua在Windows下的运行环境搭建
Lua For Windows
exe安装包
LuaForWindows_v5.1.4-46.exe
此处选用5.1版本是为了对应Cocos2d-Lua中集成的Lua解析器版本。

Cocos2d-x-lua开发环境搭建
vs+sublime text+decoda的开发环境
1、创建vs的hello world工程
create_project.py 工程名字 -package 包名 -language lua
2、sublime text+decoda工具安装
st用于编写lua代码
decoda用于调试代码

基于lua动态脚本语言cocos2d-x应用开发的技术研究
Lua与C++交互技术
首先是Lua通过Lua Binding访问C++中的类库或者函数以及传递参数,
其次是C++回调Lua C API访问Lua的函数以及传递参数。

创建节点
local item = cc.Node:create()
增加新的子节点
node:addChild(dot)
runScene:addChild(friendshare,yl.MAX_INT - 2)--第二个参数Z轴绘制顺序,第三个参数是标签
查找子节点
local icon = item:getChildByTag(1)--通过标签查找子节点
通过标签查找子节点,并停止所有该节点上的一切动作
self:removeChildByTag(UserInfoLayer.LAY_SELHEAD, true)
node:removeChild(childNode, true)--删除childNode节点。并停止所有该子节点上的一切动作。
node:removeAllChildrenWithCleanup(true)--删除node节点的所有子节点,并停止这些子节点上的一切动作。
node:removeFromParentAndCleanup(true)--从父节点删除node节点,并停止所有该节点上的一切动作。
--Node还有两个非常重要的属性:position和anchorPoint
self.m_clipDistance:setPosition(cc.p(254, 132))
self.m_clipDistance:setAnchorPoint(cc.p(1.0,0.5))
--按照帧率进行调度,优先级0是默认值。这个Node对象会定时地每帧回调用一次callback函数,priority是优先级,priority值越小越先执行。
self:scheduleUpdateWithPriorityLua(callback, 0)
self:unscheduleUpdate()--停止scheduleUpdateWithPriorityLua的调度
指定图片创建精灵
sp_table = cc.Sprite:create("Room/bg_table.png")
sp = cc.Sprite:create("background.jpg")
通过一个精灵帧对象创建另一个精灵对象
local trumpetBg = cc.Sprite:createWithSpriteFrame(frame)

Cocos2d-x Lua中标签类主要有三种:LabelTTF、LabelAtlas和LabelBMFont。此外,在Cocos2d-x 3.x之后又推出了新的标签类Label。
LabelTTF是使用系统中的字体,它是最简单的标签类。
// 创建并初始化标签
local label = cc.LabelTTF:create("1","Arial",20);
local nickName = cc.LabelTTF:create(curUserTab.szNickName,"fonts/round_body.ttf",20,cc.size(130,40),cc.TEXT_ALIGNMENT_LEFT);
create函数的第一个参数是要显示的文字,第二个参数是系统字体名,第三个参数是字体的大小,事实上该create函数省略了三个参数,create函数的完整定义如下:
cc.LabelTTF:create (text,            
fontName,  
fontSize,  
dimensions=cc.size(0,0),    --在屏幕上占用的区域大小,cc.size(0,0)表示按照字体大小显示 
hAlignment= cc.TEXT_ALIGNMENT_LEFT,         -- 水平对齐,默认值是靠右对齐 
vAlignment= cc.VERTICAL_TEXT_ALIGNMENT_TOP)     -- 垂直对齐,默认值是顶对齐 
其中后三个参数有默认值,如果不指定就会使用默认值。

LabelAtlas是图片集标签
local lValue = cc.LabelAtlas:_create(tostring(userInfoTab.cbMemberOrder),"Friend/shuzi1.png",16,20,string.byte("0"));
create函数的第一个参数是要显示的文字,第二个参数是图片集文件,第三个参数是字符高度,第四个参数是字符宽度,第五个参数是开始字符。
使用LabelAtlas需要注意的是图片集文件需要放置在Resources目录下。


local label = cc.LabelBMFont:create("HelloWorld", "fonts/BMFont.fnt")
使用LabelBMFont需要注意的是图片集文件和坐标文件需要放置在Resources目录下,文件命名相同。图片集合和坐标文件是可以通过位图字体工具制作而成的。
 
Cocos2d-x 3.x标签类Label
这种标签通过使用FreeType来使它在不同的平台上有相同的视觉效果。由于使用更快的缓存代理,它的渲染也将更加快速。Label提供了描边和阴影等特性。
local testen = cc.Label:createWithSystemFont("A","Arial", 24)
local notifyText = cc.Label:createWithTTF("", "fonts/round_body.ttf", 24)
local str = cc.FileUtils:getInstance():getStringFromFile("Service/Service.txt")
self._strLabel = cc.Label:createWithTTF(str, "fonts/round_body.ttf", 25)
createWithSystemFont是创建系统字体标签对象
createWithTTF是创建TTF字体标签对象
createWithBMFont是创建位图字体标签对象

1.3.3 Cocos2d-x 3.0版本的各语言优化
2014年4月,Cocos2d-x发布了3.0版本。
引擎团队分别针对C++、Lua、JavaScript三种编程接口的使用体验做了大量提升。
2、增强Lua语言体验:开发快,测试快,上线快
新版本为开发者增强了Lua体验,核心的改进主要有几个方面。
a、使用bindngs-generator生成Lua绑定,这大大减少了编写pkg文档的工作量。
b、对于V3.0新增功能做了绑定,例如new Label、EventDispatcher和physics等,同时对原有的一些C++功能也进行了绑定,例如websocket、xmlHttpRequest、Spine、AseetManager和OpenGL相关函数的绑定。
c、绑定时自动实现了模块化,当前在Lua中可以使用的模块有cc、ccs、ccui、sp和gl等。
d、使用ScriptHandlerMgr统一管理Lua function的注册以及注销。
e、对于一些类直接使用Lua table传递,例如Point、Rect和Size等。
f、增加了Lua脚本来直接调用Objective-C和Java代码。



20170508添加:
src\plaza\views\layer\game\GameChatLayer.lua
--聊天展现层
local GameChatLayer = class("GameChatLayer", cc.Layer)
--聊天内容
local ChatItem = class("ChatItem", cc.Node)

function ChatItem:ctor()

 self.m_labelChat = nil
-- LabelTTF* m_labelChat=NULL;
end


function ChatItem:refreshTextItem(str,sendusernick)

 if nil == self.m_labelChat then
  self.m_labelChat = cc.LabelTTF:create(str, "fonts/round_body.ttf", SIZE_CHAT_LABEL, cc.size(LEN_CHAT_WIDTH,0), cc.TEXT_ALIGNMENT_LEFT)
  self.m_labelChat:setAnchorPoint(cc.p(0.5,0))
  self.m_labelChat:setPositionY(3.0)

  self:addChild(self.m_labelChat)
 else
  self.m_labelChat:setString(str)
 end
 self.m_labelChat:setVisible(true)
 self.m_labelChat:setColor(cc.c3b(255, 255, 255))
 local labSize = self.m_labelChat:getContentSize()
--C++写法
--m_labelChat->setAnchorPoint(Point::ANCHOR_MIDDLE_BOTTOM);
--m_labelChat->setPositionY(3.0);
--addChild(m_labelChat);
--m_labelChat->setString(str);
--m_labelChat->setVisible(true);
--m_labelChat->setColor(ccc3(255, 255, 255));
end

function ChatItem:refreshBrowItem(idx,sendusernick) 
 if nil ~= self.m_labelChat then
  self.m_labelChat:setVisible(false)
 end
end

// C++/LUA
CCSize s = CCDirector::sharedDirector()->getWinSize();
CCSprite * bg = CCSprite::create("bg/bg1.jpg");
bg->setPosition(ccp(s.width/2, s.height/2));
addChild(bg);

local size = cc.Director:getInstance():getWinSize()
local bg = cc.Sprite:create("bg/bg1.jpg")
bg:setPosition(cc.p(size.width/2, size.height/2))
self:addChild(bg)

// C++/LUA创建一个图片集标签对象,create函数的第一个参数是要显示的文字,第二个参数是图片集文件,第三个参数是字符高度,第四个参数是字符宽度,第五个参数是开始字符
LabelAtlas *label;
local label = cc.LabelAtlas:_create("HelloWorld",
"fonts/tuffy_bold_italic-charmap.png",
48,
66,
string.byte(" ")
)
label:setPosition(cc.p(size.width/2  - label:getContentSize().width / 2,size.height - label:getContentSize().height))

 self._level = cc.LabelAtlas:_create(GlobalUserItem.wCurrLevelID.."",
"Information/num_info_level.png",
16,
20,
string.byte("0")
)
      :move(235,278+15)
      :setAnchorPoint(cc.p(0, 0.5))
      :addTo(self)

framework\display.lua
第189行:
FADE            = {cc.TransitionFade, cc.c3b(0, 0, 0)},
CCDirector::sharedDirector()->replaceScene( CCTransitionFade::create(0.5f, pScene, ccBLACK) );
local tranceAnima=cc.TransitionFade:create(0.5,secondScene)
cc.Director:getInstance():replaceScene(tranceAnima)

local director = cc.Director:getInstance()
device.platform == "ios"
os.exit(0)
void HelloWorld::menuCloseCallback(Ref* pSender)
{
    Director::getInstance()->end();

#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
    exit(0);
#endif
}

CCSprite *sp = CCSprite::create("Friend/biaoti5.png");
local sp = cc.Sprite:create("Friend/biaoti5.png")

CCSprite *trumpetBg = CCSprite::createWithSpriteFrame(spriteFrame("sp_trumpet_bg.png"));
local frame = cc.SpriteFrameCache:getInstance():getSpriteFrame("sp_trumpet_bg.png")
local trumpetBg = cc.Sprite:createWithSpriteFrame(frame)

CCRotateTo::create
local act = cc.RotateTo:create(10, angle)
CCAnimation::create()
local animation = cc.Animation:create()

CCAnimate::create
local act = cc.Animate:create(animation)
CCRepeatForever::create
CCSequence::create
sp:runAction(cc.RepeatForever:create(cc.Sequence:create(cc.FadeTo:create(2,255),cc.FadeTo:create(2,128))))

CCSpawn::create
CCCallFunc::create(this, callfunc_selector(CFish::removeSelf))
  bg:runAction(cc.Sequence:create(cc.DelayTime:create(delaytime),
   cc.Spawn:create(cc.FadeTo:create(0.5,0),cc.CallFunc:create(function()
    lab:runAction(cc.FadeTo:create(0.5,0))
    end)),
   cc.RemoveSelf:create(true))) 

 CCUserDefault::sharedUserDefault()->getBoolForKey("ZJD_SOUNDSTATE",true);
 CCUserDefault::sharedUserDefault()->setFloatForKey("ZJD_SOUNDNUM",0.5);
 CCUserDefault::sharedUserDefault()->flush();
 float dt = CCUserDefault::sharedUserDefault()->getFloatForKey("ZJD_SOUNDNUM");

 cc.UserDefault:getInstance():setStringForKey(key, value .. "")
 cc.UserDefault:getInstance():flush()
 return cc.UserDefault:getInstance():getBoolForKey("isBingdingAccount", false)



20170510添加:
quick-Cocos2d-x、quick framework API
cocos\framework\display.lua
第331行
function display.newSprite(source, x, y, params)
display.newSprite创建精灵
filename:精灵文件名
x:x位置坐标
y:y位置坐标
params:表参数(不常用)

疑惑一:有很多直接addTo、move等方法,我在cocos2dx的API中没找到啊,它们在哪里?
答:在src/cocos/framework/extends里面,有很多类似NodeEx.lua的文件,就是在这里啦,quick在这里对一些常见的类进行了一些方法的扩充,使得我们的代码简化了
cocos\framework\extends\NodeEx.lua
第38行
function Node:addTo(parent, zorder, tag)
第69行
function Node:move(x, y)

plaza\views\layer\logon\LogonView.lua
第17行
function LogonView:ctor(serverConfig)
第72行
 --记住密码
 self.cbt_Record = ccui.CheckBox:create("Logon/rem_password_button.png","","Logon/choose_button.png","","")--创建复选框
  :move(515,165)
  :setSelected(GlobalUserItem.bSavePassword)
  :setTag(LogonView.CBT_RECORD)
  :addTo(self)

Lua开发中实现MVC框架的简单应用
MVC,即Model View Controller。
Model(模型),一般负责数据的处理;
View(视图),一般负责界面的显示;
Controller(控制器),一般负责前端的逻辑处理。
拿一款手机游戏来说,界面UI的显示、布局等就是View负责;
点击了按钮,手势的滑动等操作由Controller来处理;
游戏中需要的数据资源就交给Model。
接下来,看看在游戏开发中怎么用,这里用网狐荣耀Lua(环境使用cocos code ide)给大家说说。
cocos
controllers
models
views
Event里面保存的全局消息类型,
Managers是用于管理游戏中的东东的,比如管理资源,管理各种场景切换,层的切换等等。
Toolkits或Utilities提供一些工具类,比如字符串的处理等。
NetCenter,专门用于处理网络的。

base\src\packages\mvc\AppBase.lua
第36行
self:enterScene(initSceneName)--等同于self:enterScene(initSceneName, nil, nil, nil)
enterScene函数接收4个参数:
sceneName是你要跳转的场景名
transition是场景切换的过渡动画类型,例如"FADE"
time过渡时间,例如1
more是过渡效果附加参数
第39行
function AppBase:enterScene(sceneName, transition, time, more)
第45行
function AppBase:enterSceneEx(sceneName, transition, time, more)
 
--场景切换 
self:getApp():enterSceneEx(appdf.CLIENT_SRC.."plaza.views.LogonScene","FADE",1)

来看看LogonScene这个类:
local LogonScene = class("LogonScene", cc.load("mvc").ViewBase)--继承cc.mvc.ViewBase
 

-- 初始化界面
function LogonScene:onCreate()

第98行:
 local  btcallback = function(ref, type)
        if type == ccui.TouchEventType.ended then
          this:onButtonClickedEvent(ref:getTag(),ref)
        end
    end

第138行:
 --返回
 if  device.platform ~= "mac" and device.platform ~= "ios" then
  ccui.Button:create("bt_return_0.png","bt_return_1.png")
   :move(75,yl.HEIGHT-51)
   :setTag(LogonScene.BT_EXIT)
   :addTo(self._backLayer)
   :addTouchEventListener(btcallback)
 end


第166行:
--按钮事件
function LogonScene:onButtonClickedEvent(tag,ref)
 --退出按钮
 if tag == LogonScene.BT_EXIT then
   local a =  Integer64.new()

 print(a:getstring())
 
  if self:getChildByTag(LogonScene.DG_QUERYEXIT) then
   return
  end
  QueryExit:create("确认退出艺游娱乐吗?",function(ok)
    if ok == true then
     os.exit(0)
    end
   end)
   :setTag(LogonScene.DG_QUERYEXIT)
   :addTo(self)
  
 end
end

lua中ccui.Button的创建和点击方式
--ccui.Button的创建方法
ccui.Button:create("cocosui/animationbuttonnormal.png", "cocosui/animationbuttonpressed.png")
ccui.Button:create("crystal.png", "", "", ccui.TextureResType.plistType)

addClickEventListener(只在按钮点击触发一次)

addTouchEventListener(按钮点击 抬起 移动 取消状态触发事件)

self:addTouchEventListener(function(sender, state)
 local event = {x = 0, y = 0}
 if state == 0 then
 event.name = "began"
 elseif state == 1 then
 event.name = "moved"
 elseif state == 2 then
 event.name = "ended"
 else
 event.name = "cancelled"
 end
 event.target = sender
 callback(event)
 end)

cocos2dx+lua注册事件函数详解
1、registerScriptTouchHandler 注册触屏事件
2、registerScriptTapHandler 注册点击事件
3、registerScriptHandler 注册基本事件 包括 触屏 层的进入 退出 事件
4、registerScriptKeypadHandler 注册键盘事件
5、registerScriptAccelerateHandler 注册加速事件

1、registerScriptTouchHandler 详解(可以设置单点或多点)
function gameWindow:addLayerTouchEventMethod1()
    local function onTouchEvent(eventType, x, y)
        --log("eventType = "..tostring(eventType))
        if eventType == "began" then
            --需要返回true
            return onTouchBegan(touch, event)
        elseif eventType == "moved" then
            onTouchMoved(touch, event)
        elseif eventType == "ended" then
            onTouchEnded(touch, event)
        end
    end
    config.bottomLayer:setTouchEnabled(true)
    config.bottomLayer:registerScriptTouchHandler(onTouchEvent)
end
 
2、registerScriptTapHandler 注册点击事件
function gameWindow:addBtn()
    local btn = cc.MenuItemImage:create("white.png", "black.png", "black.png")
    btn:setPosition(320, 160)
    local function btnClick()
        log("btnClick")
    end
    btn:registerScriptTapHandler(btnClick)
 
    local menu = cc.Menu:create()
    config.bottomLayer:addChild(menu)
    menu:setPosition(cc.p(0,0))
 
    menu:addChild(btn)
end
 
3、registerScriptHandler 注册基本事件
注册触屏事件用法
function gameWindow:addLayerTouchEventMethod2()
    --创建一个单点触屏事件
    local listener = cc.EventListenerTouchOneByOne:create()
    --注册触屏开始事件
    listener:registerScriptHandler(onTouchBegan, cc.Handler.EVENT_TOUCH_BEGAN)
    --注册触屏移动事件
    listener:registerScriptHandler(onTouchMoved, cc.Handler.EVENT_TOUCH_MOVED)
    --注册触屏结束事件
    listener:registerScriptHandler(onTouchEnded, cc.Handler.EVENT_TOUCH_ENDED)
    --获取层的事件派发器
    local eventDispatcher = config.bottomLayer:getEventDispatcher()
    --事件派发器 注册一个node事件
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, config.bottomLayer)
end
 
注册layer的 进入 退出事件用法
function gameWindow:addLayerEnterAndExitEvent()
    local function onNodeEvent(eventType)
        if eventType == "enter" then
            log("enter")
        elseif eventType == "exit" then
            log("exit")
        end
    end
    config.bottomLayer:registerScriptHandler(onNodeEvent)
end
 
3a、Lua中添加触摸事件
都需要添加监听者,都需要将监听者添加到触摸事件分发器中去
local listener=cc.EventListenerTouchOneByOne:create()
listener:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN )
listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCH_ENDED)
local dispacther=cc.Director:getInstance():getEventDispatcher()
eventdispacther:addEventListenerWithSceneGraphPriority(listener, self)

--触摸事件
function OnTouchBegan(touch,event)
        return true
end

function OnTouchEnded(touch,event)
      local p=touch:getLocation()
      print(p.x)
      print(p.y)
end


4、registerScriptHandler 注册键盘事件
function cocoEvent.addKeyboardEvent()
    local function keyboardPressed(keyCode, event)
        if keyCode == 23 then
            log("left")
        elseif keyCode == 24 then
            log("right")
        elseif keyCode == 25 then
            log("up")
        elseif keyCode == 26 then
            log("down")
        end
        --log("keyCode = "..tostring(keyCode))
        --log("event = "..tostring(event))
    end
 
    local function keyboardReleased(keyCode, event)
        --log("keyCode = "..tostring(keyCode))
        --log("event = "..tostring(event))
    end
    local listener = cc.EventListenerKeyboard:create()
    listener:registerScriptHandler(keyboardPressed, cc.Handler.EVENT_KEYBOARD_PRESSED)
    listener:registerScriptHandler(keyboardReleased, cc.Handler.EVENT_KEYBOARD_RELEASED)
    local eventDispatcher = config.bottomLayer:getEventDispatcher()
    eventDispatcher:addEventListenerWithSceneGraphPriority(listener, config.bottomLayer)
end
 

20170511添加:
quick框架之MyApp详解
1、通过一些文件进行framework的初始化
在base\src\main.lua中有2行require语句
require("config")
require("cocos.init")
在base\src\config.lua中没有require语句
在base\src\cocos\init.lua中有很多require语句
第119行
if CC_USE_FRAMEWORK then
    require "cocos.framework.init"
end
在base\src\cocos\framework\init.lua中有很多require语句
在lua中,require表示引入一个文件,其中base表示你项目的根目录
通过require这三个文件后,将会对quick的框架做一些初始化的事情。
require("config"),这句会加载base\src\config.lua文件,require加载文件的过程中会检查该文件的lua语法,以及完成文件内的一些变量的初始化,
你打开config.lua文件,你回看到都是一些变量的初始化,DEBUG、CC_USE_FRAMEWORK、CC_SHOW_FPS、CC_DISABLE_GLOBAL、CC_DESIGN_RESOLUTION这些都是全局变量,因为没有local。
require了之后,你就可以在任何地方引用这些变量,比如DEBUG变量。
2、MyApp的定义
回到MyApp文件,看这一行
local MyApp = class("MyApp", cc.load("mvc").AppBase)
--local MyApp = class("MyApp", cc.mvc.AppBase)
这一行的意思是:定义一个MyApp类,它继承自cc.mvc.AppBase
那么问题来了,cc.mvc.AppBase在哪里?
--在root/framework/cc/mvc/AppBase.lua
在base\src\packages\mvc\AppBase.lua
3、BankFrame、CheckinFrame、GameFrameEngine、LevelFrame、LogonFrame、ModifyFrame、ShopDetailFrame、TaskFrame的构造函数
BankFrame:ctor这个函数理解为构造函数
BankFrame.super.ctor(self,view,callbcak),这一行的意思是调用基类的构造函数,也就是BaseFrame的构造函数
那么我们来看看BaseFrame的ctor函数都干了啥,打开src\plaza\models\BaseFrame.lua,看ctor函数
local BaseFrame = class("BaseFrame")

function BaseFrame:ctor(view,callback)
 self._viewFrame = view
 self._threadid  = nil
 self._socket    = nil
 self._callBack = callback
end

self.name = appName
 self.packageRoot = packageRoot or "app"

src\plaza\models\BankFrame.lua
local BankFrame = class("BankFrame",BaseFrame)
function BankFrame:ctor(view,callbcak)
 BankFrame.super.ctor(self,view,callbcak)
end

src\plaza\models\CheckinFrame.lua
local CheckinFrame = class("CheckinFrame",BaseFrame)

function CheckinFrame:ctor(view,callbcak)
 CheckinFrame.super.ctor(self,view,callbcak)
end

src\plaza\models\GameFrameEngine.lua
local GameFrameEngine = class("GameFrameEngine",BaseFrame)
function GameFrameEngine:ctor(view,callbcak)
 GameFrameEngine.super.ctor(self,view,callbcak)
 self._kindID = 0
 self._kindVersion = 0
end

src\plaza\models\LevelFrame.lua
local LevelFrame = class("LevelFrame",BaseFrame)

function LevelFrame:ctor(view,callbcak)
 LevelFrame.super.ctor(self,view,callbcak)
end

src\plaza\models\LogonFrame.lua
local LogonFrame = class("LogonFrame",BaseFrame)
function LogonFrame:ctor(view,callback)
 LogonFrame.super.ctor(self,view,callback)
 self._plazaVersion = appdf.VersionValue(6,7,0,1)
 self._stationID = yl.STATION_ID
 local targetPlatform = cc.Application:getInstance():getTargetPlatform()
 local tmp = yl.DEVICE_TYPE_LIST[targetPlatform]
 self._deviceType = tmp or yl.DEVICE_TYPE
 self._szMachine = MultiPlatform:getInstance():getMachineId()

 self.m_angentServerList = {}
end

src\plaza\models\ModifyFrame.lua
local ModifyFrame = class("ModifyFrame",BaseFrame)

function ModifyFrame:ctor(view,callbcak)
 ModifyFrame.super.ctor(self,view,callbcak)
end


src\plaza\models\ShopDetailFrame.lua
local ShopDetailFrame = class("ShopDetailFrame",BaseFrame)

 

function ShopDetailFrame:ctor(view,callbcak)
 ShopDetailFrame.super.ctor(self,view,callbcak)
end


src\plaza\models\TaskFrame.lua
local TaskFrame = class("TaskFrame",BaseFrame)

function TaskFrame:ctor(view,callbcak)
 TaskFrame.super.ctor(self,view,callbcak)

 self.m_tabTaskInfo = {}
 self.m_tabTaskInfo.tasklist = {}
end

 

20170512添加:
问题:Lua如何解析网络通信中的结构体?
1、笨办法:
通过luabinding进行struct的绑定。
这样做的缺点是显而易见的:因为通讯接口较多,struct定义也会比较多,而且如果修改了通讯接口,还得重新编译so,所以LUA和C++的耦合度大。
2、网狐荣耀lua框架采用的办法:
直接在LUA中构建一个struct与服务端进行通信,以及获取到服务端返回的数据后,转换成对应的table。

网络数据处理CMD_Data.h暴露给lua用的接口
// C++服务器/LUA手机端
#define LEN_MD5      33         //加密密码
#define LEN_ACCOUNTS    32         //帐号长度
#define LEN_MACHINE_ID    33         //序列长度
#define LEN_MOBILE_PHONE   12         //移动电话
#define MDM_MB_LOGON    100         //广场登录
#define SUB_MB_LOGON_ACCOUNTS  2         //帐号登录
//帐号登录
struct CMD_MB_LogonAccounts
{
 //系统信息
 WORD       wModuleID;       //模块标识
 DWORD       dwPlazaVersion;      //广场版本
 BYTE                            cbDeviceType;                       //设备类型

 //登录信息
 TCHAR       szPassword[LEN_MD5];    //登录密码
 TCHAR       szAccounts[LEN_ACCOUNTS];   //登录帐号

 //连接信息
 TCHAR       szMachineID[LEN_MACHINE_ID];  //机器标识
 TCHAR       szMobilePhone[LEN_MOBILE_PHONE]; //电话号码
};

src\plaza\models\LogonFrame.lua
--CMD_MB_LogonAccounts
function LogonFrame:sendLogon()
 local LogonData = CCmd_Data:create(235)--whry6801服务器在UTF16和1字节对齐下编译,包体为227字节,包头为8字节
 LogonData:setcmdinfo(yl.MDM_MB_LOGON,yl.SUB_MB_LOGON_ACCOUNTS)--设置主命令、子命令
 LogonData:pushword(GlobalUserItem.nCurGameKind)
 LogonData:pushdword(self._plazaVersion)
 LogonData:pushbyte(self._deviceType)

 LogonData:pushstring(string.upper(md5(self._szPassword)),yl.LEN_MD5)

 LogonData:pushstring(self._szAccount,yl.LEN_ACCOUNTS)
 LogonData:pushstring(self._szMachine,yl.LEN_MACHINE_ID)
 LogonData:pushstring(self._szMobilePhone,yl.LEN_MOBILE_PHONE)

 --print("send logon:account-"..self._szAccount.." password-"..self._szPassword)
 
 --发送失败
 if not self:sendSocketData(LogonData) and nil ~= self._callBack then
  self._callBack(-1,"发送登录失败!")
 end
end

src\plaza\models\yl.lua
yl.LEN_MD5        = 33   --加密密码
yl.LEN_ACCOUNTS       = 32   --帐号长度
yl.LEN_MACHINE_ID      = 33   --序列长度
yl.LEN_MOBILE_PHONE      = 12   --移动电话
yl.MDM_MB_LOGON       = 100   --广场登录
yl.SUB_MB_LOGON_ACCOUNTS    = 2    --帐号登录

二维码QrNode.h暴露给lua用的接口
src\plaza\views\layer\plaza\UserInfoLayer.lua
第30行
self.m_qrContent = GlobalUserItem.szSpreaderURL or yl.HTTP_URL
local qr = QrNode:createQrNode(self.m_qrContent, 500, 5, 1)--创建二维码node:二维码内容,尺寸,点大小,二维码level
self.m_spBg:addChild(qr)
qr:setPosition(bgsize.width * 0.5, bgsize.height * 0.5)
self.m_qrNode = qr

C和C++程序员的Lua快速入门指南
http://www.docin.com/p-97369880.html
Robert Z
2010年1月
前言
本文只打算告诉读者Lua那些与C/C++相比显著不同的特性以及它们实际上带来了怎样截然不同于C/C++的思维方式。
初阶话题:数据类型、函数、表、简单对象的实现、简单继承
八种类型:
数值number:内部以double表示的数据类型。
字符串string:由任意字符组成的以零结尾的字符序列;不等价于C字符串,而是其超集。
布尔boolean:只有true或者false两个值的逻辑类型。
函数function:基本的Lua对象;不简单等同于C的函数或函数指针;Lua的关键概念之一。
表table:异构的Hash表;也是Lua的关键概念。
userdata:C用户定义的C数据结构;脚本用户只能使用它,不能定义。
线程thread:Lua协作线程(coroutine);与一般操作系统的抢占式线程不一样。
nil:代表什么也没有,在mouzhong可以与C的NULL作类比,但它不是空指针。

用关键字function定义函数,以关键字end结束
function foo(a,b,c)
local sum=a+b
return sum,c--函数可以返回多个值
end

r1,r2=foo(1,'123','hello')--平行赋值
print(r1,r2)

输出结果:
124 hello
平行赋值
a,b=c,d
如果没有用local定义,即使在函数内部定义的变量也是全局变量。
 
定义表的方式
a={},b={...}
通过.或者[]运算符来访问表的成员。
注意:表达式a.b等价于a["b"],但不等价于a[b]
任何类型的变量,除了nil,都可以做为表项的键或值。给一个表项的值赋nil意味着从表中删除这一项,比如令a.b=nil,则把表a中键为"b"的项删除。
另外,如果访问一个不存在的表项,其值是nil。比如有c=a.b,但表中没有键为"b"的项,则c等于nil。
--穷举表a
for k,v in pairs(a) do
   print(k,"=>",v)
end
 
一种简单的对象实现方式
对象工厂模式
用表来表示对象,把对象的数据和方法都放在一张表内,虽然没有隐藏私有成员,但对于简单脚本来说完全可以接受。
成员方法的定义
function obj:method(a1,a2,...)...end等价于
function obj.method(self,a1,a2,...)...end等价于
obj.method=function(self,a1,a2,...)...end
成员方法的调用
obj:method(a1,a2,...)等价于
obj.method(obj,a1,a2,...)

简单继承
优点:简单、直观
缺点:传统、不够动态


进阶话题:函数闭包、基于对象的实现方式、元表、基于原型的继承、函数环境、包
Upvalue是Lua不同于C/C++的特有属性。
一个函数和它的所有upvalue构成一个函数闭包。
Lua函数闭包使函数在几次调用间具有保持它自己状态的能力,可以产生同一类型的若干实例,每个实例都有自己的状态。
基于对象的实现方式
把需要隐藏的成员放在一张表里,把该表作为公有成员函数的upvalue;再把所有的共有成员放在另一张表里,把这张表作为对象。

元表本身只是一个普通的表,一般带有一些特殊的事件回调函数,通过setmetatable被设置到某个对象上进而影响这个对象的行为。
回调事件(比如__index和__add)由Lua定义而回调函数由脚本用户定义并在相应事件发生时由Lua虚拟机调用。
基于原型的继承
prototype模式
一个对象既是一个普通的对象,同时也可以作为创建其他对象的原型的对象(即类对象,class object);动态的改变原型对象的属性就可以动态的影响所有基于此原型的对象;
另外,基于一个原型被创建出来的对象可以重载任何属于这个原型对象的方法、属性而不影响原型对象;同时,基于原型被创建处来的对象还可以作为原型来创建其他对象。

函数环境就是一个函数在运行时所能访问的全局变量的集合,装在一个表中。在缺省状态下,一个函数与定义它的函数共享同一个环境;但是每个函数都可以有自己的环境,通过setfenv来设定。
函数环境是Lua相对于C/C++所独有的特性之一。利用它可以实现函数执行的“安全沙箱”;另外Lua的包的实现也依赖它。
包是一种组织代码的方式。
一般在一个Lua文件内以module调用开始定义一个包。
module调用同时为这个Lua文件定义了一个新的函数环境。
Lua虚拟机把一个Lua文件的内容当作一个函数体来处理。设定了一个新的函数环境后,Lua文件所定义的所有全局变量都保存在那个表里。
一般用require函数来导入一个包,要导入的包必须被置于包路径上。包路径可以通过package.path或者环境变量来设定。一般来说,当前工作路径总是在包路径中。
高阶话题:迭代iteration、协作线程coroutine











©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页