一、游戲的分析(之前沒有接觸過小游戲,制作的思維還停留在大型ARPG游戲大家共同協作的想法里,但是小游戲講究小而全,大部分時間是一個人獨立開發,所以需要迫使自己養成看到小游戲先拆分細化的思想)
二、一些必要的參數
台階參數
1: 設置分辨率: 720x1280
2: 台階的原點:
3: 配置好4個中心點,如果跳到就到4個中心點,否則就失敗;
4: 編寫代碼獲得中心點的位置,來初始化Player;
5: 斜率: 0.5560472, 與平行四邊形相當;
6: 塊開始的世界坐標的位置: (180, 350)
參數
1: 監聽事件,開啟蓄積能量, 2秒縮放到0.5;
2: 0.5秒內,scale變形到1;
3: 0.5秒內, 旋轉一周;
4: 0.5秒內,跳躍到目的地;
5: 能量蓄積: 加速度: power: 600, 初始化: 150;
this.speed += dt * this.power;
this.jumpDistance += this.speed * dt;
6:帶上拖尾:
MotionStreak組件: 配置好圖片;(引擎bug,父節點移動,帶有拖尾的子節點顯示效果就會有問題,待解決)
7: ancher_offset: 100
8: 生成地圖: 200, 400的距離隨機
9: 地圖滾動參數: y, 隨着玩家滾動, x 取最左值和最右值(180, 580);
10:開始位置(180, 350)
三、實現的步驟
1 調整好player,具有旋轉和壓縮兩個動畫
2 實現跳躍,前置條件是有東西可跳,所以要先制作兩個塊
3 制作塊,設置塊的原點,中心點,前后左右點(主要是做跳躍檢測,使用小色塊),currBlock nextBlock
4 開始寫game_scene.js腳本
綁定player和block
固定第一個block(坐標轉換)
添加第二個block (add_block方法)
5 調整第一個塊和player的位置
6 實現player的跳躍方法player_jump,以及block的檢測方法is_jump_on_block
7 實現地圖滾動方法move_map
8 完善游戲代碼
四、代碼
//game_scene.js cc.Class({ extends: cc.Component, properties: { // foo: { // // ATTRIBUTES: // default: null, // The default value will be used only when the component attaching // // to a node for the first time // type: cc.SpriteFrame, // optional, default is typeof default // serializable: true, // optional, default is true // }, // bar: { // get () { // return this._bar; // }, // set (value) { // this._bar = value; // } // }, player: { type: cc.Node, default: null }, block_prefabs: { type: cc.Prefab, default: [] }, block_root: { default: null, type: cc.Node }, left_org: cc.v2(0, 0), map_root: { default: null, type: cc.Node }, y_radio: 0.5560472, checkout: { type: cc.Node, default: null } }, // LIFE-CYCLE CALLBACKS: // onLoad () {}, start() { this.block_list = []; this.cur_block = cc.instantiate(this.block_prefabs[Math.floor(Math.random() * this.block_prefabs.length)]); this.block_root.addChild(this.cur_block); // 將第一個塊的位置設置為初始位置 this.cur_block.setPosition(this.block_root.convertToNodeSpaceAR(this.left_org)); var w_pos = this.cur_block.getChildByName('mid').convertToWorldSpaceAR(cc.v2(0, 0)); this.player.setPosition(this.map_root.convertToNodeSpaceAR(w_pos)); this.next_block = this.cur_block; this.player_comp = this.player.getComponent("player"); this.block_zOrder = -1; this.add_block(); }, add_block: function() { this.cur_block = this.next_block; this.next_block = cc.instantiate(this.block_prefabs[Math.floor(Math.random() * this.block_prefabs.length)]); this.block_root.addChild(this.next_block); this.next_block.zIndex = this.block_zOrder; this.block_zOrder--; var x_distance = 200 + Math.random() * 200; var y_distance = x_distance * this.y_radio; var next_pos = this.cur_block.getPosition(); next_pos.x += x_distance * this.player_comp.direction; next_pos.y += y_distance; this.next_block.setPosition(next_pos); this.player_comp.set_next_block(this.next_block.getComponent("block")); // 刪除block this.block_list.push(this.next_block); if (this.block_list.length >= 5) { for (var i = 0; i < 2; i++) { var block = this.block_list.shift(); block.destroy(); } } }, // 地圖滾動 move_map(offset_x, offset_y) { var m1 = cc.moveBy(0.5, offset_x, offset_y); var end_func = cc.callFunc(function() { this.add_block(); }.bind(this)); var seq = cc.sequence([m1, end_func]); this.map_root.runAction(seq); }, on_checkout_game: function() { this.checkout.active = true; }, on_game_again: function() { cc.director.loadScene("game_scene"); }, // update (dt) {}, });
// player.js var game_scene = require("game_scene"); cc.Class({ extends: cc.Component, properties: { // foo: { // // ATTRIBUTES: // default: null, // The default value will be used only when the component attaching // // to a node for the first time // type: cc.SpriteFrame, // optional, default is typeof default // serializable: true, // optional, default is true // }, // bar: { // get () { // return this._bar; // }, // set (value) { // this._bar = value; // } // }, init_speed: 150, a_power: 600, y_radio: 0.5560472, game_manager: { type: game_scene, default: null }, }, // LIFE-CYCLE CALLBACKS: onLoad() { this.next_block = null; this.direction = 1; }, start() { this.rot_node = this.node.getChildByName("rotate"); this.anima_node = this.rot_node.getChildByName("anima"); this.is_power_mode = false; this.speed = 0; this.x_distance = 0; this.anima_node.on(cc.Node.EventType.TOUCH_START, function(e) { this.is_power_mode = true; this.x_distance = 0; this.speed = this.init_speed; this.anima_node.stopAllActions(); this.anima_node.runAction(cc.scaleTo(2, 1, 0.5)); }.bind(this), this); this.anima_node.on(cc.Node.EventType.TOUCH_END, function(e) { this.is_power_mode = false; this.anima_node.stopAllActions(); this.anima_node.runAction(cc.scaleTo(0.5, 1, 1)); this.player_jump(); }.bind(this), this); this.anima_node.on(cc.Node.EventType.TOUCH_CANCEL, function(e) { this.is_power_mode = false; this.anima_node.stopAllActions(); this.anima_node.runAction(cc.scaleTo(0.5, 1, 1)); this.player_jump(); }.bind(this), this); }, update(dt) { if (this.is_power_mode) { this.speed += (this.a_power * dt); this.x_distance += this.speed * dt; } }, player_jump: function() { var x_distance = this.x_distance * this.direction; var y_distance = this.x_distance * this.y_radio; var target_pos = this.node.getPosition(); target_pos.x += x_distance; target_pos.y += y_distance; // 跳躍時候旋轉 this.rot_node.runAction(cc.rotateBy(0.5, -360 * this.direction)); var w_pos = this.node.parent.convertToWorldSpaceAR(target_pos); var is_game_over = false; if (this.next_block.is_jump_on_block(w_pos, this.direction)) { target_pos = this.node.parent.convertToNodeSpaceAR(w_pos); } else { is_game_over = true; } var j = cc.jumpTo(0.5, target_pos, 200, 1); this.direction = (Math.random() < 0.5) ? -1 : 1; var end_func = cc.callFunc(function() { if (is_game_over) { this.game_manager.on_checkout_game(); } else { if (this.direction === -1) { this.game_manager.move_map(580 - w_pos.x, -y_distance); } else { this.game_manager.move_map(180 - w_pos.x, -y_distance); } } }.bind(this)); var seq = cc.sequence(j, end_func); this.node.runAction(seq); }, set_next_block(block) { this.next_block = block; }, });
// block.js cc.Class({ extends: cc.Component, properties: { // foo: { // // ATTRIBUTES: // default: null, // The default value will be used only when the component attaching // // to a node for the first time // type: cc.SpriteFrame, // optional, default is typeof default // serializable: true, // optional, default is true // }, // bar: { // get () { // return this._bar; // }, // set (value) { // this._bar = value; // } // }, }, start() { this.mid = this.node.getChildByName("mid"); this.up = this.node.getChildByName("up"); this.down = this.node.getChildByName("down"); this.left = this.node.getChildByName("left"); this.right = this.node.getChildByName("right"); }, // dir 1右跳 -1左跳 is_jump_on_block(w_dst_pos, direction) { var mid_pos = this.mid.convertToWorldSpaceAR(cc.v2(0, 0)); var dir = w_dst_pos.sub(mid_pos); var min_len = dir.mag(); var min_pos = mid_pos; if (direction === 1) { var up_pos = this.up.convertToWorldSpaceAR(cc.v2(0, 0)); dir = w_dst_pos.sub(up_pos); var len = dir.mag(); if (min_len > len) { min_len = len; min_pos = up_pos; } var down_pos = this.down.convertToWorldSpaceAR(cc.v2(0, 0)); dir = w_dst_pos.sub(down_pos); var len = dir.mag(); if (min_len > len) { min_len = len; min_pos = down_pos; } } else { var left_pos = this.left.convertToWorldSpaceAR(cc.v2(0, 0)); dir = w_dst_pos.sub(left_pos); var len = dir.mag(); if (min_len > len) { min_len = len; min_pos = left_pos; } var right_pos = this.right.convertToWorldSpaceAR(cc.v2(0, 0)); dir = w_dst_pos.sub(right_pos); var len = dir.mag(); if (min_len > len) { min_len = len; min_pos = right_pos; } } // 找到跳躍位置距離參考點最近的那個點以及位置 dir = w_dst_pos.sub(min_pos); if (dir.mag() < 100) { w_dst_pos.x = min_pos.x; w_dst_pos.y = min_pos.y; return true; } return false; }, });