轉載URL:https://www.jianshu.com/p/d76dc3cf5aa7node
[關鍵詞]小遊戲開發,cocos,數學,類似三角形,單位向量,弧度角度轉換,向量轉換爲夾度,產生不重複的隨機序列,切水果遊戲,拋物線算法
在搖桿控制物體運動的遊戲中,搖桿的手柄(下圖黃色圓餅),不能移出搖桿所在的套(下圖灰色圓環),也就是說搖桿偏離中心點的最大距離爲max_R。一旦觸摸移動過程當中移動的點超出此最大距離,咱們須要將搖桿手柄拖回到最大距離處。數組
如何將搖桿拖回到灰色圓環處,無非是要求出在C點的座標。根據△ODC和△OBA爲類似三角形,有OD:OB = OC:OA,也就是?:pos.x = max_R:len。dom
其中pos爲A點的座標(x,y),len爲向量OA的模。ide
?表示C點的x座標,也就是可是咱們求出來,要做爲新的pos,去設置搖桿的位置。函數
因此有:工具
在搖桿控制物體的運動時,若是搖桿只控制物體的方向,也就是說無論搖桿偏離原點多遠,都不會影響物體運動的速度,而隻影響物體運動的方向,也就是實質上咱們要獲取一個方向的值(好比向量與x軸正方向的夾角),這時候,咱們就須要使用單位向量。測試
單位向量是指向量的模爲1的向量,也就是以一個單位長度爲半徑畫一個圓,從圓心指向圓周上任意一點的向量都是單位向量。this
假設單位向量OA與x軸正向的夾角爲α,則向量OA能夠用(cosα,sinα)表示,也就是A點的座標。以下圖所示:blog
因此無論任何向量,咱們要轉換爲單位向量,只須要計算出這個向量的餘弦和正弦值就能夠了。例如向量OC咱們將其轉換爲單位向量就是OC’,由於OC’的長度爲1,因此向量OC’的座標就是(cos(c),sin(c)),c爲OC和x軸正方向的夾角。而OC’和OC的方向是重合的,他們與x軸正向夾角相等,也就是咱們只須要計算向量OC的cos(c)、sin(c)便可。
假設獲得的C點座標爲pos(x,y),則在Cocos遊戲開發中,會有下列代碼:
var len = pos.mag(); // 求向量pos的模(內部算法是(x2+y2)開根號)。
pos.x = pos.x / len; // 獲得單位向量的x座標
pos.y = pos.y/ len; // 獲得單位向量的y座標
角度指從原點發出的射線與X軸正向的角度。而x軸正向繞原點在水平平面內旋轉一週爲360°。而弧度是指圓弧長度與半徑的比值。假設有個半徑r爲1的圓,則其一週爲360°。圓周對應的弧度長爲2πr=2π。也就是說在角度轉換爲弧度是360°等價於2π,180°等價於π。
(1)弧度轉換爲角度:根據degree : 180 = rad:π
var rad = Math.atan2(y, x); // 反正切函數,獲得弧度
var degree = 180 * rad / Math.PI ; // 將弧度rad轉換爲角度
(2)角度轉換爲弧度:根據rad:π=degree:180
var degree = 90;
var rad = Math.PI * degree / 180; // 角度轉換爲弧度
在遊戲中,有時候咱們須要計算物體旋轉了多少度,好比咱們要模擬一個KTV裏面的遊戲轉盤,手指觸摸的時候,要獲取觸摸的點的位置,觸摸點的位置與轉盤中心點之間構成一個向量,咱們要獲取轉動了多少度,就須要有一個參考向量。
以下圖所示,假如藍色的圓就是轉盤的邊緣,咱們最開始觸摸A點,而後轉動到B點,這時候轉動的角度就是∠AOB,這個角度在Cocos中如何求呢?
代碼pos就表示B點的座標,pos和原點(0,0)相減,獲得向量OB,也即代碼中的dirVec,弧AB爲radian,轉換爲角度degree。
// 向量轉換爲角度
vectorsToDegree(dirVec) {
// 水平向右的對比向量
let comVec = cc.v2(1, 0);
// 求方向向量與對比向量間的弧度
let radian = dirVec.signAngle(comVec);
// 將弧度轉換爲角度
let degree = cc.misc.radiansToDegrees(radian);
return degree;
},
調用示例(具體能夠參考咱們的《KTV酒令轉盤虛擬仿真實現》):
// 獲取觸摸點與原點連線的射線與X軸正向的角度
getTouchAngle(e){
var screen_pos = e.getLocation(); // 觸摸點世界座標
// 轉換爲相對於當前節點的錨點的座標
var pos = this.node.convertToNodeSpaceAR(screen_pos);
// 獲取觸摸點距離輪盤中心點的向量
var dirVec = pos.sub(cc.v2(0,0));
// 將向量轉換爲基於參考方向(v2(0,1))的角度
return this.vectorsToDegree(dirVec);
},
重力加速g:
Vy= V0+ g * t;
h = V0 t + 0.5 g t t;
斜拋運動(以下圖所示):
分解到水平上:勻速直線運動;
分解到豎直方向:勻變速直線運動(加速度)。
具體在Cocos中如何實現,限於篇幅,在此不作贅述,能夠參考咱們的公開課《切水果》核心技術:拋物線物理仿真。
應用場景:例如洗牌,發牌,例如掃雷遊戲中從100個格子中隨機抽取10個埋雷。
凡是須要打亂順序,或者從某個數組中抽取必定數量的不重複的元素,都用得着。
// 數組工具類
var ArrayUtils = function(){};
// 【1】初始化獲得有序元素數組:[start,end)的天然數序列
ArrayUtils.initOrderArray = function(start, end){
let sortArray = [];
for(let i= start; i<end; i++){
sortArray.push(i);
}
return sortArray;
};
// 【2】從數組arr中隨機抽取count個元素,返回數組
ArrayUtils.randChoiseFromArr = function(arr, count){
let result = arr;
// 隨機排序,打亂順序
result.sort(function(){
return 0.5 - Math.random();
});
// 返回打亂順序後的數組中的前count個元素
return result.slice(0,count);
};
// 【3】從從start到end中的連續整數中隨機抽取count個數字
ArrayUtils.randChoiseFromTo = function(start, end, count){
let arr = this.initOrderArray(start,end);
return this.randChoiseFromArr(arr, count);
};
// 【2】-【方式二】從數組arr中隨機抽取count個元素,返回數組
ArrayUtils.getRandomArrayElements = function(arr, count) {
// 從0位置取到結束位置存入shffled數組
let shuffled = arr.slice(0);
let i = arr.length;
let min = i - count;
let temp = 0;
let index = 0;
// 隨機一個位置的元素和最後一個元素交換
// 隨機一個位置元素和倒數第二個元素交換
// 假設i=8,count=3,則min=5,
// 循環體中[i]=7,6,5,也就是說最後三個元素要從數組中隨機取
// 循環結束後,從min=5的位置取到結束,即取3個元素。
while(i-- > min) {
index
= Math.floor((i + 1) * Math.random());
temp
= shuffled[index];
shuffled[index]
= shuffled[i];
shuffled[i]
= temp;
}
return shuffled.slice(min);
};
module.exports= ArrayUtils;
原理解析:如上述代碼,方式一randChoiseFromArr方法,採用隨機排序打亂數組中全部元素的順序,而後從數組第一個元素開始抽取須要的count個元素。
方式二getRandomArrayElements方法,須要取幾個元素,就隨機幾個位置和倒數最後幾個元素交換,最後取倒數最後幾個元素便可。注意:index = Math.floor((i+ 1) * Math.random());i+1才能保證最後一個元素多是自身和自身交換,也就是保證這個位置的元素多是原有這個位置的元素。
上面全部代碼咱們已經所有測試經過,感興趣的朋友能夠本身動手去實踐。
————————————————————————————————————
做者:遊戲程序猿
連接:https://www.jianshu.com/p/d76dc3cf5aa7來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。