一、主要邏輯
首先根據配置表設置好遊戲數據(比如大球的旋轉速度、旋轉方向、默認已經插上的針數及間隔角度,小球的數量等按需設置即可),開始遊戲後大球不停的旋轉,點擊屏幕從下方發射“大頭針”,並計算好移動距離,這樣可以不需要檢測針尖和大球的碰撞,當“大頭針”移動到指定位置時修改它的父節點爲大球,關鍵來了,這裏因爲大球一直在旋轉,爲了讓“大頭針”始終垂直的插上大球,這裏要正確設置小球的旋轉角度,大頭針的目標座標爲大球的底部,根據大球的半徑和角度可以求得具體x、y。如果大頭針和大頭針相碰了則遊戲失敗,如果沒有相碰則繼續下一輪,如果全部發射完畢則過關。
二、主要結構
大球-小球-大頭針
大球:只是個精靈節點
小球: 下方待發射區展示用,精靈+label顯示編號
大頭針:點擊發射時,根據小球的編號來創建一個大頭針並使其飛向大球同時移除待發射區最上面的一顆小球,大頭針的錨點爲針尖位置,方便計算旋轉角度。
三、上代碼:
大頭針
/**
* Created by xujiawei on 2020-04-29 17:58:39
*/
cc.Class({
extends: cc.Component,
properties: {
arrow: cc.Node,
numLabel: cc.Label,
},
initSmallBall(params) {
this.numLabel.string = params.num;
this.arrow.active = !!params.showArrow;
},
/**
* 當碰撞產生的時候調用
* @param {Collider} other 產生碰撞的另一個碰撞組件
* @param {Collider} self 產生碰撞的自身的碰撞組件
*/
onCollisionEnter: function (other, self) {
other.node.stopAllActions();
self.node.stopAllActions();
zy.event.emit("gameover");
cc.log('小球碰撞,遊戲失敗');
}
});
主要邏輯 Game.js
/**
* Created by xujiawei on 2020-04-29 17:37:50
*/
cc.Class({
extends: cc.Component,
properties: {
ballPanel: cc.Node,
smallBallPF: cc.Prefab,
bigBall: cc.Node,
levelLabel: cc.Label,
bulletNode: cc.Node,
bgNode: cc.Node,
},
init(params) {
this.smallBalls = [];
this.tmpBalls = []; // 發射的尚未添加到大球上的小球
this._bigSpeed = 0;
this._bigDir = -1;
this._gameStart = false;
this.curLevel = zy.dataMng.userData.curLevel;
this.curLevel = parseInt(this.curLevel);
this.loadLevel(this.curLevel);
},
loadLevel(l) {
let data = zy.dataMng.levelData.getLevelData(l);
this._bigDir = data.dir == 0 ? (Math.random() < 0.5 ? 1 : -1) : data.dir;
this._bigSpeed = data.speed;
this.levelLabel.string = "第 " + l + " 關";
// 清空數據
for (let b of this.tmpBalls) {
b.destroy();
}
for (let b of this.smallBalls) {
b.destroy();
}
this.tmpBalls.splice(0);
this.smallBalls.splice(0);
for (let i = 0; i < data.smallNum; i++) {
let ball = cc.instantiate(this.bulletNode);
ball.parent = this.ballPanel;
this.smallBalls.push(ball);
ball.getComponentInChildren(cc.Label).string = data.smallNum - i;
}
this.bgNode.color = cc.color("#436770");
this.loadBigBall(data.bigNum);
this.scheduleOnce(() => {
this._gameStart = true;
}, 0.1);
},
start() {
let mng = cc.director.getCollisionManager();
mng.enabled = true;
// mng.enabledDebugDraw = true;
// mng.enabledDrawBoundingBox = true;
this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
zy.event.on("gameover", () => {
if (this._gameStart) {
this._gameStart = false;
this.bgNode.color = cc.color("#7A3341");
zy.ui.tip.show("遊戲失敗,即將重新開始");
this.scheduleOnce(() => {
this.loadLevel(this.curLevel);
}, 2);
}
}, this);
},
loadBigBall(counts) {
this.bigBall.destroyAllChildren();
let radius = this.bigBall.width / 2 - 2;
let degree = 360 / counts;
for (let i = 0; i < counts; i++) {
let ball = cc.instantiate(this.smallBallPF);
let radian = cc.misc.degreesToRadians(i * degree);
let x = radius * Math.sin(radian);
let y = radius * Math.cos(radian);
ball.x = x;
ball.y = y;
ball.parent = this.bigBall;
// 計算旋轉角度
ball.angle = 180 - i * degree;
ball.getChildByName("numLabel").active = false;
}
},
onTouchStart(event) {
if (!this._gameStart) {
return;
}
if (this.smallBalls.length > 0) {
let bullet = this.smallBalls.shift();
let wordPos = bullet.parent.convertToWorldSpaceAR(bullet.getPosition());
let ball = cc.instantiate(this.smallBallPF);
ball.getComponentInChildren(cc.Label).string = bullet.getComponentInChildren(cc.Label).string;
ball.parent = this.bigBall.parent;
ball.position = this.bigBall.parent.convertToNodeSpaceAR(wordPos);
this.tmpBalls.push(ball);
bullet.destroy();
let radius = this.bigBall.height / 2 - 2;
let des = cc.v2(0, this.bigBall.y - radius);
ball.runAction(cc.sequence(cc.moveTo(0.05, des).easing(cc.easeSineOut()), cc.callFunc(() => {
this.tmpBalls.shift();
ball.parent = this.bigBall;
let angle = this.bigBall.angle;
angle = angle % 360 + 180;
let radian = cc.misc.degreesToRadians(angle);
let x = radius * Math.sin(radian);
let y = radius * Math.cos(radian);
ball.x = x;
ball.y = y;
ball.angle = 180 - angle;
this.scheduleOnce(this._checkPass.bind(this), 0);
})));
}
},
_checkPass() {
if (this._gameStart && this.smallBalls.length == 0) {
this._gameStart = false;
this.bgNode.color = cc.color("#4C7043");
let des = "恭喜過關,即將進入下一關";
const max = zy.dataMng.levelData.getMaxLevel();
if (this.curLevel < max) {
this.curLevel += 1;
} else {
des = "恭喜你通關了";
}
zy.ui.tip.show(des);
this.scheduleOnce(() => {
this.loadLevel(this.curLevel);
}, 2);
zy.dataMng.userData.curLevel = this.curLevel;
}
},
lateUpdate(dt) {
if (!this._gameStart) {
return;
}
this.bigBall.angle += this._bigDir * this._bigSpeed;
}
});