1. 程式人生 > >cocos creator 檯球小遊戲

cocos creator 檯球小遊戲

所用平臺:cocos creator 所用語言:js

遊戲的實現點: 1.可碰撞物體:以白球、其他球、球袋、球杆、球桌分五類,使用creator內建的操作設定可產生碰撞的節點;新增剛體,以節點形狀選擇剛體形狀。以節點屬性選擇剛體型別是靜態還是動態,其中球袋要多設定一項:sensor,即不產生碰撞效果,只產生碰撞監測。 2.球杆的移動、拉伸:球杆要隨著白球為中心移動,為不接觸白球,要設定最小距離,達到此距離則隱藏。以點選點與白球中心得到一個向量,用得到的向量長度拉伸球杆並改變球杆衝量;向量和水平軸的夾角得到球杆旋轉度數。 3.白球進洞操作區別其他球:白球縮小尺寸,其他球則在完全隱藏,這樣可以繼續對白球的操作,同時,對其他球可以通過每幀執行一個函式:檢查球桌上是否還有其他球(除白球)來判斷遊戲勝利。

程式碼

  • 掛在白球節點上
cc.Class({
    extends: cc.Component,

    properties: {
        cue: {
            type: cc.Node,
            default: null,
        },
        max_dis: 100,
        min_dis: 5, // 如果拖動的距離到白球的中心 < 這個距離,那麼我們就隱藏球杆,否者的話,顯示球杆;
    },

    start () {
        this.body = this.getComponent(cc.RigidBody);
        this
.cue_inst = this.cue.getComponent("cue"); this.start_x = this.node.x; this.start_y = this.node.y; this.node.on(cc.Node.EventType.TOUCH_START, function(e) { }.bind(this), this); this.node.on(cc.Node.EventType.TOUCH_MOVE, function(e) { var w_pos = e.getLocation(); var
dst = this.node.parent.convertToNodeSpaceAR(w_pos); //相對於this.node.parent(canvas)這個為參照物,AR為原點的座標,(假設)白球移動到移動到世界座標為 w_pos //就是去獲得點選點的二維向量 var src = this.node.getPosition();//白球二維向量 var dir = cc.pSub(dst, src);//向量相減得到的一個方向向量 var len = cc.pLength(dir); if (len < this.min_dis) { this.cue.active = false; // 設定球杆為隱藏; return; } if (len > this.max_dis) { this.cue.active = false; // 設定球杆為隱藏; return; } this.cue.active = true; var r = Math.atan2(dir.y, dir.x);//得到弧度 var degree = r * 180 / Math.PI; degree = 360 - degree; this.cue.rotation = degree + 90; //旋轉球杆 var cue_pos = dst; var cue_len_half = this.cue.width * 0.1;//本來cue的錨點在中心的,應該是* 0.5的 cue_pos.x += (cue_len_half * dir.x / len); cue_pos.y += (cue_len_half * dir.y / len);//使得球杆好像在隨著點選點的後移向後拉 this.cue.setPosition(cue_pos); }.bind(this), this); this.node.on(cc.Node.EventType.TOUCH_END, function(e) { if(this.cue.active === false) { return; } this.cue_inst.shoot_at(this.node.getPosition());//朝白球方向射擊 }.bind(this), this); this.node.on(cc.Node.EventType.TOUCH_CANCEL, function(e) { if(this.cue.active === false) { return; } this.cue_inst.shoot_at(this.node.getPosition()); }.bind(this), this); }, reset: function() { this.node.scale = 0.35;//當時加入的時候就是0.35 this.node.x = this.start_x; this.node.y = this.start_y; this.body.linearVelocity = cc.p(0, 0);//線性轉速 this.body.angularVelocity = 0;//角轉速 }, onBeginContact: function(contact, selfCollider, otherCollider) { // 白球有可能,碰球杆,碰球,碰邊,球袋 if(otherCollider.node.groupIndex == 2) { // 隔1秒一種,要把白球放回原處; this.node.scale = 0;//消失 this.scheduleOnce(this.reset.bind(this), 1);//1秒後白球重置 // end return; } }, // update (dt) {}, });
  • 掛在其他球節點上

cc.Class({
    extends: cc.Component,
    // 屬性列表,它將會作為元件例項的資料成員,到元件裡面,繫結到我們的編輯器上;
    properties: {

        value: 1,
    },

    onLoad () {//每幀比update先
        // this,指的就是當前的元件例項
    },

    start () {//初始化時
        // this,指的就是當前的元件例項
        this.body = this.getComponent(cc.RigidBody);//同一節點的其他元件
        this.start_x = this.node.x;
        this.start_y = this.node.y;
    },

    // dt: 距離上一次重新整理的時間;
    update (dt) {//每幀
        // this,指的就是當前的元件例項
    },

    reset: function() {
        this.node.active = true;
        this.node.x = this.start_x;
        this.node.y = this.start_y;

        this.body.linearVelocity = cc.p(0, 0);
        this.body.angularVelocity = 0;
    },

    onBeginContact: function(contact, selfCollider, otherCollider) {
        // 白球有可能,碰球杆,碰球,碰邊,球袋
        if(otherCollider.node.groupIndex == 2) {
            this.node.active = false;
            return;
        }
    },
});
  • 掛在canvas節點上的遊戲引擎
cc.Class({
    extends: cc.Component,

    properties: {

        is_debug: false,
        gravity: cc.p(0, -320), 

    },


    // onLoad () {},
    onLoad: function() {
        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;

        cc.director.getPhysicsManager().gravity = this.gravity;
    },

    // update (dt) {},
});
  • 掛在canvas節點上總場景
cc.Class({
    extends: cc.Component,

    properties: {

        ball_root: {
            type: cc.Node,
            default: null,
        },

        w_ball: {
            type: cc.Node,
            default: null,
        },
    },


    // onLoad () {},

    start () {
        this.is_game_started = true;
    },

    restart_game: function() {
        for(var i = 0; i < this.ball_root.childrenCount; i ++) {
            var b = this.ball_root.children[i];
            b.getComponent("ball").reset();
        }

        this.w_ball.getComponent("w_ball").reset();
        this.is_game_started = true;
    },

    check_game_over: function() {
        for(var i = 0; i < this.ball_root.childrenCount; i ++) {
            var b = this.ball_root.children[i];
            if(b.active === true) {
                return;
            }
        }

        this.is_game_started = false; // game_over;
        this.scheduleOnce(this.restart_game.bind(this), 3);
    },

    update (dt) {
        if (!this.is_game_started) {
            return;
        }

        // 是否所有的球都打入進去了;   
    },
});

掛在球杆節點上

cc.Class({
    extends: cc.Component,

    properties: {

        SHOOT_POWER: 18, // 合適的值就可以了
    },


    // onLoad () {},

    start () {
        this.body = this.getComponent(cc.RigidBody);

    },


    shoot_at: function(dst) {
        // 衝量: 給這個球杆一個方向的衝量,向量,大小,有方向;
        // 方向問題:  src---> dst;
        var src = this.node.getPosition();//此時的球杆頭位置
        var dir = cc.pSub(dst, src);//dst白球位置


        // 大小問題;
        var cue_len_half = this.node.width * 0.5;
        var len = cc.pLength(dir);
        var distance = len - cue_len_half;
        // end 

        var power_x = distance * this.SHOOT_POWER * dir.x / len;
        var power_y = distance * this.SHOOT_POWER * dir.y / len;

        //對該點施加衝量 applyLinearImpulse(衝量大小向量, 球杆的原點轉成世界座標, true)
        this.body.applyLinearImpulse(cc.p(power_x, power_y), this.node.convertToWorldSpaceAR(cc.p(0, 0)), true);

    },

    onPreSolve: function(contact, selfCollider, otherCollider) {
        this.node.active = false;
    },
    // update (dt) {},
});