029 -- 自找麻烦之 cocos creator 第二篇 (结合微信小游戏与facebook小游戏展开)

1. 开启物理引擎debug模式的通用文件,绑定在canvas节点上窝:

// 这个文件用来开启物理引擎,应该是通用的吧,个人觉得
cc.Class({
    extends: cc.Component,

    properties: {
        is_debug: false, // 是否显示调试信息;   
    },

    onLoad () {
        // 游戏引擎的总控制
        // cc.Director, cc.director 区别呢?
        // 大写的cc.Director是一个类, 小写cc.direcotr全局的实例
        cc.director.getPhysicsManager().enabled = true; // 开启了物理引擎
        // 独立的形状,打开一个调试区域,游戏图像的,逻辑区域;
        // 开始调试模式:
        if (this.is_debug) { // 开启调试信息
            var Bits = cc.PhysicsManager.DrawBits; // 这个是我们要显示的类型
            cc.director.getPhysicsManager().debugDrawFlags = Bits.e_jointBit | Bits.e_shapeBit;
        }
        else { // 关闭调试信息
            cc.director.getPhysicsManager().debugDrawFlags = 0;
        }
    },

    start () {

    },

    // update (dt) {},
});

2. 碰撞刚体类型的不同会有不同的效果 (不是现实中的碰撞效果最好不要用这些刚体碰撞,自己手写检测) 

  • 和 Dynamtic 类型刚体绑定的物理组件会受重力影响,可以设置速度
  • 和 Static 类型刚体绑定的物理组件,不会受重力影响,不可以设置速度,可以通过设置位置让其移动
  • 和 Kinematic 类型刚体绑定的物理组件,不受重力影响,可以设置速度
  • 绑定了 Dynamic(运动)类型的物理组件不能穿透绑定了 Static(静态)类型的物理组件
  • 绑定了 Dynamic 类型的物理组件不能穿透绑定了Kinematic类型的物理组件
  • Static 和 Kinematic 不会触发碰撞事件,Static 和 Static,Kinematic 和 Kinematic 不会触发碰撞事件;

3. 为属性设置引用时,只有在属性声明时规定type为引用类型时(比如我们这里写的cc.Prefab类型),才能够将资源或节点拖拽到该属性上:

properties: {
        kuaiPrefab: {
            default: null,
            type: cc.Prefab
        },
        // 方块的等级
        grade: 0
    },

4. 摄像机的使用: 创建空节点--添加组件--添加其他组件--Camera--target改为1--把对准的目标节点拉过来(绘制以这个节点为中心点,屏幕窗口大小为区域的画面)(像 像素鸟这种游戏就可以使用camera,把鸟的坐标同步到camera上面,将camera节点的x坐标设为鸟的x坐标,要在同一坐标系中)

5. 把普通坐标转换为世界坐标

var w_pos = this.target.convertToWorldSpaceAR(cc.p(0,0));

6. 把世界坐标转成相对与某个节点中的坐标

var pos = this.node.parent.convertToNodeSpaceAR(w_pos);

7. 发布成微信竖屏游戏可以设置canvas大小为640*960,还有 fit height 打勾

8. JavaScript Array some() 方法

var ages = [3, 10, 18, 20];

function checkAdult(age) {
    return age >= 18;
}

function myFunction() {
    document.getElementById("demo").innerHTML = ages.some(checkAdult);
}

some() 方法用于检测数组中的元素是否满足指定条件(函数提供);

some() 方法会依次执行数组的每个元素;

function(currentValue, index,arr) ----  currentValue(当前元素的值)是必须的,其他两个可选

9. 触摸事件: 先注册监听对应的触摸事件

  •  cc.Node.EventType.TOUCH_START:  触摸开始;
  • cc.Node.EventType.TOUCH_MOVE: 触摸移动;
  • cc.Node.EventType.TOUCH_END: 触摸结束, (物体内部结束)

  • cc.Node.EventType.TOUCH_CANCEL: 触摸结束, (物体外部结束)

  • 回掉函数的格式: cc.Touch对象触摸事件对象 {触摸信息,事件信息}

 this.node.on(cc.Node.EventType.TOUCH_START, function(t) {
      console.log("cc.Node.EventType.TOUCH_START called");
      // this 函数里面的this,
      // 停止事件传递
      t.stopPropagationImmediate(); 
}, this);

关闭监听用off

        // 移除
        // this.node.off(cc.Node.EventType.TOUCH_MOVE, this.on_touch_move, this);
        // 移除target上所有的注册事件(注意这里参数是this而不是this.node)
        // this.node.targetOff(this);

触摸回调函数里面的参数t

t: --> cc.Touch
    触摸的位置: 屏幕坐标,左小角(0, 0); getLocation(); 
     getLocation()执行结果是点对象,有x和y
// 距离上一次触摸变化了多少;
        var delta = t.getDelta(); // x, y各变化了多少cc.Vec2(x, y)

        this.node.x += delta.x;
        this.node.y += delta.y;

10. 开发要做的两件事情: 学习系统组件,自己开发组件

11. 获取节点上的其他组件:getComponent (例如label组件)

var vip = this.getComponent(cc.Label);

12. 构建发布微信小游戏的话,竖屏选择 Portrait,横屏选择 landspace,然后选择构建

13. 包体裁剪(减少打包后cocos-2d的文件代码大小),选择 项目--项目设置--模块设置--把没有用的东西取消掉--再构建发布一次

14. 资源远程部署: 微信小游戏现在不允许代码太大,目前是4M,微信小游戏是支持把资源部署到第三方的;

五行代码搭建服务器(npm i express),新建文件 webserver.js

var express = require("express");
var app = express();
app.listen(80);
var path = require("path");

app.use("/",express.static(path.join(process.cwd(),"www_root")));  //www_root 是与当前文件同级的文件夹名,这个文件夹存放index.html等文件

在www_root 新建远程资源文件夹remote ,把微信小游戏源码中的 res 文件夹资源放到我们 remote 文件夹下,打开微信小游戏源码中的 libs/xmldom/wx-downloader,

...

var WXDownloader = window.WXDownloader = function() {

    ...
    this.REMOTE_SERVER_ROOT = '';   // 大概40行的地方,在src/main.js文件中配置这个参数
}

在 src/main.js 这样配置就行(改好后点击微信开发者工具上面的 详情 -- 不校验合法域名打勾)

...
 if(true){

    require(window._CCSetting.debug ? 'cocos2d-js.js':'cocos2d-js-min.js');
    var prevPipe = cc.loader.md5Pipe || cc.loader.assetLoader;
    wxDownloader.REMOTE_SERVER_ROOT = "http:127.0.0.1/remote/";   //大概204行的地方,在这里配置第三方服务器的地址
}

15. 名言:没有什么错误是 console.log 调试不出来的,如果有,那就多 console.log 几次;

16. Button组件使用:属性检查器--transition可以选择过渡的效果,按钮点击事件想传参数的话 Button组件--CustomEventData 里面填写(参数都是一个字符串对象)在关卡功能中会用到这种传参数的点击事件

...

    on_button_click: function(e,level){  //第二个参数才是编辑器上面填写的,是个字符串类型
        level = parseInt(level);
        console.log(level);
    }

代码中使用button组件

//属性中声明,然后直接在编辑器里面拉取绑定
    button: {
        default: null,
        type: cc.Button
    }

获取节点中的button组件与添加button组件

onload: function () {
    this.start_button = this.node.getChildByName("ks_up").getComponent(cc.Button); //获得名为xx的子节点上面的button组件
    this.red_button = this.node.getChildByName("red_btn").addComponent(cc.Button); //为名为xx的子节点上添加一个button组件
}

为button节点添加一个响应函数(适用于动态添加按钮之后的点击事件)

onload:function(){
    var click_event = new cc.Component.EventHandler();
    click_event.target = this.node;
    click_event.component = "game_scene";
    click_event.handler = "on_click";
    click_event.customEventData = "red_btn";

    this.red_btn.clickEvents = [clcik_event];  //这个数组添加多个就是多个点击事件
}

on_click: function(e,custom){
    console.log(custom);
}

代码触发按钮的响应事件,而不用自己去触摸

onload: function(){
    this.scheduleOnce(function(){
        var click_event = this.red_btn.clickEvents;
        for(var i = 0 ; i < click_events.length; i++){
            var comp_env_handle = click_events[i];
            // 在代码里面触发按钮的响应函数
            comp_env_handle.emit(["","on_click"]);
        }
    
    }.bind(this),3)

}
on_click: function(e,custom){
    console.log(custom);
}

17. 横屏游戏类似捕鱼达人这种可以把canvas设置为1334*750

18. 例如给鱼添加游动轨迹,点击节点--添加组件--添加其他组件--Animation--点击动画编辑器--新建--点击左上角的编辑按钮--在里面选择鱼的节点添加位置position-- 点击+号 -- 拉动动画编辑器中的帧 -- 再调整节点的位置 -- 点击虚线 --调整

19. 获取其他脚本组件中的函数

var gen_map_path = require("gen_map_path");   //这里引入其他文件名
// 组件类,
cc.Class({
    extends: cc.Component,

    properties: {
        map: {     // 这里需要声明一下(然后去编辑器里面拖动所对应的节点到map里面)
            type: gen_map_path,
            default: null,
        },

        speed: 100,
    },

    // start函数 组件开始运行之前,调用, 初始入口的好地方;
    start () {
        this.run_road();
    },

    run_road() {
        var road_set = this.map.get_road_set();
        var index = Math.random() * road_set.length;
        index = Math.floor(index);
        this.road_data = road_set[index]; // 假设从第0条;

        if (this.road_data.length < 2) {
            return;
        }
        this.is_walking = false;
        this.node.setPosition(this.road_data[0]);
        this.next_step = 1; // 下一个要走的路径点;
        this.walk_to_next();
    }, 

    walk_to_next() {
        if (this.next_step >= this.road_data.length) {
            this.is_walking = false;
            this.run_road();
            return;
        }

        this.is_walking = true;
        var src = this.node.getPosition();
        var dst = this.road_data[this.next_step];
        var dir = cc.pSub(dst, src);  //返回两个向量的差(2.0就没有这个方法了)
        var len = cc.pLength(dir);   //返回指定向量的长度(2.0就没有这个方法了)

        this.total_time = len / this.speed;
        this.now_time = 0;
        this.vx = this.speed * dir.x / len;
        this.vy = this.speed * dir.y / len;

        // 旋转鱼头
        var r = Math.atan2(dir.y, dir.x); // 弧度
        var degree = r * 180 / Math.PI;
        degree = 360 - degree + 90; // 逆时针--> 顺时针
        // this.node.rotation = degree;
        this.node.runAction(cc.rotateTo(0.5, degree));
        // end
    },

    // update 组件再游戏画面每次刷新的时候调用, update
    // dt: 是距离上一次过去刷新的时间;
    update (dt) {
        if(this.is_walking === false) {
            return;
        }

        this.now_time += dt;
        if (this.now_time > this.total_time) {
            dt -= (this.now_time - this.total_time);
        }

        var sx = this.vx * dt;
        var sy = this.vy * dt;

        this.node.x += sx;
        this.node.y += sy;

        if (this.now_time >= this.total_time) {
            this.next_step ++;
            this.walk_to_next(); // 继续走下一个点;
        }
    },
});

20. 播放帧动画的脚本组件,感觉是可以通用的,来自捕鱼达人的鱼的帧动画组件(引擎自带的帧动画不用有自己的道理)

cc.Class({
    extends: cc.Component,

    properties: {
        sprite_frames : {
            default: [],
            type: cc.SpriteFrame,
        },
        
        duration: 0.1, // 帧的时间间隔
        loop: false, // 是否循环播放
        play_onload: false, // 是否在组件加载的时候播放;
    },

    onLoad: function () {
        // 判断一下在组件所挂在的节点上面有没有cc.Sprite组件;
        var s_com = this.node.getComponent(cc.Sprite);
        if (!s_com) { // 没有cc.Sprite组件,要显示图片一定要有cc.Sprite组件,所以我们添加一个cc.Sprite组件;
            s_com = this.node.addComponent(cc.Sprite);
        }
        this.sprite = s_com; // 精灵组件
        // end 
        this.is_playing = false; // 是否正在播放;
        this.play_time = 0;
        this.is_loop = false;
        this.end_func = null;
        
        // 显示第0个frame;
        if (this.sprite_frames.length > 0) {
            this.sprite.spriteFrame = this.sprite_frames[0];    
        }
        
        if (this.play_onload) {
            if (!this.loop) {
                this.play_once(null);    
            }
            else {
                this.play_loop();
            }
        }
    },
    
    // 实现播放一次,
    play_once: function(end_func) {
        this.play_time = 0;
        this.is_playing = true;
        this.is_loop = false;
        this.end_func = end_func;
    }, 
    // end 
    
    // 实现循环播放
    play_loop: function() {
        this.play_time = 0;
        this.is_playing = true;
        this.is_loop = true;
    },
    // end 
    
    stop_anim: function() {
        this.play_time = 0;
        this.is_playing = false;
        this.is_loop = false;
    }, 
    
    start: function() {
        
    },
    
    // called every frame, uncomment this function to activate update callback
    // 每一次刷新的时候需要调用的函数,dt距离上一次刷新过去的时间;
    update: function (dt) {
        if (this.is_playing === false) { // 没有启动播放,不做处理
            return;
        }
        
        
        
        this.play_time += dt; // 累积我们播放的时间;
        
       // 计算时间,应当播放第几帧,而不是随便的下一帧,
       // 否则的话,同样的动画1, 60帧,你在30FPS的机器上你会播放2秒,
       // 你在60FPS的机器上你会播放1秒,动画就不同步;
       
        var index = Math.floor(this.play_time / this.duration); // 向下取整数
        // index
        if (this.is_loop === false) { // 播放一次
            if (index >= this.sprite_frames.length) { // 非循环播放结束
                // 精灵显示的是最后一帧;
                this.sprite.spriteFrame = this.sprite_frames[this.sprite_frames.length - 1];
                // end 
                this.is_playing = false;
                this.play_time = 0;
                if (this.end_func) { // 调用回掉函数
                    this.end_func();
                }
                return;
            }
            else {
                this.sprite.spriteFrame = this.sprite_frames[index];
            }
        }
        else { // 循环播放;
            
            while (index >= this.sprite_frames.length) {
                index -= this.sprite_frames.length;
                this.play_time -= (this.duration * this.sprite_frames.length);
            }
            
            //  在合法的范围之内
            this.sprite.spriteFrame = this.sprite_frames[index];
            // end 
        }
    },
});

21. 这里面发现一个js 居然不支持这种写法

142 < pos_x < (142+71)

而只能用这种(我到今天才发现的感觉)

pos_x > 142 && pos_x < (142+71)

22. 以后做移动端游戏统一使用touch事件最好,又没有兼容问题(最好不要和点击按钮的事件混着用)

23. 客户端发起http请求: 在需要发请求的脚本文件里面先引

var http = require("http");
var http = {
    // calback(err, data)
    get: function(url, path, params, callback) {
        var xhr = cc.loader.getXMLHttpRequest();
        xhr.timeout = 5000;
        var requestURL = url + path;
        if (params) {
            requestURL = requestURL + "?" + params;
        }
         
        xhr.open("GET",requestURL, true);
        if (cc.sys.isNative){
            xhr.setRequestHeader("Accept-Encoding","gzip,deflate","text/html;charset=UTF-8");
        }

        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
                console.log("http res("+ xhr.responseText.length + "):" + xhr.responseText);
                try {
                    var ret = xhr.responseText;
                    if(callback !== null){
                        callback(null, ret);
                    }
                    return;
                } catch (e) {
                    callback(e, null);
                }
            }
            else {
                callback(xhr.readyState + ":" + xhr.status, null);
            }
        };
        
        xhr.send();
        return xhr;
    },

    post: function(url, path, params, body, callback) {
        var xhr = cc.loader.getXMLHttpRequest();
        xhr.timeout = 5000;
        var requestURL = url + path;
        if (params) {
            requestURL = requestURL + "?" + params;
        }
        xhr.open("POST",requestURL, true);
        if (cc.sys.isNative){
            xhr.setRequestHeader("Accept-Encoding","gzip,deflate","text/html;charset=UTF-8");
        }

        if (body) {
            xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            xhr.setRequestHeader("Content-Length", body.length);
        }
        

        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
                try {
                    var ret = xhr.responseText;
                    if(callback !== null){
                        callback(null, ret);
                    }
                    return;
                } catch (e) {
                    callback(e, null);
                }
            }
            else {
                callback(xhr.readyState + ":" + xhr.status, null);
            }
        };
        if (body) {
            xhr.send(body);
        }
        return xhr;
    }, 

    download: function(url, path, params, callback) {
        var xhr = cc.loader.getXMLHttpRequest();
        xhr.timeout = 5000;
        var requestURL = url + path;
        if (params) {
            requestURL = requestURL + "?" + params;
        }

        xhr.responseType = "arraybuffer";  
        xhr.open("GET",requestURL, true);
        if (cc.sys.isNative){
            xhr.setRequestHeader("Accept-Encoding","gzip,deflate","text/html;charset=UTF-8");
        }

        xhr.onreadystatechange = function() {
            if(xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 300)){
                var buffer = xhr.response;
                var dataview = new DataView(buffer);
                var ints = new Uint8Array(buffer.byteLength);
                for (var i = 0; i < ints.length; i++) {
                    ints[i] = dataview.getUint8(i);
                }
                callback(null, ints);
            }
            else {
                callback(xhr.readyState + ":" + xhr.status, null);
            }
        };
        xhr.send();
        return xhr;
    },

};

module.exports = http;


发请求这样写

http.get("http:127.0.0.1:80","/lucky","name=black&uphone=12312",function(err,ret){
    if(err){
        return;
    }
    console.log(ret);
});

24. 使用定时器等函数要注意 this的指向问题,不然哪里错了都不知道,注意,注意,注意

25. 顺序执行两个动作

var m1 = cc.moveTo(0.5,cc.v2(0,56));
var m2 = cc.moveTo(0.5,cc.v2(0,-580));

var end_func = cc.callFunc(function(){
    console.log("dd")
}.bind(this));
// 这是定义一个容器来放动作
var seq = cc.sequence([m1,m2,end_func]);

this.rope.runAction(seq);
var m1 = cc.moveTo(0.5,cc.v2(0,56));

var mid_func = cc.callFunc(function(){
    console.log("中间");
    var cow = this.hit_test(); 
    cow.removeFromParent();  // 把从父节点中删除该节点
}.bind(this));

var m2 = cc.moveTo(0.5,cc.v2(0,-580));

var end_func = cc.callFunc(function(){
    console.log("dd")
}.bind(this));
// 这是定义一个容器来放动作
var seq = cc.sequence([m1,mid_func,m2,end_func]);  //原来可以在第一个动作执行完就回调
 
this.rope.runAction(seq);

26. 复制预制体(需要先声明),设置位置,定时器

properties: {
    cow_prefab: {
        type: cc.Prefab,
        default: null
    },
    cow_root: {
        type: cc.Node,
        default: null
    }
},
gen_one:{
    var cow = cc.instantiate(this.cow_prefab);
    this.cow_root.addChild(cow);
    cow.setPosition(cc.v2(520,-70)); // 设置位置

    var time = 3 + Math.random() * 2;  // 3到5秒
    this.scheduleOnce(this.gen_one.bind(this),time);  // 每隔三到五秒钟调一次函数
}

27. 写代码要先写总体逻辑,然后再逐个实现整个逻辑中需要的函数(很重要,提高代码可读性)

28. 声明图片数组集合

rope_imgs: {
    type: cc.SpriteFrame,
    default: []
}

29.修改精灵节点上的图片

this.rope_sprite.spriteFrame = this.rope_imgs[cow_type];  // spriteFrame 这个属性就是指图片

30. 接入微信小游戏,排行榜功能要用 wx.getFriendCloudStorage() 和 wx.getGroupCloudStorage() 两个 API,这两个 API 的返回结果都是一个对象数组,数组的每一个元素都是一个表示用户数据的对象

31. 开发者需要创建两个项目(子域必须使用全屏窗口,与主域保持一样的设计分辨率和适配模式。)

  • 主域项目工程(正常的游戏项目)
  • 开放数据域项目工程(通过微信 API 获取用户数据来做排行榜等功能的项目)

32. Mask组件:就是一个视口(想像一个窗口去看外面的世界,只能看到这个窗口大小的视区),所以mask组件的type类型有椭圆,矩形,图片类型;mask有nverted(反向遮罩) 这个属性,mask的子节点大小超过mask的就看不到;椭圆ellipse的时候segements等于64的时候就是相当于一个圆。

33. Layout组件:对子元素进行垂直或者水平布局,或者先水平后垂直布局(type:GRID);面板属性--ResizeMode:node不会对子节点和容器进行大小缩放,child对子节点的大小进行缩放,container对容器的大小进行缩放(注意这个最常用);

34. scrollView滚动视图组件:

  • 主要结构: root->view(Mask裁剪超出范围的内容) ---> content(Layout)负责内容排版;
  • 滚动列表的每个选项:root(w, h,制定大小,好给Layout用)
  • 代码里面使用cc.ScrollView:将选项做成预制体,在代码里面new 出预制体,加入到content节点下;

35. 代码演示scrollView的使用

cc.Class({
    extends: cc.Component,

    properties: {
        // foo: {
        //    default: null,      // The default value will be used only when the component attaching
        //                           to a node for the first time
        //    url: cc.Texture2D,  // optional, default is typeof default
        //    serializable: true, // optional, default is true
        //    visible: true,      // optional, default is true
        //    displayName: 'Foo', // optional
        //    readonly: false,    // optional, default is false
        // },
        // ...
        item_prefab: {
            type: cc.Prefab,
            default: null,
        },

        opt_item_prefab: {
            type: cc.Prefab,
            default: null,
        },

        scrollview: {
            type: cc.ScrollView,
            default: null,
        },
    },

    // use this for initialization
    onLoad: function () {
        var item = cc.instantiate(this.item_prefab);
        this.node.addChild(item);


        for(var i = 0; i < 10; i ++) {
            var opt_item = cc.instantiate(this.opt_item_prefab);
            this.scrollview.content.addChild(opt_item);  //scrollview节点的content属性默认绑定了content节点(也就是视图内容)
        }
    },

    // called every frame, uncomment this function to activate update callback
    // update: function (dt) {

    // },
});

36. 生命周期:onLoad只会调用一次,官方说法是“onLoad 回调会在组件首次激活时触发”。onEnable则会在节点每次被设置为激活时触发。(例如设置游戏结束显示界面 this.endUI.active = true 之类可以用这个生命周期来播放背景音乐)

37. action动画

// (1)缩放
var delay1 = cc.delayTime(0.5); //延迟0.5秒
var toBigAction1 = cc.scaleTo(0.3, 3); //0.3秒变成3倍大小(默认是线性的放大,即匀速放大)
var action1 = cc.sequence(delay1, toBigAction1); //按顺序执行,先延迟1秒,后缩放
this.birdNode1.runAction(action1); //this.birdNode1执行以上动作
// 注意:这里缩放没有使用缓动动作,默认按线性。
// (2)移动
var delay_startBtn = cc.delayTime(0.2); //延迟0.2秒
//0.75秒内x移动0,y移动-1200,移动曲线按cc.easeCubicActionIn()
var startBtnAction = cc.moveBy(0.75, cc.p(0, -1200)).easing(cc.easeCubicActionIn()); 
this.startBtn.runAction(cc.sequence(delay_startBtn, startBtnAction)); //this.startBtn执行以上动作
// 注意:这里移动使用了缓动动作,通常也就设计到运动学的情况会用到缓动动作,比如抛物线运动、弹簧。
// (3)透明度
var delay2 = cc.delayTime(0.3); //延迟0.3秒
var fadeAction2 = cc.fadeTo(0.25, 0); //0.25秒透明度从255降到0
var action2 = cc.sequence(delay2, fadeAction2);
this.heartNode1.runAction(action2);
this.heartNode2.runAction(action2.clone()); //这里不能直接用action2,必须action2.clone()
// 注意:action不能同名,同名的话只会执行最后一个。需要重复使用时,可用上面的clone()。
// (4)回调函数
onLoad: function(){
    var delay3 = cc.delayTime(0.3);
    var fadeAction3 = cc.fadeTo(0.25, 255);
    var callback1 = cc.callFunc(this.ladderAnimation, this); //回调函数
    var action3 = cc.sequence(delay3, fadeAction3, callback1);
    this.mileageNode.runAction(action3);
},
ladderAnimation: function(){
....
},
// 注意:回调函数是一个很有用的设定,比如你可以在点击按钮后,先将按钮飞出屏幕,然后执行跳转场景的函数。


// (5)震屏
var quakeAction = cc.repeat(
cc.sequence(cc.moveBy(0.05,cc.p(2,2)), 
cc.moveBy(0.1,cc.p(-4,4)), 
cc.moveBy(0.05,cc.p(2,2)), 
cc.moveBy(0.1,cc.p(0,-6))),
2);
this.bgNode.runAction(quakeAction);
// 注意:这里用了cc.repeat,其执行了2次。

38. 判断一个节点是否处于Action动画中

// (1)给每个action设置tag,保存当前播放的action tag,通过tag获得当前action,执行以下 
// action->isDone() 返回true则action执行完毕。
var action = cc.moveTo(0.1, cc.p(100, 1));
action.setTag(1);
this.action2 = action.clone();
this.node.runAction(action);
var action1 = this.node.getActionByTag(1);
if(action1.isDone()){
cc.log("执行完毕");
}
if(this.action2.getTarget() != null){
cc.log("Action有目标");
}
//通过节点的事件来判断	
this.node.runAction(cc.moveBy(2, cc.p(100,100)).setTag(123)); 
this.node.on("position-changed", function(event){
cc.log('移动了哦');
var action3 = event.currentTarget.getActionByTag(123);
if(action3.isDone()){
cc.log("执行完毕");
}
});

39. action的执行时间包含了回调函数的执行时间。即action的isDone会在回调函数执行完,值才为true。

40. 在for循环中执行Action,Action的执行会在for循环外面。for循环只是启动所有Action,就立刻退出了循环。

41. 存储数据:

// (1)单个数据的存储
cc.sys.localStorage.setItem(key, value)
cc.sys.localStorage.getItem(key)
//存储
cc.sys.localStorage.setItem('gold', 100);
//读取
var g = cc.sys.localStorage.getItem('gold');


// (2)将对象序列化为 JSON 后保存
userData = {
    name: 'Tracer',
    level: 1,
    gold: 100
};
//存储
cc.sys.localStorage.setItem('userData', JSON.stringify(userData));
//读取
var userData = JSON.parse(cc.sys.localStorage.getItem('userData'));

42. 前后台切换

// 1.cocos creator前后台切换
// 当玩家在玩游戏时,突然接了一个电话,此时游戏会被切到后台待机,所有的声音
// 播放都会停止,等打完电话,回到游戏,游戏又会被切回前台来,需要手动播放
// 声音。可使用如下代码
onLoad: function () {
    cc.game.on(cc.game.EVENT_HIDE, function(){
        console.log("游戏进入后台");
        this.doSomeThing();
    },this);
    cc.game.on(cc.game.EVENT_SHOW, function(){
        console.log("重新返回游戏");
        this.doSomeThing();
    },this);
},

43. 微信开发者工具报错 showShareMenu:fail no permission 确认申请的是一个游戏类目的小程序就行了

====================================================================================1. 动画编辑器里面属性列表的 sample 表示一秒钟有多少帧,speed 表示播放速度,大于1表示加快,小于1表示变慢,wrapmode 表示动画的播放模式
2. 代码中使用animation组件:
   

anim: {  //声明,然后编辑器里面拉取对应带有animation组件的节点(第一种方式)
        type: cc.Animation,
        default: null
    }

    this.anim_com = this.node.getChildByName("anim").getComponent(cc.Animation); //获得节点上的Animation组件(第二种方式)

3. Animation组件主要的方法:
    play([name], [start_time]), 播放指定的动画,如果没有制定就播放默认的动画;
    playAdditive: 与play一样,但是不会停止当前播放的动画;(用的不多)
    stop([name]): 停止指定的动画,如果没有指定名字就停止当前播放的动画;
    pause/resume: 暂停唤醒动画;
    getClips: 返回组件里面带的AnimationClip数组
4. Animation播放事件:  动画组件对象来监听on,不是节点
    play : 开始播放时  stop : 停止播放时 pause : 暂停播放时 resume : 恢复播放时
    lastframe : 假如动画循环次数大于 1,当动画播放到最后一帧时 finished : 动画播放完成时
5. 动画里面调用代码函数:
    1: 插入一个时间到动画里面;
    2: 编辑这个时间触发的函数: 名字 + 参数
    3: 遍历当前动画组件所挂节点上面所有的脚本或组件,根据这个名字来触发函数;
    4: 要慎用,代码和动画之间不易太多的调用;
6. cc.loader
    1:有三个默认的Pipeline:
     (1) assetLoader: 主要用于加载资源, 加载asset类型资源,和释放这些资源;
     (2) downloader: 主要用于下载文件, 文本,图像,脚本,声音,字体, 自定义的download;
     (3) loader:  第三个默认的Pipeline,可以加载json, image, plist, fnt, uuid;
    2: 资源分为本地(assets目录下)与远程资源;
    3:  加载异步的;
7. 本地资源加载:
    代码里面加载资源必须要求资源在assets/resources/文件夹下
        根据场景的依赖关系来打包我们的资源;  去掉不用的资源
        无法判断在代码里面加载的资源,是哪些?-->所有的resources目录下的资源,都会被打包进去,你在代码里面就能加载到它了
        如果资源不在代码里面加载,一般不要放到resources目录下 ,如果放到了,这个资源不关你有没有用,都会被打包进去;
    资源的url不需要加assets/resources这个部分,路劲不需要加这个前缀;
   

cc.loader.loadRes(url, onComplete回掉函数);
    cc.loader.getRes(url, [type]); 获取资源id;
    cc.loader.loadResArray([], type类型, progressCallback, completeCallback);
    cc.loader.loadResDir (url [type ] [progressCallback ] [completeCallback ]) 加载一个路径下的资源;
    代码演示:
    local_load: function() {
        // 本地加载声音
        // 注意:这里不需要后缀名, assets/resources/这个也不需要
        cc.loader.loadRes("bg", function(err, ret){
            if(err) {
                console.log(err);
                return;
            }
            console.log(ret); // audio clip
            this.audio.clip = ret;
            this.audio.play();
        }.bind(this));
        // end 

        // 本地加载图片
        cc.loader.loadRes("img/disk", cc.SpriteFrame, function(err, ret) {
            if (err) {
                console.log(err);
                return;
            }

            // spriteFrame对象
            // 例如我们的游戏,在进入下一个场景之前,有一个资源加载场景,那么到了新的场景后,我们就能够找到这个加载好的资源
            // cc.loader.getRes();
            this.sprite.spriteFrame = cc.loader.getRes("img/disk", cc.SpriteFrame);
            // end 
        }.bind(this));
        // end 
    },


8. 远程资源加载:
   

 // 加载远程的图片
    cc.loader.load("http://127.0.0.1:6080/splash.png", function(err, ret) {
        if(err) {
            console.log(err);
            return;
        }

        // ret is cc.Texture2D这样对象
        this.sprite.spriteFrame.setTexture(ret);  //这样就显示出来了
        this.sprite.node.setContentSize(ret.getContentSize()); // 使用这个图片的原始大小
        // end 
    }.bind(this));

    // 从服务器加载mp3来进行播放, type,就是url不带类型,我们就使用url + type的模式来制定类型
    cc.loader.load({url: "http://127.0.0.1:6080/bg.mp3", type: "mp3"}, function(err, ret) {
        if (err) {
            console.log(err);
            return;
        }
        this.audio.clip = ret;
        this.audio.play();
    }.bind(this));
    // end 

    // 从服务器加载json文件
    cc.loader.load({url: "http://127.0.0.1:6080/project.json", type: "json"}, function(err, ret) {
        if (err) {
            console.log(err);
            return;
        }
        
        console.log(ret);
    }.bind(this));
    // end 

    // 
    cc.loader.load({url: "http://127.0.0.1:6080/test.mydata", type: "mydata"}, function(err, ret) {
        if (err) {
            console.log(err);
            return;
        }
        
        console.log(ret);
    }.bind(this));

9. 每个场景有个自动释放资源,勾选上这个场景的资源会自动释放,不勾选上这个场景的资源不释放
10. 代码加载的资源,默认是不会受这个选项的影响的,除非设置 cc.loader.setAutoRelease(url, brealse)
11. 手动释放资源: loadRes/ releaseRes     load / release   releaseAsset (资源对象的object);

12. 字体文件直接拖到res文件夹后,再直接拖到层级管理器中的节点就好了

13. 界面适配:

  • 背景图做到能适配任何主流的手机分辨率;
  •  将界面布局分为9大停靠点

14. 按钮按下时状态变化(Transition)

  • NONE
  • COLOR   纯色切换
  • SPRITE  图片切换
  • SCALE   按钮缩放

15. 在脚本中动态添加按钮

// 以下是关卡界面的脚本片段
var btnNode = cc.instantiate(this.levelBtnPrefab); //按钮的预制(预制中无法保存按钮事件)
this.scrollViewContentNode.addChild(btnNode);
btnNode.setPosition(pos[i % 12][0] + 750 * Math.floor(i / 12), pos[i % 12][1]);
//绑定事件
var clickEventHandler = new cc.Component.EventHandler();
clickEventHandler.target = this.node;
clickEventHandler.component = "Level"; //脚本名字
clickEventHandler.handler = "onLevelBtn"; //点击的回调函数
clickEventHandler.customEventData = (i + 1).toString(); //参数
var btn = btnNode.getComponent(cc.Button);
btn.clickEvents.push(clickEventHandler);

16.

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值