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);  // 每隔三到五秒钟调一次函数
}

猜你喜欢

转载自blog.csdn.net/m0_37291785/article/details/81611411