2.x升级3.3的完整教程 (保留js文件)

攒劲的节目

此贴可引导js项目升级至3.3,并保留js文件来降低升级风险,线上中大项目一两个bug带来的损失都是难以估量的
(对于小游戏开发者、新人及编程习惯不成形的开发者,仍然建议手动升级js文件为ts)
此贴的升级方式尽可能的保护项目原内容,减少工作量,能保留js内容也让大型项目升级3.3成为可能。

3.3优秀在哪里?

相信大多数人看了直播里对3.3的各项优点介绍,很明显,3D的提升是巨大的,引擎团队基本将所有的精力都放在了3D上面,尽管直播时没有低端机甚至中端机的性能表现,但未来可期。一个是ts直接转译c++的大饼,还有一个是引擎团队许诺近期版本都将对性能着重优化。

要不要升级?基于升级风险,做以下分析建议

if(你是独立开发者){
   if(小游戏){
       if(纯2D游戏){
         无升级必要,3.3的2d性能并没有多大的提升,如果体量较小,可尝试升级,无所谓
       }else{
         //3D游戏
         升吧,代码也不多,工作量可控
		 //2D游戏但有加入3D内容的想法
		 根据游戏内容和未来计划决定升级时间
       }
   }else{
       //中大型
	   笔者就属于此情况,而且游戏当前是纯2D手游。
	   为什么要升级,是因为3D游戏优秀的代入感,独立开发者做手游,整个人都是绑在这个游戏上的,策划、开发、美工、运维、客服等等,而且笔者有长期运维游戏的打算,十年八年的,时刻出新的引擎是跟上节奏的保证
   }
}else if(你是公司员工){
   在升级过程中,基本上新的开发内容都是暂停的,这在大多数公司都是无法接受的,而且升级过程中的协作问题也很麻烦。公司的项目很多都是流水线作品,2D项目无升级的必要,而且引擎团队对2.x提供两年的持续维护。
   对于3.3,更多的是考虑3D,这是主要衡量点。
   就算项目是2.x的纯3D内容,也要有个衡量,api有大量的变动,不过2.x的大型3D游戏不太多,具体情况就请具体分析了。
}

step1

如果你当前低于2.4.6,先升级至2.4.6,因为3.3的升级导入插件对2.4.6兼容。2.x->2.4.6工作量并不多,这一步也可以当作试炼,如果这一步就遇到了问题且解决起来找不到头绪,就不要向下尝试了。

step2

将升级后的2.4.6项目备份,如果升级3.3失败,2.4.6的项目也可以拿来作为主力版本。

新建3.3项目,下载修改后的导入插件,修改版取消了插件对 js->ts 自动转换,插件的js转ts功能就像一坨shit,而且基本所有的js文件都不能顺利转换,而且作者会很贴心的提醒你:我转不了,但我把你以前的代码都注释了,你自己转吧 [微笑]
https://pan.baidu.com/s/138mYH55vXs6XyHAakhicsg
a2n4

插件的使用方法

插件准备就绪后关闭编辑器

step3

找到3.3项目的package.json文件,将type:3d 改为 type:module [重要!这将直接影响编辑器能否将js文件识别为模块]

有关于模块的官方说明

官方升级指南(必读)

step4

使用编辑器打开项目,设置插件为启用状态 (扩展-管理器-项目|全局)

使用插件导入2.4.6项目

此时编辑器的报错很多,不要着急,慢慢来

修改所有require为import,如果对import和export不太熟练,请恶补es6相关内容

导入js的语句需带有js文件格式,而ts不用,官方对模块的说明中有提及

import * as TD_Match_Scripts from "../../UISubLayer/TD_Match_Scripts";
import * as GameScripts from "../../UILayer/UI_PVPTDScripts.js"

js文件ccclass修改为如下形式

举例

2.x写法

cc.Class({
extends: cc.Component,

properties: {
   nameLabel:cc.Label,
    timeLabel:cc.Label,
    countLabel:cc.Label,
    mainSP:cc.Sprite,

    itemID:null,
},

initCell:function (itemID,timeText,CountText) {
  let self = this;
  self.itemID = itemID;
  //巴拉巴拉
  
},
itemClick:function(){},

onBtnDetail:function(){
    var self = this;
    cc.ll.mainGameView.showInfo(cc.ll.gameData.getItemHelp(cc.ll.gameData.getItemTypeID(self.itemID)))
},

});

3.x写法

import * as cc from “cc”;

const {
ccclass,
property
} = cc._decorator;
@ccclass
export default class extends cc.Component {

@property(cc.Label)
nameLabel = null;
@property(cc.Label)
timeLabel = null;
@property(cc.Label)
countLabel = null;
@property(cc.Sprite)
mainSP = null;
itemID = null;

initCell(itemID, timeText, CountText) {
    let self = this;
    self.itemID = itemID;
    //巴拉巴拉
}

itemClick() {
}

onBtnDetail() {
    var self = this;
    cc.ll.mainGameView.showInfo(cc.ll.gameData.getItemHelp(cc.ll.gameData.getItemTypeID(self.itemID)))
}

}

在此附上主要改动代码,供复制粘贴使用

import * as cc from “cc”; //此语句大幅减少代码修改量,四处的cc.,那无处不在的青春
const {ccclass,property} = cc._decorator;
@ccclass
export default class test extends cc.Component {
//将ccclass里的内容复制在此,props做修改,方法全部替换即可,多写几次就会很快了
}

常用组件声明

@property(cc.Label)

@property(cc.Button)

@property(cc.ScrollView)

@property(cc.Prefab)

@property(cc.Node)

@property(cc.SpriteAtlas)

@property(cc.Sprite)

@property(cc.Font)

@property(cc.EditBox)

@property(List)

@property(cc.RichText)

@property(cc.SpriteFrame)

@property(cc.ProgressBar)

@property(cc.Toggle)

@property(cc.Slider)

在修改完一个以后,在编辑器添加组件,在自定义组件出现了你的ccclass才算成功,此时打开绑定了脚本组件的prefab | node,查看之前在2.x的绑定是否还在,如下图


(赞一下写这一块的引擎组成员,变量绑定不会丢失,这也是升级的关键所在)

至此js文件模块的支持就完成了。

step5

effect的升级

直接拿我升级后的effect为大家做对比演示

2.x

//流光shader
CCEffect %{
techniques:

  • passes:
    • vert: vs
      frag: fs
      blendState:
      targets:
      • blend: true
        rasterizerState:
        cullMode: none
        properties:
        texture: { value: white }
        u_fluxayTexture: { value: white }
        u_fluxaySpeed: { value: 1 }
        u_startPos: { value: -0.6 }
        u_UVoffset: { value: [1,0,0,1] }
        u_rotated: { value: 0 }
        u_time: { value: 0 }
        }%

CCProgram vs { #include <cc-global> precision highp float; in vec3 a_position; in vec2 a_uv0; out vec2 uv0; void main () { gl_Position = cc_matViewProj * vec4(a_position, 1); uv0 = a_uv0; } }

CCProgram fs %{
precision highp float;
in vec2 uv0;
uniform sampler2D texture;
uniform ARGS {
vec4 u_UVoffset;
float u_startPos; //流动的时间
float u_rotated;
float u_time;
float u_fluxaySpeed;
sampler2D u_fluxayTexture; //流光图纹理
}
void main()
{
vec2 UVnormalize;
UVnormalize.x = (uv0.x-u_UVoffset.x)/(u_UVoffset.z-u_UVoffset.x);
UVnormalize.y = (uv0.y-u_UVoffset.y)/(u_UVoffset.w-u_UVoffset.y);
if(u_rotated > 0.5)
{
float temp = UVnormalize.x;
UVnormalize.x = UVnormalize.y;
UVnormalize.y = 1.0 - temp;
}

    vec4 src_color = texture2D(texture, uv0).rgba;
    //调整第二张图的UV,调整其x使其产生流动效果
    vec2 flow_uv = vec2(UVnormalize.x,UVnormalize.y);
    flow_uv.x -= (u_time*u_fluxaySpeed)+u_startPos;

    vec4 src_color1 = texture2D(u_fluxayTexture, flow_uv).rgba;
    //根据底图是否有颜色来判断是否显示流光
    if(src_color.a >= 1.0) {
        gl_FragColor = src_color+src_color1;
    }
    else {
        gl_FragColor = src_color;
    }
}

}%

3.3

//流光shader
CCEffect %{
techniques:

  • passes:
    • vert: unlit-vs
      frag: unlit-fs:frag
      blendState:
      targets:
      • blend: true
        rasterizerState:
        cullMode: none
        properties:
        u_fluxayTexture: { value: white }
        u_fluxaySpeed: { value: 1 }
        u_startPos: { value: -0.6 }
        u_UVofunlit_fset: { value: [1,0,0,1] }
        u_rotated: { value: 0 }
        u_time: { value: 0 }
        }%

CCProgram unlit-vs { #include <cc-global> precision highp float; in vec3 a_position; in vec2 a_texCoord; out vec2 uv0; void main () { gl_Position = cc_matViewProj * vec4(a_position, 1); uv0 = a_texCoord; } }

CCProgram unlit-fs %{
precision highp float;
#include
in vec2 uv0;

#pragma builtin(local)
layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;

  uniform sampler2D u_fluxayTexture;  //流光图纹理
uniform ARGS {
    vec4  u_UVofunlit_fset;
    float u_startPos;           //流动的时间
    float u_rotated;
    float u_time;
    float u_fluxaySpeed;
};

vec4 frag()
{ 

    vec2 UVnormalize;
    UVnormalize.x = (uv0.x-u_UVofunlit_fset.x)/(u_UVofunlit_fset.z-u_UVofunlit_fset.x);
    UVnormalize.y = (uv0.y-u_UVofunlit_fset.y)/(u_UVofunlit_fset.w-u_UVofunlit_fset.y);
    if(u_rotated > 0.5)
    {
        float temp = UVnormalize.x;
        UVnormalize.x = UVnormalize.y;
        UVnormalize.y = 1.0 - temp;
    }

    vec4 src_color = texture(cc_spriteTexture, uv0).rgba;
     
    //调整第二张图的UV,调整其x使其产生流动效果
    vec2 flow_uv = vec2(UVnormalize.x,UVnormalize.y);
    flow_uv.x -= (u_time*u_fluxaySpeed)+u_startPos;

    vec4 src_color1 = texture(u_fluxayTexture, flow_uv).rgba;
    //根据底图是否有颜色来判断是否显示流光
    if(src_color.a >= 1.0) {
        return (src_color+src_color1);
    }
    else {
        return (src_color);
    }
   
}

}%

Fluxay.effect.zip (1.1 KB)

可以对比寻找改变,圈几个重点吧

   1.a_texCoord 

   2.#include <output>

   3.#pragma builtin(local)
     layout(set = 2, binding = 10) uniform sampler2D cc_spriteTexture;

   4.return (src_color);

至于接口的改变,就需要大家一点点的修改了,务必要小心。

踩坑指南

需要注意的是3.3的z轴,详情可查看api文档

1.setposition(v2)在3.3是会导致NODE的_pos为NAN,也就是不生效

2…position返回的是只读v3
个人辅助工具,可将setPosition()统一替换为setPositionEx,减少工作量

cc.Node.prototype.setPositionEx = function () {
    let self = this;
    if (arguments.length == 1) {
        let v = arguments[0];
        if (v instanceof cc.Vec2) {
            //v2类型
            self.setPosition(v.x, v.y, 0)
        }
        if (v instanceof cc.Vec3) {
            //v3类型
            if (isNaN(v.z)) v.z = 0;
            self.setPosition(v)
        }
    } else if (arguments.length == 2) {
        self.setPosition(arguments[0], arguments[1])
    } else if (arguments.length == 3) {
        self.setPosition(arguments[0], arguments[1], arguments[2])
    }
}

3.setScale(1) 是错误的写法

个人辅助工具

cc.Node.prototype.setScaleEx = function () {
    if (arguments.length == 1) {
        this.setScale(arguments[0], arguments[0])
    } else if (arguments.length == 2) {
        this.setScale(arguments[0], arguments[1])
    } else if (arguments.length == 3) {
        this.setScale(arguments[0], arguments[1], arguments[2])
    } 
}

4

aa = cc.v2(1,1)
bb = cc.v2(2,2)
let cc = aa.add(bb) 并不会返回新的v2,而是aa变为 (3,3),即addself,加减乘除都是如此,请格外注意少踩坑,3.3正确写法为 let cc = aa.clone().add(bb);

5.jumpto fadeto 等一些action都废弃了

6.addChild的修改,见文档,另外子child被add后,其layer并不会随父节点修改,如果相机视野不对应其layer,会导致看不到child
减少工作量辅助,对应2.x addchild,同时解决layer不随变问题

cc.Node.prototype.addChildEx = function (child, zIndex, name) {
    if (typeof zIndex != undefined && zIndex) {
        child.zIndex = zIndex;
    }
    if (typeof name != undefined && name) {
        child.name = name;
    }
    child.layer = this.layer;
    this.addChild(child);
}

7.zIndex取消,排序有 UITransform和 * setSiblingIndex

减少工作量辅助

Object.defineProperty(cc.Node.prototype, "zIndex", {
    get: function() {
        let t = this.getComponent(UITransform)
        return t ? t.priority : 0
    },

    set: function(priority) {
        let t = this.getComponent(UITransform)
        if(!t) {
            t = this.addComponent(UITransform)
        }

        t.priority = priority

    },
    enumerable: true,
    configurable: true,
})

8.camera的修改,需额外注意Z轴和far属性,screenToWorld传参也需传入v3

9.tween的坑挺多的

持续增加中…

下面的帖子有3.x protobuf,crypto-js

因笔者项目代码量巨多,一个个踩坑导致升级的持续时间较长,且在升级的过程中,线上的游戏也需一些重要的更新,近期没有持续升级,升级中的一些操作可能没想起来,将持续添加。

ps:线上游戏的更新合并到3.3又是痛苦的过程

9赞

支持一下,题主这个是真是执着

既然是坚定的TypeScript支持者,那就顺手把文件名的js后缀也改成ts同时把对应的meta里的类型也换一下吧…

个人建议:不要升,一堆bug等你发现,我公司项目也有用到3d,其中一些效果在2.x好好的,3.x就不一样了,还无法修改

经过我的一些测试,3.3的2d性能好像不如2.x,但还没有拿出源生对比,所以还没有什么证据

1赞

no,我认为ts就是垃圾,es6天下无敌,
只有能效率转换为金钱的技术才是好技术。
只有菜鸟纠结技术,这也是为什么策划一直瞧不起程序员的原因。

1赞

个人辅助工具,扩展Node后并没办法使用,是需要处理什么吗?image

哪个proto?发来看看,直接给你js文件

大胆!哪里的小小策划胆敢嚣张,下次提需求给本大人先微信扫码付款!

大佬!能帮我看看我这几个2.x的脚本要怎么升级到3.4版本能用呢?我自己改了好久,改不动了,这里还是把原来的脚本给你看一下tool.zip (18.1 KB)

你像这个fn.ts ,这不都改的差不多了,import * as cc from ‘cc’ 这样可以省事,在3.x中,cc不再是全局,需要什么模块则导入什么

刚好就是其他的我改不来了,比如说Dict里面的找不到我声明的dict,或者是@property(StateSwitch)在编辑器里面直接识别不了,可以的话能加一下好友吗,真心请教一下

我的qq:824151370

大佬帮帮忙!!有偿也行,只要能让这几个脚本在3.4能正常使用或者你来操刀另外写一份实现相同的功能脚本

TS的改动我并不擅长,这个帖子是让你在3.x中直接使用2.x旧版本的js文件,无需改成ts

啊这…(哭唧唧