跳转至

cocos2dx-lua项目迁移到Cocos Creator

目前在工作中遇到一些比较老的项目想要发布到H5平台,所以就出现了从cocos2dx-lua项目迁移到Cocos Creator的需求 这里将讲述用得到的一些步骤和需要注意的问题

step1 Lua转换为TypeScript

在nodejs中有一个模块叫lua-to-typescript,安装之后通过这个模块来转换

yarn global add lua-to-typescript
# or
npm install -g lua-to-typescript

然后使用ltts命令行来转换

ltts --help 
#查看帮助
ltts main.lua 
#生成main.ts,后面的参数是需要转换的文件路径

ltts a.lua b.lua c.lua ...
#生成 a.ts, b.ts, c.ts, ...

ltts -d library.lua
# 生成 library.d.ts

如果希望直接转换整个目录的话,你可以使用bat,当然你需要在相应的目录中执行

for /R %%i in (*.lua) do ltts %%i

PS:执行脚本过程中可能遇到的问题,目前不支持do end语法(好像还有其他的,但是我忘记了,回头补充)

step2 ccbi转化为Prefab

这个请参考之前的文章ccbi转换为ccb

step3 代码部分的修补

  • lua中的数组下标从1开始,而ts是从0开始,所以需要注意
  • 使用脚本转换后,目前我观察到的elseif语句的条件和结果都会出问题,具体表现是

    --乱代码如下
      if i == 1 then
          print("a")
      elseif i == 2 then
          print(b)
      end
    
    //转换后的ts代码
      if (i == 1) {
          print("a")
      }  
      else (i == 1) {
          print("a")
      }
    
    可以看到明显的错误,这部分也需要自己单独处理

  • 静态函数或者说方法可能需要单独处理

  • this的指向问题 很多时候函数的转换会是这样

    class a{
        count = 1;
        test(){
            function foo(){
                this.count = this.count + 1;
            }
    
            foo();
        }
    }
    
    在lua中这没有问题,但是到ts中this的指向这个时候变成了Window,所以count是取不到的,需要修改为

    ```ts class a{ count = 1; test(){ let foo = ()=> { this.count = this.count + 1; } foo(); } } - 部分for循环

    for (const [i, v] of ipairs(array)) {
        foo(v);
    }
    
    ipairs这个关键字也不能被正常转换,需要修正为
    for(let i = 0; i < array.length; i++){
        let v = array[i];
        foo(v);
    }
    
    - lua中table到ts后的实际类型 在ts中table更像是ts中的objcet,没有明确的结构,在转换时可能出现下面2种情况
    - 正常转化为数组
    --原始数组
    local array = {1,2,3,4}
    

     //转化后
     let array = [1,2,3,4];
    
    - 转化为object
    --原始数组
    local array = {
       a:1,
       b:2,
       c:3
    }
    

    //转化后
    let array = array = {
       a:1,
       b:2,
       c:3
    };
    
    在第1种转换后你可以用之前提到的for循环处理,但是第二种就不行了 你需要使用如下代码来循环
     for (const k in array) {
         if (Object.prototype.hasOwnProperty.call(array, k)) {
             let v = array[k];
         }
     }
    

    step4 prefab的修补

    • 图片尺寸异常 ccbi转换到prefab后可能因为版本的部分,采用SLICED模式的图片尺寸会丢失,这个时候只能挨个查看修改
    • 互相引用的ccbi文件丢失 比如在A.ccbi中包含了B.ccbi,那转换到prefab后可能就不会显示B了,而且也不知道引用了B,只知道引用了一个ccbFile,这个也只能是你根据原版来查看判断引用的是哪个
    • 字号异常 当使用自制的字体时通常会出现这个问题,也只能自己按个找到引用然后修改了
    • Button组件的修改 在转换过程中通常Button会挂载4张图片,供4个状态使用,但是转换过来的prefab中并没有指定带有sprite组件的target所以并不能顺利的达到想要的效果,只能手动给Button组件指定target

step5 针对Cocos2dx-Lua特有的一些问题

  • TableView的转化
    在cococs creator中并没有专门的TableView,通常我使用ScrollView来替代,比如
        function Test:reloadListView()
            local boardWidth = self._rootnode.listView:getContentSize().width
            local boardHeight = self._rootnode.listView:getContentSize().height
            local function createFunc(index)
                local item = require("Item").new()
                return item:create({
                    viewSize = cc.size(boardWidth, boardHeight),
                    itemData = self._listData[index + 1],
                    openFunc = function(cell)
                        local idx = cell:getIdx() + 1
                        local itemData = self._listData[idx]
                        foo(itemData)
                    end
                })
            end
            local function refreshFunc(cell, index)
                cell:refresh(self._listData[index + 1])
            end
            local cellContentSize = require("Item").new():getContentSize()
            self._listViewTable = require("utility.TableViewExt").new({
                size = cc.size(boardWidth, boardHeight),
                direction = kCCScrollViewDirectionVertical,
                createFunc = createFunc,
                refreshFunc = refreshFunc,
                cellNum = #self._listData,
                cellSize = cellContentSize
            })
            self._listViewTable:setPosition(0, 0)
            self._rootnode.listView:addChild(self._listViewTable)
        end
    
    转换后
    class test{
        listView: cc.ScrollView;
        _listData: any[];
        reloadListView(){
            let length = Math.max(this.listView.content.length, this._listData.length);
            for (let index = 0; index < length; index++) {
                const data = this._listData[index];
                let node = this.listView.content.children[index];
                if (data) {
                    if (!node) {
                        let item = await Item.createNode();
                        item.init({
                            index: index,
                            itemData: data,
                            openFunc: (cell: GuildFuliItem) => {
                                let itemData = cell.itemData;
                                foo(itemData);
                            }
                        });
                        this.listView.content.addChild(item.node);
                    }
                    else {
                        let item = node.getComponent(GuildFuliItem);
                        item.refresh({
                            index: index,
                            itemData: data
                        });
                    }
                }
                else if (node) {
                    node.active = false;
                }
            }
        }
    }
    
    const { ccclass, property } = cc._decorator;
    @ccclass
    class Item extends cc.Component {
        itemData;
        openFunc;
        static async createNode() {
            //ResMgr.loadPrefab的具体实现没有在这里写明,就是加载Prefab
            let node = cc.instantiate(await ResMgr.loadPrefab("item"));
            return node.addComponent(Item);
        }
    
        init(param: {
            itemData,
            openFunc: Function,
        }) {
            this.openFunc = param.openFunc;
            this.refreshItem(param);
        }
    
        refresh(param: {
            itemData,
        }) {
            this.refreshItem(param);
        }
    
        refreshItem(param: {
            itemData: GuildFuliData
        }) {
            this.itemData = param.itemData;
            //具体实现不写了
        }
    }
    
    这样转化之后基本上能和之前的TableView保持一致,唯一可能存在的问题是当列表数据太多时,性能上会有影响
  • 添加Button和Sprite等组件时的差异 在cocos2dx中基本上Button等都是节点的子类,但是到了cocos creator中就变成了组件,都需要单独挂载在一个节点上,所以一定要弄清楚要操作的是节点还是组件

写在最后

本文是本人在最近转换项目时所遇到的真实案例,可能还有一些地方忘记了,后续补充,有疑问可以页面右下角邮件我,不定期回复.

友情链接