《切水果》核心技術(shù):拋物線物理仿真
在切水果游戲中,我們需要從下方向上斜拋出水果。這時(shí)候就需要使用拋物線物理仿真。
一、?創(chuàng)建項(xiàng)目、導(dǎo)入資源、編輯游戲場(chǎng)景

具體場(chǎng)景在此不過(guò)過(guò)多闡述,需要源碼的可以聯(lián)系我們。
二、?組件化開發(fā)流程
【1】創(chuàng)建一個(gè)類,自定義腳本js。
【2】實(shí)例化這個(gè)類,得到這個(gè)類的實(shí)例?!咎砑咏M件】、addComponent。
【3】執(zhí)行原理:加載游戲場(chǎng)景 → 遍歷節(jié)點(diǎn)樹 → 加載節(jié)點(diǎn)上所有組件 → 游戲引擎調(diào)用組件中的onLoad方法、start方法 → 每次更新都會(huì)調(diào)用update(dt)方法。
新建game_mgr,代碼如下:
// 定義了一個(gè)class, new 構(gòu)造函數(shù)()
cc.Class({
// 組件類
extends: cc.Component,
// 屬性列表,可以通過(guò)編輯器修改設(shè)置,注意點(diǎn):在properties中改無(wú)效
properties: {
is_debug: false,
speed: 100,
pos: cc.v2(0, 0),
},
// 第一次運(yùn)行之前調(diào)用 組件實(shí)例.start
start () {
// this--> 當(dāng)前組件實(shí)例, this.node --> 當(dāng)前組件實(shí)例所在的節(jié)點(diǎn);
// 調(diào)用引擎的API,來(lái)做游戲控制;
console.log("start:", this, this.node);
},
// 每次刷新的時(shí)候調(diào)用; 組件實(shí)例.update;
// dt : 與幀頻有關(guān)、平均時(shí)間(不是每次都相同)
// 保證不同手機(jī)顯示效果一致,保證是勻速平滑進(jìn)行
update (dt) {
console.log(dt);
},
});
在Canvas節(jié)點(diǎn)上,【添加組件】-【用戶腳本組件】-game_mgr。

在properties中添加屬性,且通過(guò)編輯器綁定:
apple : { type : cc.Node, default : null, },

在update方法中添加如下代碼:
// 為什么非得用dt,不用會(huì)導(dǎo)致什么問(wèn)題?
// 【1】因?yàn)椴煌謾C(jī)幀頻不一樣,保證不同手機(jī)顯示效果一致!
// 60FPS的手機(jī)會(huì)比30FPS的手機(jī)運(yùn)動(dòng)距離多一倍
// 【2】因?yàn)閐t每次都不一樣,保證同一手機(jī)是勻速運(yùn)動(dòng)
//this.apple.x += this.speed;
this.apple.x += this.speed * dt;
三、?拋物線物理仿真實(shí)現(xiàn)
重力加速g:
Vy = v0 + g * t;
h = v0 * t + 0.5 * g * t * t;
斜拋運(yùn)動(dòng):
分解到水平上: 勻速直線運(yùn)動(dòng);
分解到豎直方向: 勻變速直線運(yùn)動(dòng) (加速度)。
1. 自定義用戶腳本類throw_action.js
properties: {
G: -160, // 重力加速度
speed: 200, // 初速度大小
degree: 45, // 拋射角度
play_onload: false,
},
在start方法中根據(jù)是否需要在加載的時(shí)候就執(zhí)行,調(diào)用相應(yīng)方法:
start () {
this.is_moving = false; // 標(biāo)記這個(gè)物體是否移動(dòng);
if (this.play_onload) { // 執(zhí)行拋物線這個(gè)運(yùn)動(dòng)
this.throw_aciton();
}
},
throw_aciton() {
var r = this.degree * Math.PI / 180;
this.vx = this.speed * Math.cos(r);
this.vy = this.speed * Math.sin(r);
this.is_moving = true;
},
在throw_action中實(shí)質(zhì)只是修改設(shè)置相關(guān)的關(guān)鍵參數(shù)(速度分量、移動(dòng)狀態(tài)),具體動(dòng)態(tài)效果在update(dt)方法中執(zhí)行,因?yàn)槊扛粢欢螘r(shí)間會(huì)刷新一次。
update (dt) {
if (this.is_moving === false) {
return;
}
// 水平方向運(yùn)動(dòng)(勻速直線運(yùn)動(dòng))
var sx = this.vx * dt;
this.node.x += sx;
// 豎直方向運(yùn)動(dòng)(勻變速直線運(yùn)動(dòng))
var sy = this.vy * dt + 0.5 + this.G * dt * dt;
this.vy = this.vy + this.G * dt;
this.node.y += sy;
// 當(dāng)前節(jié)點(diǎn)(蘋果)的坐標(biāo)轉(zhuǎn)換為世界坐標(biāo)(參考原點(diǎn)為左下角)
var w_pos = this.node.convertToWorldSpaceAR(cc.v2(0, 0));
if (this.out_of_screen(w_pos)) {
this.node.removeFromParent();
console.log("removed");
}
},
out_of_screen(w_pos){
return w_pos.x < 0 || w_pos.x > cc.winSize.width ||
w_pos.y < 0 || w_pos.y > cc.winSize.height;
},
如果蘋果超出屏幕顯示區(qū)域,應(yīng)該移出。
2. 添加組件到apple節(jié)點(diǎn)上

運(yùn)行結(jié)果如下:

發(fā)現(xiàn)蘋果速度小了,改properties中的值200為400,編譯發(fā)現(xiàn)運(yùn)行無(wú)變化??!為什么?

要么在編輯器中修改,要么在onLoad方法或start方法中修改。而且優(yōu)先級(jí)start>onLoad>編輯器。
3. 隨機(jī)不斷拋出蘋果
修改update(dt)方法中的代碼如下:
if (this.out_of_screen(w_pos)) {
//this.node.removeFromParent();
//console.log("removed");
this.is_moving = false;
this.re_show();
}
重新顯示蘋果的代碼如下:
re_show(){
if(this.is_moving){
return;
}
// [負(fù)屏幕寬度一半,屏幕高度一半) 例如[-200,200)
var x = Math.random() * cc.winSize.width - cc.winSize.width / 2;
var y = -cc.winSize.height * 0.5 + 50;
this.node.setPosition(x, y);
this.speed = Math.random()*300 + 200; // [200,500)
this.degree = Math.random()*45 + 45; // [45,90)
this.throw_aciton();
},
如果是在運(yùn)動(dòng)中,不要重新出現(xiàn)新蘋果。
當(dāng)蘋果超出屏幕區(qū)域后,移動(dòng)狀態(tài)切換為false。然后,進(jìn)入到re_show方法中,條件才不會(huì)被攔截,所以會(huì)設(shè)置蘋果到新的位置(從屏幕下方拋出,錨點(diǎn)在屏幕中心)。設(shè)置拋出速度、角度,然后調(diào)用throw_action()方法即可。方法throw_action中會(huì)重新計(jì)算速度分量,切回將運(yùn)動(dòng)移動(dòng)狀態(tài)修改為true,如此update方法中又能根據(jù)運(yùn)動(dòng)狀態(tài)進(jìn)行相關(guān)刷新,動(dòng)態(tài)顯示了。
4. 細(xì)節(jié)優(yōu)化
發(fā)現(xiàn)蘋果沒(méi)有完全離開屏幕就消失了,還有一半遺留在屏幕就消失了。
out_of_screen(w_pos){
/*return w_pos.x < 0 || w_pos.x > cc.winSize.width ||
w_pos.y < 0 || w_pos.y > cc.winSize.height;*/
var apple_width = this.node.width/2;
var apple_height = this.node.height/2;
return w_pos.x < -apple_width
|| w_pos.x > cc.winSize.width + apple_width
|| w_pos.y < -apple_height
|| w_pos.y > cc.winSize.height + apple_height;
},
如上修改即可,因?yàn)樘O果的錨點(diǎn)也在中心,要完全離開,還需要考慮蘋果的寬和高!
四、?微信小游戲打包發(fā)布
略,需要的,可以加群649760436。