用原生 JS 寫一個(gè)簡(jiǎn)易版的臺(tái)球
前言
突發(fā)奇想想用JS寫一個(gè)臺(tái)球小游戲,磕磕碰碰之后,算是實(shí)現(xiàn)了一個(gè)簡(jiǎn)易版的。用到的知識(shí)主要是通過遞歸來調(diào)用requestAnimationFrame,以及一些簡(jiǎn)單的三角函數(shù)角度計(jì)算。requestAnimationFrame就是一個(gè)JS動(dòng)畫幀,簡(jiǎn)單來說和定時(shí)器有點(diǎn)相似,但是動(dòng)畫呈現(xiàn)出來的效果比定時(shí)器更流暢,性能更好。
1、繪制游戲元素
CSS
html
JS
2、球桿跟隨鼠標(biāo)旋轉(zhuǎn)
先獲取鼠標(biāo)在頁面的坐標(biāo),然后減去球心的坐標(biāo),就得到了一個(gè)相對(duì)坐標(biāo)。然后把球心當(dāng)成原點(diǎn),計(jì)算出鼠標(biāo)相對(duì)球心的角度,最后把這個(gè)角度賦值給球桿的transform屬性,就可以實(shí)現(xiàn)球桿跟隨鼠標(biāo)旋轉(zhuǎn)的效果了
3、球桿的擊球動(dòng)畫
球桿其實(shí)是由 3 個(gè)盒子組成的,最外面的大盒子來控制球桿的旋轉(zhuǎn),大盒子里面有兩個(gè)盒子 gan2 和 gan3, gan3 這個(gè)盒子用來放球桿的圖片。gan2 這個(gè)盒子是看不到的,它負(fù)責(zé)把球桿向外面撐開。所以球桿的動(dòng)畫就很簡(jiǎn)單了,只要增加和減少 gan2 盒子的寬,就能實(shí)現(xiàn)球桿的伸縮了。
實(shí)現(xiàn)動(dòng)畫就是用尾遞歸來重復(fù)調(diào)用 requestAnimationFrame 函數(shù)。
4、球桿擊球后,母球的移動(dòng)
母球的擊球動(dòng)畫同樣是通過尾遞歸來重復(fù)調(diào)用 requestAnimationFrame 函數(shù),但是涉及到墻壁反彈,以及撞擊子秋,母球的移動(dòng)函數(shù)的參數(shù)會(huì)復(fù)雜一點(diǎn)。
母球移動(dòng)的速度和距離,是通過i這個(gè)變量來控制的,這個(gè)函數(shù)每調(diào)用一次,i 會(huì)遞減。x 和 y 這兩個(gè)參數(shù)會(huì)接收一個(gè) -1 到 1 之間的值,起到一個(gè)方向系數(shù)的效果,通過參數(shù)把球桿的撞擊方向傳遞進(jìn)來。碰到邊界之后,就把對(duì)應(yīng)的系數(shù)取負(fù),然后用新系數(shù)執(zhí)行移動(dòng)函數(shù),就能起到反彈的效果了。
5、母球撞擊子球移動(dòng)
這是最麻煩的一步,撞擊后兩個(gè)球的運(yùn)動(dòng)軌跡都會(huì)發(fā)生變化。只考慮最普通的撞擊,子球的運(yùn)動(dòng)方向應(yīng)該是撞擊點(diǎn)與子球球心這條直線的方向,這個(gè)比較好計(jì)算。母球的撞擊后的方向應(yīng)該是以撞擊點(diǎn)的那條切線進(jìn)行反彈,三角函數(shù)幾乎忘光了,這個(gè)我也不知道怎么計(jì)算了,所以用了個(gè)簡(jiǎn)易的算法,就和撞墻壁一樣直接反彈,這樣會(huì)導(dǎo)致某些角度下,母球撞擊之后的方向不正常。
把這個(gè)撞擊判斷加到母球移動(dòng)的函數(shù)里面,然后再補(bǔ)充一個(gè)子球的移動(dòng)函數(shù),整個(gè)代碼就寫完了
總結(jié)
這個(gè)小游戲?qū)崿F(xiàn)的并不完美,因?yàn)橛玫搅颂嗟倪f歸,很多細(xì)節(jié)方面不好控制,球的運(yùn)動(dòng)軌跡也很難計(jì)算,在某些角度下會(huì)出現(xiàn)BUG。球雖然是圓的,但是它的盒子是正方形,所以撞擊有的時(shí)候會(huì)看著很奇怪。移動(dòng)的函數(shù)寫的也有缺陷,它不能復(fù)用,如果想添加多個(gè)球,函數(shù)就得改。
這個(gè)破產(chǎn)版的臺(tái)球主要就是寫著玩一玩,嘗試了一下JS動(dòng)畫的實(shí)現(xiàn) , 不喜勿噴。