游戲編程中需要掌握哪些數(shù)學物理知識
一、相似三角形知識的應用
在搖桿控制物體運動的游戲中,搖桿的手柄(下圖黃色圓餅),不能移出搖桿所在的套(下圖灰色圓環(huán)),也就是說搖桿偏離中心點的最大距離為max_R。一旦觸摸移動過程中移動的點超出此最大距離,我們需要將搖桿手柄拖回到最大距離處。

如何將搖桿拖回到灰色圓環(huán)處,無非是要求出在C點的坐標。根據(jù)△ODC和△OBA為相似三角形,有OD:OB = OC:OA,也就是?:pos.x = max_R:len。
其中pos為A點的坐標(x,y),len為向量OA的模。
?表示C點的x坐標,也就是但是我們求出來,要作為新的pos,去設置搖桿的位置。
所以有:

二、單位向量
在搖桿控制物體的運動時,如果搖桿只控制物體的方向,也就是說不管搖桿偏離原點多遠,都不會影響物體運動的速度,而只影響物體運動的方向,也就是實質(zhì)上我們要獲取一個方向的值(比如向量與x軸正方向的夾角),這時候,我們就需要使用單位向量。
單位向量是指向量的模為1的向量,也就是以一個單位長度為半徑畫一個圓,從圓心指向圓周上任意一點的向量都是單位向量。
假設單位向量OA與x軸正向的夾角為α,則向量OA可以用(cosα,sinα)表示,也就是A點的坐標。如下圖所示:

所以不管任何向量,我們要轉(zhuǎn)換為單位向量,只需要計算出這個向量的余弦和正弦值就可以了。例如向量OC我們將其轉(zhuǎn)換為單位向量就是OC’,因為OC’的長度為1,所以向量OC’的坐標就是(cos(c),sin(c)),c為OC和x軸正方向的夾角。而OC’和OC的方向是重合的,他們與x軸正向夾角相等,也就是我們只需要計算向量OC的cos(c)、sin(c)即可。
假設得到的C點坐標為pos(x,y),則在Cocos游戲開發(fā)中,會有下列代碼:
var len = pos.mag(); // 求向量pos的模(內(nèi)部算法是(x2+y2)開根號)。
pos.x = pos.x / len; // 得到單位向量的x坐標
pos.y = pos.y/ len; // 得到單位向量的y坐標
三、弧度角度轉(zhuǎn)換
角度指從原點發(fā)出的射線與X軸正向的角度。而x軸正向繞原點在水平平面內(nèi)旋轉(zhuǎn)一周為360°。而弧度是指圓弧長度與半徑的比值。假設有個半徑r為1的圓,則其一周為360°。圓周對應的弧度長為2πr=2π。也就是說在角度轉(zhuǎn)換為弧度是360°等價于2π,180°等價于π。
1.弧度轉(zhuǎn)換為角度:根據(jù) degree : 180 = rad:π
var rad = Math.atan2(y, ?x); // 反正切函數(shù),得到弧度
var degree = 180 * rad / Math.PI ; // 將弧度rad轉(zhuǎn)換為角度
2.角度轉(zhuǎn)換為弧度:根據(jù)rad:π=degree:180
var degree = 90;
var rad = Math.PI * degree / 180; // 角度轉(zhuǎn)換為弧度
四、向量轉(zhuǎn)換為夾角
在游戲中,有時候我們需要計算物體旋轉(zhuǎn)了多少度,比如我們要模擬一個KTV里面的游戲轉(zhuǎn)盤,手指觸摸的時候,要獲取觸摸的點的位置,觸摸點的位置與轉(zhuǎn)盤中心點之間構(gòu)成一個向量,我們要獲取轉(zhuǎn)動了多少度,就需要有一個參考向量。
如下圖所示,假如藍色的圓就是轉(zhuǎn)盤的邊緣,我們最開始觸摸A點,然后轉(zhuǎn)動到B點,這時候轉(zhuǎn)動的角度就是∠AOB,這個角度在Cocos中如何求呢?
代碼pos就表示B點的坐標,pos和原點(0,0)相減,得到向量OB,也即代碼中的dirVec,弧AB為radian,轉(zhuǎn)換為角度degree。

// 向量轉(zhuǎn)換為角度?
vectorsToDegree(dirVec) { ? ?
// 水平向右的對比向量 ??
?let comVec = cc.v2(1, 0); ? ?
// 求方向向量與對比向量間的弧度 ? ?
let radian = dirVec.signAngle(comVec); ? ?
// 將弧度轉(zhuǎn)換為角度 ??
?let degree = cc.misc.radiansToDegrees(radian); ? ?
return degree;?
},
調(diào)用示例(具體可以參考我們的《KTV酒令轉(zhuǎn)盤虛擬仿真實現(xiàn)》):
// 獲取觸摸點與原點連線的射線與X軸正向的角度?
getTouchAngle(e){ ? ?
var screen_pos = e.getLocation();?
? // 觸摸點世界坐標 ??
?// 轉(zhuǎn)換為相對于當前節(jié)點的錨點的坐標 ?
??var pos = this.node.convertToNodeSpaceAR(screen_pos); ?
?// 獲取觸摸點距離輪盤中心點的向量 ?
??var dirVec = pos.sub(cc.v2(0,0)); ?
??// 將向量轉(zhuǎn)換為基于參考方向(v2(0,1))的角度 ? ?
return this.vectorsToDegree(dirVec);?
},
五、切水果游戲中的拋物線
重力加速g:
Vy = V0 + g * t;
h = V0 * t + 0.5 * g * t * t;
斜拋運動(如下圖所示):
分解到水平上: 勻速直線運動;
分解到豎直方向: 勻變速直線運動 (加速度)。

具體在Cocos中如何實現(xiàn),限于篇幅,在此不做贅述,可以參考我們的公開課《切水果》核心技術:拋物線物理仿真。
六、如何產(chǎn)生不重復的隨機序列
應用場景:例如洗牌,發(fā)牌,例如掃雷游戲中從100個格子中隨機抽取10個埋雷。
凡是需要打亂順序,或者從某個數(shù)組中抽取一定數(shù)量的不重復的元素,都用得著。
// 數(shù)組工具類?
var ArrayUtils = function(){};?
// 【1】初始化得到有序元素數(shù)組:[start,end)的自然數(shù)序列?
ArrayUtils.initOrderArray = function(start, end){ ??
?let sortArray = []; ?
?for(let i= start; i<end; i++){ ? ? ??
?sortArray.push(i); ?
??} ??
?return sortArray;?
};?
?// 【2】從數(shù)組arr中隨機抽取count個元素,返回數(shù)組
ArrayUtils.randChoiseFromArr = function(arr, count){ ? ?
let result = arr; ??
?// 隨機排序,打亂順序
? result.sort(function(){ ? ? ??
?return 0.5 - Math.random();?
? ?}); ??
?// 返回打亂順序后的數(shù)組中的前count個元素 ??
?return result.slice(0,count); };
// 【3】從從start到end中的連續(xù)整數(shù)中隨機抽取count個數(shù)字?
ArrayUtils.randChoiseFromTo = function(start, end, count){ ?
?let arr = this.initOrderArray(start,end); ?
?return this.randChoiseFromArr(arr, count); };
// 【2】-【方式二】從數(shù)組arr中隨機抽取count個元素,返回數(shù)組 ArrayUtils.getRandomArrayElements = function(arr, count) {?
? ?// 從0位置取到結(jié)束位置存入shffled數(shù)組 ? ?
let shuffled = arr.slice(0); ?
?let i = arr.length; ?
?let min = i - count; ??
?let temp = 0; ??
?let index = 0;?
? ?// 隨機一個位置的元素和最后一個元素交換 ?
?// 隨機一個位置元素和倒數(shù)第二個元素交換
? ?// 假設i=8,count=3,則min=5,
? ?// 循環(huán)體中[i]=7,6,5,也就是說最后三個元素要從數(shù)組中隨機取?
? ?// 循環(huán)結(jié)束后,從min=5的位置取到結(jié)束,即取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 方法,采用隨機排序打亂數(shù)組中所有元素的順序,然后從數(shù)組第一個元素開始抽取需要的count個元素。
方式二getRandomArrayElements方法,需要取幾個元素,就隨機幾個位置和倒數(shù)最后幾個元素交換,最后取倒數(shù)最后幾個元素即可。注意:index = Math.floor((i + 1) * Math.random()); i+1才能保證最后一個元素可能是自身和自身交換,也就是保證這個位置的元素可能是原有這個位置的元素。
編程中需要掌握的數(shù)學知識就先分享到這里,更多課程和源碼下載請點擊:
https://bycwedu.vipwan.cn/promotion_channels/630597732