Hilo开发H5小游戏踩坑笔记
第一次開(kāi)發(fā)小游戲,用的是Hilo框架。由于項(xiàng)目開(kāi)發(fā)時(shí)間比較緊張,對(duì)游戲和CANVAS都沒(méi)有了解過(guò)。代碼雖然寫(xiě)的很爛,但是還是記錄下踩過(guò)的坑吧!本文為碎碎念模式,并不深入,寫(xiě)錯(cuò)的地方希望多多指點(diǎn)。
一、CANVAS橫屏適配處理
游戲是微信內(nèi)的一款橫屏游戲。如果強(qiáng)制橫屏,提示用戶去控制橫豎屏開(kāi)關(guān)并不友好。
解決方案,游戲場(chǎng)景做成如下圖紫色部分結(jié)構(gòu),游戲?qū)捀吆褪謾C(jī)屏幕調(diào)換。如果手機(jī)為豎屏,那么將游戲旋轉(zhuǎn)90°即可。
注:所述【橫屏】為用戶打開(kāi)了允許橫屏的開(kāi)關(guān)并橫屏,真正的橫屏。
代碼如下所示:
let width = document.documentElement.clientWidth; let height = document.documentElement.clientHeight; let box = document.getElementsByTagName('canvas'); let style = ''; // 豎屏 if (width < height) {style += `width:${height}px;`;style += `height:${width}px;`;style += '-webkit-transform: rotate(90deg); transform: rotate(90deg);';// 注意旋轉(zhuǎn)中點(diǎn)的處理style += `-webkit-transform-origin: ${width / 2}px ${width / 2}px;`;style += `transform-origin: ${width / 2}px ${width / 2}px;`; }if (box.length) {box[0].style.cssText = style; } 復(fù)制代碼當(dāng)用戶開(kāi)啟了橫屏開(kāi)關(guān),如果用戶橫屏,那就將游戲場(chǎng)景旋轉(zhuǎn)0°即可,也就是恢復(fù)最初的樣子。如下:
// 橫屏 if (width > height) {style += `width:${width}px;`; // 注意旋轉(zhuǎn)后的寬高切換style += `height:${height}px;`;style += '-webkit-transform: rotate(0); transform: rotate(0);';style += '-webkit-transform-origin: 0 0;';style += 'transform-origin: 0 0;'; }if (box.length) {box[0].style.cssText = style; } 復(fù)制代碼橫屏沒(méi)想象那么順利,我們的游戲是在微信場(chǎng)景。當(dāng)用戶開(kāi)啟橫屏開(kāi)關(guān)并橫屏后,微信內(nèi)置瀏覽器頭也會(huì)占一大部分區(qū)域。這樣我們的游戲場(chǎng)景旋轉(zhuǎn)后明顯是顯示不全的。
解決方案就是利用Hilo的api resize下舞臺(tái)
// 解決微信橫屏瀏覽器頭部 導(dǎo)致高度變化的問(wèn)題 this.stage.resize(height, width, true); 復(fù)制代碼最后有幾個(gè)注意點(diǎn):
1、注意旋轉(zhuǎn)過(guò)程中的寬高切換2、注意單位適配問(wèn)題3、注意微信瀏覽器頭,就因?yàn)檫@個(gè)頭的變化。整個(gè)游戲都需要處理,所以還是盡量不要自己處理。。。 復(fù)制代碼參考文章
二、點(diǎn)擊事件失效
如下圖所示,游戲結(jié)束場(chǎng)景的2個(gè)按鈕。
左側(cè)旋轉(zhuǎn)90°后變成右側(cè)橫屏,但是豎屏下的橫屏(也就是旋轉(zhuǎn)90°得來(lái)的)【再來(lái)一次】按鈕點(diǎn)擊事件會(huì)失效,但是點(diǎn)擊紅色區(qū)域(沒(méi)有按鈕,大致繪制并不精準(zhǔn))部分這個(gè)時(shí)間會(huì)被觸發(fā)。
而用戶橫屏(開(kāi)啟了橫屏開(kāi)關(guān),自然橫屏)【再來(lái)一次】按鈕點(diǎn)擊事件不會(huì)失效。
繪制時(shí)坐標(biāo)以游戲場(chǎng)景左上角為(0,0),而旋轉(zhuǎn)90°后坐標(biāo)以游戲場(chǎng)景左下角為(0,0)。因?yàn)樾D(zhuǎn)90°后游戲場(chǎng)景左下角變成了視覺(jué)上的左上角。因此豎屏下的橫屏點(diǎn)擊紅色區(qū)域生效就是因?yàn)?#xff0c;Hilo的點(diǎn)擊事件是綁定在元素繪制時(shí)坐標(biāo)區(qū)域上(猜測(cè),沒(méi)有看源碼)。旋轉(zhuǎn)后,按鈕的點(diǎn)擊事件生效區(qū)間就變成了根據(jù)繪制的x、y也就是紅色區(qū)域。
那么如何解決這個(gè)問(wèn)題,如上圖所示,旋轉(zhuǎn)后的x、y如圖中藍(lán)色字所示。可以算出
// 再玩一次按鈕 const start = this.gameOverScene.getChildById('start'); // 再玩一次按鈕 新的x = 游戲畫(huà)布寬度 - 繪制的y - 按鈕的高度 const startNewX = this.width - start.y - start.height ; // 再玩一次按鈕 新的y = 繪制的x const startNewY = start.x; // 監(jiān)聽(tīng)舞臺(tái)點(diǎn)擊事件 this.stage.on(Hilo.event.POINTER_START, (e) => {// 利用新的x、y 和按鈕自身的高度和寬度 判斷是否點(diǎn)擊在按鈕區(qū)域if ((e.stageX > startNewX && e.stageX < startNewX + start.height) &&(e.stageY > startNewY && e.stageY < startNewY + start.width)) {// 在玩一次邏輯處理} )}; 復(fù)制代碼【再玩一次】按鈕點(diǎn)擊事件解決了,但是事情沒(méi)有那么簡(jiǎn)單。
給另一個(gè)【分享】按鈕加上事件,what?無(wú)論橫屏還是豎屏點(diǎn)擊事件都不生效。至少【再玩一次】按鈕事件還是生效的,只是不準(zhǔn)罷了。
原因,觀察上述圖。【分享】按鈕在初始化的過(guò)程中是在游戲畫(huà)布右側(cè),也就是手機(jī)屏幕外部。經(jīng)過(guò)測(cè)試發(fā)現(xiàn),發(fā)現(xiàn)繪制時(shí)在手機(jī)屏幕外的區(qū)域點(diǎn)擊事件都不會(huì)生效。解決方法如【再玩一次】,無(wú)論橫屏還是豎屏都計(jì)算坐標(biāo)判斷。
三、音樂(lè)播放兼容
Hilo的HTMLAudio聲音播放模塊,官方文檔表示【使用限制:iOS平臺(tái)需用戶事件觸發(fā)才能播放,很多Android瀏覽器僅能同時(shí)播放一個(gè)音頻。】但是目前使用來(lái)看,瀏覽器測(cè)試OK,絕大部分手機(jī)都不能正常播放。解決方案,采用DOM的audio,但是同樣iOS平臺(tái)需用戶事件觸發(fā)才能播放。因此最終的解決方案就是進(jìn)入游戲之前或者某個(gè)合適的環(huán)節(jié)獲取所有的音樂(lè),先播放再暫停。用戶不會(huì)感知,可以完美解決。如下:
// html <audio id="audio" src="xxx.mp3" preload="auto"></audio> // dom為獲取 const dom = document.getElementById('audio'); dom.play(); dom.pause(); 復(fù)制代碼四、部分機(jī)型游戲場(chǎng)景顯示不全
游戲中可能有某些元素是經(jīng)常復(fù)用的,因此會(huì)單獨(dú)切出來(lái)。如下圖左側(cè)
如上圖右側(cè)所示效果,最開(kāi)始的實(shí)現(xiàn)方式如下。在初始化的時(shí)候就將公用元素Y軸截?cái)嗾故?#xff0c;這個(gè)效果看似OK,但是在測(cè)試階段發(fā)現(xiàn)某些iPhone手機(jī)不能顯示這2個(gè)元素。
new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [0, 100, 50, 300],y: 0, }); new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect:[0, 150, 50, 300],y: 0, });復(fù)制代碼查看Hilo源碼繪制圖片是用CanvasRenderingContext2D.drawImage方法。
CanvasRenderingContext2D.drawImage() 是瀏覽器原生提供的在 canvas 上繪制圖片的方法。
其有以下三種參數(shù)形式(詳細(xì)用法說(shuō)明及演示可見(jiàn) MDN):
| sx, sy | 源圖像的選擇區(qū)域的偏移量 |
| sWidth, sHeight | 源圖像的選擇區(qū)域的寬高 |
| dx, dy | 目標(biāo)canvas的選擇區(qū)域的偏移量 |
| dWidth, dHeight | 目標(biāo)canvas的選擇區(qū)域的寬高 |
注:
而我們的元素在部分機(jī)型上不能顯示就是因?yàn)橛|發(fā)了第3點(diǎn)坑。修復(fù)代碼如下,通過(guò)完整的繪制圖片,然后通過(guò)元素的坐標(biāo)來(lái)達(dá)到目標(biāo)樣式。
new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [0, 0, 50, 300],y: -100, }); new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect:[0, 0, 50, 300],y: -150, }); 復(fù)制代碼參考文章
五、碰撞檢測(cè),撞擊坐標(biāo)不準(zhǔn)確
用Hilo最開(kāi)始開(kāi)心的一點(diǎn)也是碰撞檢測(cè)不需要自己寫(xiě),hitTestObject檢測(cè)object參數(shù)指定的對(duì)象是否與其相交。因此撞擊區(qū)域可以書(shū)寫(xiě)撞擊坐標(biāo)。
// 給如下圖中的一個(gè)多邊形實(shí)行撞擊坐標(biāo) new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [0, 0, 50, 300],y: -100,boundsArea: [// 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo),圖中紅點(diǎn)的坐標(biāo),從左到右{x: 0, y: 0},{x: 0, y: 100},{x: 100, y: 100},{x: 100, y: 200},{x: 200, y: 200},{x: 200, y: 100},{x: 300, y: 100},{x: 300, y: 0},] }); 復(fù)制代碼理想中應(yīng)該是如下黃色區(qū)域構(gòu)成的碰撞檢測(cè)區(qū)域。
而實(shí)際卻是如下黃色區(qū)域,空氣墻???用戶反饋為什么沒(méi)撞到就死翹翹了。(看了Hilo碰撞檢測(cè)這部分的實(shí)現(xiàn)源碼,沒(méi)太看懂多邊形的處理。。)
解決辦法,類(lèi)似雪碧圖使用,恩...主要是懶得切圖
new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [0, 0, 100, 100],y: 0,boundsArea: [// 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo),圖中紅點(diǎn)的坐標(biāo),從左到右{x: 0, y: 0},{x: 0, y: 100},{x: 100, y: 100},{x: 100, y: 0},] }); new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [100, 0, 100, 200],y: 0,boundsArea: [// 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo),圖中紅點(diǎn)的坐標(biāo),從左到右{x: 0, y: 0},{x: 0, y: 200},{x: 100, y: 200},{x: 100, y: 0},] }); new Hilo.Bitmap({// 繪制的圖片image: 'imgurl', // 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo)rect: [200, 0, 100, 100],y: 0,boundsArea: [// 測(cè)試坐標(biāo),非精準(zhǔn)坐標(biāo),圖中紅點(diǎn)的坐標(biāo),從左到右{x: 0, y: 0},{x: 0, y: 100},{x: 100, y: 100},{x: 100, y: 0},] }); 復(fù)制代碼其實(shí)就是將1張圖裁剪成了3張圖,裁剪出來(lái)的區(qū)域撞擊坐標(biāo)都中規(guī)中矩。過(guò)于不規(guī)則的圖形只能盡量寫(xiě)的粗糙一些。
這么輕松就解決了嗎???當(dāng)然NO!!!回顧下第四點(diǎn),部分機(jī)型游戲場(chǎng)景顯示不全。上面裁剪的3張圖里,最后一張圖又觸發(fā)了safari的bug。o(╥﹏╥)o,所以還是乖乖切圖,或者雪碧圖留一點(diǎn)安全區(qū)域吧!
而且后來(lái)我才知道雪碧圖對(duì)于CANVAS來(lái)說(shuō)更耗性能,還不如多切點(diǎn)圖呢~
轉(zhuǎn)載于:https://juejin.im/post/5ba0dea5f265da0aa3591f8d
總結(jié)
以上是生活随笔為你收集整理的Hilo开发H5小游戏踩坑笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 敏捷世界中的合规性
- 下一篇: 03-高级选择器,属性选择器,伪类选择器