从Unity到Cocos

Cocos Creator 2.4x 笔记 - 从Unity到C

2021-04-25  本文已影响0人  zitaoye

内容基本来自Copy Paste Cocos Creator 的官网文档
主要来自于阅读的时候同时做笔记

CC Class

CCclass 构造函数 ctor: function () {}

声明变量的时候加上类型,本质上是在声明处填写构造函数,设置get/set方法
playerNode:cc.Node

节点访问和常用接口

获取组件所在的节点this.node

获取其他组件
通过类型 this.getComponent(cc.Label);
通过类名 var rotate = this.getComponent("SinRotate");

模块化方法 var Player = require("Player"); 然后 player:{defualt:null , type:Player}

查找子节点this.node.children
his.node.getChildByName("Cannon 01");
cc.find("Cannon 01/Barrel/SFX", this.node);

全局查找,只有一个参数的find
this.backNode = cc.find("Canvas/Menu/Back");

通过全局变量访问或require模块化方法来实现跨文件操作
var Global = require("Global");

节点激活 this.node.active = false;

更改父节点 this.node.parent = parentNode;

更改节点位置
this.node.x = 100;
this.node.setPosition(cc.v2(100, 50));

更改节点旋转
this.node.rotation = 90;
this.node.setRotation(90);

缩放
this.node.scaleX = 2;this.node.setScale(2);

尺寸
this.node.width = 100;this.node.setContentSize(cc.size(100, 100));

锚点位置
this.node.setAnchorPoint(1, 0);this.node.anchorX = 1;

颜色透明度

在使用 Sprite、Label 这些基本的渲染组件时,要注意修改颜色和不透明度的操作只能在节点的实例上进行,因为这些渲染组件本身并没有设置颜色和不透明度的接口。)

mySprite.node.color = cc.Color.RED;
mySprite.node.opacity = 128;

cc.Component 是所有组件的基类,任何组件都包括如下的常见接口(该组件的脚本中,以 this 指代本组件):

this.node:该组件所属的节点实例
this.enabled:是否每帧执行该组件的 update 方法,同时也用来控制渲染组件是否显示
update(dt):作为组件的成员方法,在组件的 enabled 属性为 true 时,其中的代码会每帧执行
onLoad():组件所在节点进行初始化时(节点添加到节点树时)执行
start():会在该组件第一次 update 之前执行,通常用于需要在所有组件的 onLoad 初始化完毕后执行的逻辑

创建节点
new cc.Node() 并且通过node.addComponent(cc.Sprite)方式来进行
克隆和根据Prefab预制件生成节点 cc.instantiate

销毁节点 node.destroy() 销毁节点并不会立刻被移除,而是在当前帧逻辑更新结束后,统一执行。当一个节点销毁后,该节点就处于无效状态,可以通过 cc.isValid 判断当前节点是否已经被销毁。if (cc.isValid(this.target))

生命周期回调 Lifetime Callback Function | 链接

onLoad 组件脚本的初始化阶段,我们提供了 onLoad 回调函数。onLoad 回调会在节点首次激活时触发,比如所在的场景被载入,或者所在节点被激活的情况下。在 onLoad 阶段,保证了你可以获取到场景中的其他节点,以及节点关联的资源数据。onLoad 总是会在任何 start 方法调用前执行,这能用于安排脚本的初始化顺序。通常我们会在 onLoad 阶段去做一些初始化相关的操作
start start 回调函数会在组件第一次激活前,也就是第一次执行 update 之前触发。start 通常用于初始化一些需要经常修改的数据,这些数据可能在 update 时会发生改变。
update 游戏开发的一个关键点是在每一帧渲染前更新物体的行为,状态和方位。
lateUpdate update 会在所有动画更新前执行,但如果我们要在动效(如动画、粒子、物理等)更新之后才进行一些额外操作,或者希望在所有组件的 update 都执行完之后才进行其它操作,那就需要用到 lateUpdate 回调。

onEnable当组件的 enabled 属性从 false 变为 true 时,或者所在节点的 active 属性从 false 变为 true 时,会激活 onEnable 回调。倘若节点第一次被创建且 enabled 为 true,则会在 onLoad 之后,start 之前被调用。

onDisable 当组件的 enabled 属性从 true 变为 false 时,或者所在节点的 active 属性从 true 变为 false 时,会激活 onDisable 回调。

onDestroy当组件或者所在节点调用了 destroy(),则会调用 onDestroy 回调,并在当帧结束时统一回收组件。当同时声明了 onLoadonDestroy 时,它们将总是被成对调用。也就是说从组件初始化到销毁的过程中,它们要么就都会被调用,要么就都不会被调用。

一个组件从初始化到激活,再到最终销毁的完整生命周期函数调用顺序为:onLoad -> onEnable -> start -> update -> lateUpdate -> onDisable -> onDestroy

onLoad 节点激活时立即调用 组件 enabled 时才会调用?否
start 节点激活时延迟调用 组件 enabled 时才会调用?是

加载和场景切换

通过场景名索引和加载切换cc.director.loadScene("MyScene");
对于AssetBundle区分加载和运行需要使用 cc.director.runScene(scene);

如果需要有全局不因为场景加载而销毁的常驻节点,类似Unity DontDestroyOnLoad 可以使用常驻节点,或全局变量访问
cc.game.addPersistRootNode(myNode); 会将 myNode 变为常驻节点,这样挂在上面的组件都可以在场景之间持续作用,我们可以用这样的方法来储存玩家信息,或下一个场景初始化时需要的各种数据。
取消常驻 cc.game.removePersistRootNode(myNode);

场景加载回调函数 cc.director.loadScene("MyScene", onSceneLaunched); 上一行里 onSceneLaunched 就是声明在本脚本中的一个回调函数,在场景加载后可以用来进一步的进行初始化或数据传递的操作。由于回调函数只能写在本脚本中,所以场景加载回调通常用来配合常驻节点,在常驻节点上挂载的脚本中使用。

预加载 cc.director.preloadScene(string sceneName, callback()) 可以静默加载等待

设置和获取资源

所有继承自 cc.Asset 的类型都统称资源,如 cc.Texture2D, cc.SpriteFrame, cc.AnimationClip, cc.Prefab 等。它们的加载是统一并且自动化的,相互依赖的资源能够被自动预加载。例如,当引擎在加载场景时,会先自动加载场景关联到的资源,这些资源如果再关联其它资源,其它也会被先被加载,等加载全部完成后,场景加载才会结束。

手动加载

定义资源属性后手动加载 texture: { default: null, type: cc.Texture2D,},

动态加载

动态加载资源:cc.resources.load 通常我们会把项目中需要动态加载的资源放在 resources 目录下,配合接口动态加载。你只要传入相对 resources 的路径即可,并且路径的结尾处 不能 包含文件扩展名。

cc.resources.load("test assets/prefab", function (err, prefab) {
    var newNode = cc.instantiate(prefab);
    cc.director.getScene().addChild(newNode);
});

所有需要通过脚本动态加载的资源,都必须放置在 resources 文件夹或它的子文件夹下。resources 文件夹需要在 assets 根目录 下手动创建。资源动态加载的时候都是 异步 的,需要在回调函数中获得载入的资源。这么做是因为 Creator 除了场景关联的资源,没有另外的资源预加载列表,动态加载的资源是真正的动态加载。
有些资源需要指定其类型,否则加载出来的默认类型有误(例如把spriteFrame加载为Texture2D)

// 加载 SpriteFrame
var self = this;
cc.resources.load("test assets/image", cc.SpriteFrame, function (err, spriteFrame) {
    self.node.getComponent(cc.Sprite).spriteFrame = spriteFrame;
});

资源释放 cc.resources.release("test assets/image", cc.SpriteFrame);cc.assetManager.releaseAsset(spriteFrame); 进行释放

资源预加载 cc.resources.preload(path, cctype); 预加载的加载参数与正常加载时一样,不过预加载只会去下载必要的资源,并不会进行资源的反序列化和初始化工作,所以性能消耗更小,适合游戏运行中使用。

cc.resources.preload('test assets/image', cc.SpriteFrame);

// wait for while
cc.resources.load('test assets/image', cc.SpriteFrame, function (err, spriteFrame) {
    self.node.getComponent(cc.Sprite).spriteFrame = spriteFrame;
});

加载远程资源和设备资源 cc.assetManager.loadRemote
这种方式有一定限制:1. 这种加载方式只支持图片、声音、文本等原生资源类型,不支持 SpriteFrame、SpriteAtlas、Tilemap 等资源的直接加载和解析。(如需远程加载所有资源,可使用 Asset Bundle) 2. Web 端的远程加载受到浏览器的 CORS 跨域策略限制,如果对方服务器禁止跨域访问,那么会加载失败,而且由于 WebGL 安全策略的限制,即便对方服务器允许 http 请求成功之后也无法渲染。

// 远程 url 带图片后缀名
var remoteUrl = "http://unknown.org/someres.png";
cc.assetManager.loadRemote(remoteUrl, function (err, texture) {
    // Use texture to create sprite frame
});

资源的依赖与释放
在加载完资源之后,所有的资源都会临时被缓存到 cc.assetManager
针对 JavaScript 中无法跟踪对象引用的问题,Asset Manager 提供了一套基于引用计数的资源释放机制,让开发者可以简单高效地释放资源,不用担心项目规模的急剧膨胀。每一个资源对象都提供了两个方法 addRefdecRef,你可以使用这两个接口来对动态资源的引用进行控制

Asset Bundle
从 v2.4 开始,Cocos Creator 推出了 Asset Bundle 功能,支持 代码、资源 和 场景 的分包加载。开发者可将项目中的部分场景、资源、代码等内容划分到不同的 Asset Bundle 中,这些 Asset Bundle 不会在游戏启动时加载,而是由开发者在游戏过程中手动调用 loadBundle 进行加载,从而有效降低游戏启动的时间,尽可能做到按需加载。关于 Asset Bundle 的更多介绍,请参考 Asset Bundle

加载asset bundle cc.assetManager.loadBundle 加载时需要传入 Asset Bundle 配置面板中的 Bundle 名称 或者 Asset Bundle 的 url。

cc.assetManager.loadBundle('01_graphics', (err, bundle) => {
    bundle.load('xxx');
});

从 v2.4.3 开始,cc.assetManager.loadBundle 还支持传入用户空间中的路径来加载用户空间中的 Asset Bundle。通过对应平台提供的下载接口将 Asset Bundle 提前下载到用户空间中,然后再使用 loadBundle 进行加载,开发者就可以完全自己管理 Asset Bundle 的下载与缓存过程,更加灵活。

// 提前下载某个 Asset Bundle 到用户空间 pathToBundle 目录下。
//需要保证用户空间下的 Asset Bundle 和对应原始 Asset Bundle 的结构和内容完全一样
// ...
// 通过 Asset Bundle 在用户空间中的路径进行加载
// 微信小游戏平台
cc.assetManager.loadBundle(wx.env.USER_DATA_PATH + '/pathToBundle/bundleName', (err, bundle) => {
    // ...
});

当 Asset Bundle 加载完成后,会触发回调并返回错误信息和 cc.AssetManager.Bundle 类的实例,这个实例就是 Asset Bundle API 的主要入口,开发者可以使用它去加载 Asset Bundle 中的各类资源。在 Asset Bundle 加载完成后,返回了一个 cc.AssetManager.Bundle 类的实例。

可以通过名称进行获取

let bundle = cc.assetManager.getBundle('01_graphics');

加载资源: bundle.load 方法来加载 Asset Bundle 中的资源,此方法的参数与 cc.resources.load 相同,

加载场景:Asset Bundle 提供了 loadScene 方法用于加载指定 bundle 中的场景,你只需要传入 场景名 即可。loadScenecc.director.loadScene 不同的地方在于 loadScene 只会加载指定 bundle 中的场景,而不会运行场景,你还需要使用 cc.director.runScene 来运行场景。

预加载:Asset Bundle 中提供了 preloadpreloadDir 接口用于预加载 Asset Bundle 中的资源。具体的使用方式和 cc.assetManager 一致

释放资源:常规的cc.assetManager.releaseAssetbundle.release('image', cc.SpriteFrame);bundle.releaseAll();

移除AssetBundle:cc.assetManager.removeBundle(bundle);

当手动移除了某个不需要的 bundle,那么此 bundle 的缓存也会被移除,如果需要再次使用,则必须再重新加载一次。在移除 Asset Bundle 时,并不会释放该 bundle 中被加载过的资源。如果需要释放,请先使用 Asset Bundle 的 release / releaseAll 方法:

监听与发射事件

事件处理是在节点(cc.Node)中完成的。对于组件,可以通过访问节点 this.node 来注册和监听事件。监听事件可以通过 this.node.on() 函数来注册,除了使用on 监听,我们还可以使用 once 方法。once 监听在监听函数响应后就会关闭监听事件。

监听事件
注册监听方法:this.node.on('mousedown', function ( event ) {console.log('Hello!');});
/ 例:点击事件的绑定 this.node.on(‘touchstart’,this.fire,this);
事件监听函数 on 可以传第三个参数 target,用于绑定响应函数的调用者。

// 使用函数绑定
this.node.on('mousedown', function ( event ) {this.enabled = false;}.bind(this));

// 使用第三个参数
this.node.on('mousedown', function (event) {this.enabled = false;}, this);

关闭监听:off方法,推荐和onEnable()onDisable() 配合案例

cc.Class({
  extends: cc.Component,

  _sayHello: function () {
    console.log('Hello World');
  },

  onEnable: function () {
    this.node.on('foobar', this._sayHello, this);
  },

  onDisable: function () {
    this.node.off('foobar', this._sayHello, this);
  },
});

发射事件
发射事件有两种方式:emitdispatchEvent。两者的区别在于,后者可以做事件传递。

在发射事件时,我们可以在 emit 函数的第二个参数开始传递我们的事件参数。同时,在 on 注册的回调里,可以获取到对应的事件参数。出于底层事件派发的性能考虑,这里最多只支持传递 5 个事件参数。

onLoad () { //事件注册
    this.node.on('foo', function (arg1, arg2, arg3) {
      console.log(arg1, arg2, arg3);  // print 1, 2, 3
    });
  },
  start () {
    // 事件发射
    let arg1 = 1, arg2 = 2, arg3 = 3;
    // At most 5 args could be emit.
    this.node.emit('foo', arg1, arg2, arg3);
  },

派送事件 (用于我不想触发全部,而是可以截获)

dispatchEvent 方法,通过该方法发射的事件,会进入事件派送阶段。在 Cocos Creator 的事件派送系统中,我们采用冒泡派送的方式。冒泡派送会将事件从事件发起节点,不断地向上传递给他的父级节点,直到到达根节点或者在某个节点的响应函数中做了中断处理 event.stopPropagation()
发送的节点c
this.node.dispatchEvent( new cc.Event.EventCustom('foobar', true) );
截获的节点b
this.node.on('foobar', function (event) {event.stopPropagation();});

事件对象
在事件监听回调中,开发者会接收到一个 cc.Event 类型的事件对象 eventstopPropagation 就是 cc.Event 的标准 API。
在发送用户自定义事件的时候,请不要直接创建 cc.Event 对象,因为它是一个抽象类,请创建 cc.Event.EventCustom 对象来进行派发。
其中重要的API包含:
API - 类型 - 意义
type -String 事件的类型(事件名)
target- cc.Node 接收到事件的原始对象
currentTarget - cc.Node 接收到事件的当前对象,事件在冒泡阶段当前对象可能与原始对象不同
getType -Function 获取事件的类型
stopPropagation-Function 停止冒泡阶段,事件将不会继续向父节点传递,当前节点的剩余监听器仍然会接收到事件
stopPropagationImmediate- Function 立即停止事件的传递,事件将不会传给父节点以及当前节点的剩余监听器
getCurrentTarget-Function 获取当前接收到事件的目标节点
detail-Function 自定义事件的信息(属于 cc.Event.EventCustom)
setUserData-Function 设置自定义事件的信息(属于 cc.Event.EventCustom)
getUserData-Function 获取自定义事件的信息(属于 cc.Event.EventCustom)

系统内置事件

Cocos Creator 支持的系统事件包含鼠标、触摸、键盘、重力传感四种,其中本章节重点介绍与节点树相关联的鼠标和触摸事件,这些事件是被直接触发在相关节点上的,所以被称为节点系统事件。与之对应的,键盘和重力传感事件被称为全局系统事件。
系统事件遵守通用的注册方式,开发者既可以使用枚举类型也可以直接使用事件名来注册事件的监听器,事件名的定义遵循 DOM 事件标准。

// 使用枚举类型来注册
node.on(cc.Node.EventType.MOUSE_DOWN, function (event) {
  console.log('Mouse down');
}, this);

// 使用事件名来注册
node.on('mousedown', function (event) {
  console.log('Mouse down');
}, this);

鼠标事件类型与事件对象
鼠标事件在桌面平台才会触发:
鼠标事件在桌面平台才会触发,系统提供的事件类型如下:

枚举对象定义- 对应的事件名- 事件触发的时机
cc.Node.EventType.MOUSE_DOWN- mousedown 当鼠标在目标节点区域按下时触发一次
cc.Node.EventType.MOUSE_ENTER- mouseenter 当鼠标移入目标节点区域时,不论是否按下
cc.Node.EventType.MOUSE_MOVE- mousemove 当鼠标在目标节点区域中移动时,不论是否按下
cc.Node.EventType.MOUSE_LEAVE- mouseleave 当鼠标移出目标节点区域时,不论是否按下
cc.Node.EventType.MOUSE_UP - mouseup 当鼠标从按下状态松开时触发一次
cc.Node.EventType.MOUSE_WHEEL- mousewheel 当鼠标滚轮滚动时

鼠标事件(cc.Event.EventMouse)的重要 API 如下(cc.Event 标准事件 API 除外):
函数名- 返回值类型 -意义
getScrollY Number 获取滚轮滚动的 Y 轴距离,只有滚动时才有效
getLocation Object 获取鼠标位置对象,对象包含 x 和 y 属性
getLocationX Number 获取鼠标的 X 轴位置
getLocationY Number 获取鼠标的 Y 轴位置
getPreviousLocation Object 获取鼠标事件上次触发时的位置对象,对象包含 x 和 y 属性
getDelta Object 获取鼠标距离上一次事件移动的距离对象,对象包含 x 和 y 属性
getButton Number 获取cc.Event.EventMouse.BUTTON_LEFTcc.Event.EventMouse.BUTTON_RIGHTcc.Event.EventMouse.BUTTON_MIDDLE

触摸事件类型和事件对象 网页
TOUCH_START还有TOUCH_MOVE TOUCH_END TOUCH_CANCEL 四种微妙差别
触摸事件API 部分可以获取 触点对象touch,getID,getLocation,获取上次触点getPreviousLocation,获取触点初始位置 getStartLocation , 获取移动的距离对象getDelta 需要注意的是,触摸事件支持多点触摸,每个触点都会发送一次事件给事件监听器。

触摸事件的传递问题,参考事件冒泡:如果c是b的子节点,b是a的子节点:会通过c - b - a 冒泡在触摸事件冒泡的过程中不会有触摸检测,这意味着即使触点不在 A B 节点区域内,A B 节点也会通过触摸事件冒泡的机制接收到这个事件。

cc.Node 的其它事件
position-changed 当位置属性修改
rotation-changed 当旋转属性修改时
scale-changed 当缩放属性修改时
size-changed 当宽高属性修改时
anchor-changed 当锚点属性修改时

屏蔽多点触摸系统
cc.macro.ENABLE_MULTI_TOUCH = false;

暂停和恢复节点事件系统
this.node.pauseSystemEvents();this.node.resumeSystemEvents();

全局系统事件

全局系统事件是指与节点树不相关的各种全局事件,由 cc.systemEvent 来统一派发

定义输入事件
键盘、设备重力传感器此类全局事件是通过函数 cc.systemEvent.on(type, callback, target)注册的。
可选的 type 类型有:
cc.SystemEvent.EventType.KEY_DOWN (键盘按下)
cc.SystemEvent.EventType.KEY_UP (键盘释放)
cc.SystemEvent.EventType.DEVICEMOTION (设备重力传感)

键盘事件

cc.Class({
    extends: cc.Component,
    onLoad: function () {
        // add key down and key up event
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    },

    onDestroy () {
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
    },

    onKeyDown: function (event) {
        switch(event.keyCode) {
            case cc.macro.KEY.a:
                console.log('Press a key');
                break;
        }
    },

    onKeyUp: function (event) {
        switch(event.keyCode) {
            case cc.macro.KEY.a:
                console.log('release a key');
                break;
        }
    }
});

重力传感器事件 cc.SystemEvent.EventType.DEVICEMOTION

上一篇下一篇

猜你喜欢

热点阅读