第一次開發小遊戲,用的是Hilo框架。因爲項目開發時間比較緊張,對遊戲和CANVAS都沒有了解過。代碼雖然寫的很爛,可是仍是記錄下踩過的坑吧!本文爲碎碎念模式,並不深刻,寫錯的地方但願多多指點。javascript
遊戲是微信內的一款橫屏遊戲。若是強制橫屏,提示用戶去控制橫豎屏開關並不友好。css
解決方案,遊戲場景作成以下圖紫色部分結構,遊戲寬高和手機屏幕調換。若是手機爲豎屏,那麼將遊戲旋轉90°便可。html
注:所述【橫屏】爲用戶打開了容許橫屏的開關並橫屏,真正的橫屏。html5
代碼以下所示:java
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);';
// 注意旋轉中點的處理
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;
}
複製代碼
當用戶開啓了橫屏開關,若是用戶橫屏,那就將遊戲場景旋轉0°便可,也就是恢復最初的樣子。以下:web
// 橫屏
if (width > height) {
style += `width:${width}px;`; // 注意旋轉後的寬高切換
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;
}
複製代碼
橫屏沒想象那麼順利,咱們的遊戲是在微信場景。當用戶開啓橫屏開關並橫屏後,微信內置瀏覽器頭也會佔一大部分區域。這樣咱們的遊戲場景旋轉後明顯是顯示不全的。canvas
解決方案就是利用Hilo的api resize下舞臺api
// 解決微信橫屏瀏覽器頭部 致使高度變化的問題
this.stage.resize(height, width, true);
複製代碼
最後有幾個注意點:瀏覽器
1、注意旋轉過程當中的寬高切換
2、注意單位適配問題
3、注意微信瀏覽器頭,就由於這個頭的變化。整個遊戲都須要處理,因此仍是儘可能不要本身處理。。。
複製代碼
參考文章安全
以下圖所示,遊戲結束場景的2個按鈕。
左側旋轉90°後變成右側橫屏,可是豎屏下的橫屏(也就是旋轉90°得來的)【再來一次】按鈕點擊事件會失效,可是點擊紅色區域(沒有按鈕,大體繪製並不精準)部分這個時間會被觸發。
而用戶橫屏(開啓了橫屏開關,天然橫屏)【再來一次】按鈕點擊事件不會失效。
繪製時座標以遊戲場景左上角爲(0,0),而旋轉90°後坐標以遊戲場景左下角爲(0,0)。由於旋轉90°後遊戲場景左下角變成了視覺上的左上角。所以豎屏下的橫屏點擊紅色區域生效就是由於,Hilo的點擊事件是綁定在元素繪製時座標區域上(猜想,沒有看源碼)。旋轉後,按鈕的點擊事件生效區間就變成了根據繪製的x、y也就是紅色區域。
那麼如何解決這個問題,如上圖所示,旋轉後的x、y如圖中藍色字所示。能夠算出
// 再玩一次按鈕
const start = this.gameOverScene.getChildById('start');
// 再玩一次按鈕 新的x = 遊戲畫布寬度 - 繪製的y - 按鈕的高度
const startNewX = this.width - start.y - start.height ;
// 再玩一次按鈕 新的y = 繪製的x
const startNewY = start.x;
// 監聽舞臺點擊事件
this.stage.on(Hilo.event.POINTER_START, (e) => {
// 利用新的x、y 和按鈕自身的高度和寬度 判斷是否點擊在按鈕區域
if ((e.stageX > startNewX && e.stageX < startNewX + start.height) &&
(e.stageY > startNewY && e.stageY < startNewY + start.width)) {
// 在玩一次邏輯處理
}
)};
複製代碼
【再玩一次】按鈕點擊事件解決了,可是事情沒有那麼簡單。
給另外一個【分享】按鈕加上事件,what?不管橫屏仍是豎屏點擊事件都不生效。至少【再玩一次】按鈕事件仍是生效的,只是不許罷了。
緣由,觀察上述圖。【分享】按鈕在初始化的過程當中是在遊戲畫布右側,也就是手機屏幕外部。通過測試發現,發現繪製時在手機屏幕外的區域點擊事件都不會生效。解決方法如【再玩一次】,不管橫屏仍是豎屏都計算座標判斷。
Hilo的HTMLAudio聲音播放模塊,官方文檔表示【使用限制:iOS平臺需用戶事件觸發才能播放,不少Android瀏覽器僅能同時播放一個音頻。】可是目前使用來看,瀏覽器測試OK,絕大部分手機都不能正常播放。解決方案,採用DOM的audio,可是一樣iOS平臺需用戶事件觸發才能播放。所以最終的解決方案就是進入遊戲以前或者某個合適的環節獲取全部的音樂,先播放再暫停。用戶不會感知,能夠完美解決。以下:
// html
<audio id="audio" src="xxx.mp3" preload="auto"></audio>
// dom爲獲取
const dom = document.getElementById('audio');
dom.play();
dom.pause();
複製代碼
遊戲中可能有某些元素是常常複用的,所以會單獨切出來。以下圖左側
如上圖右側所示效果,最開始的實現方式以下。在初始化的時候就將公用元素Y軸截斷展現,這個效果看似OK,可是在測試階段發現某些iPhone手機不能顯示這2個元素。
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [0, 100, 50, 300],
y: 0,
});
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect:[0, 150, 50, 300],
y: 0,
});
複製代碼
查看Hilo源碼繪製圖片是用CanvasRenderingContext2D.drawImage
方法。
CanvasRenderingContext2D.drawImage()
是瀏覽器原生提供的在 canvas 上繪製圖片的方法。
其有如下三種參數形式(詳細用法說明及演示可見 MDN):
ctx.drawImage(image, dx, dy);
ctx.drawImage(image, dx, dy, dWidth, dHeight);
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
複製代碼
參數 | 意義 |
---|---|
sx, sy | 源圖像的選擇區域的偏移量 |
sWidth, sHeight | 源圖像的選擇區域的寬高 |
dx, dy | 目標canvas的選擇區域的偏移量 |
dWidth, dHeight | 目標canvas的選擇區域的寬高 |
注:
sx + sWidth
和 sy + sHeight
不超過源圖像的寬高,不然 drawImage()
函數不會繪製任何圖像。(未在更高版本的 Safari 上測試)而咱們的元素在部分機型上不能顯示就是由於觸發了第3點坑。修復代碼以下,經過完整的繪製圖片,而後經過元素的座標來達到目標樣式。
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [0, 0, 50, 300],
y: -100,
});
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect:[0, 0, 50, 300],
y: -150,
});
複製代碼
用Hilo最開始開心的一點也是碰撞檢測不須要本身寫,hitTestObject
檢測object參數指定的對象是否與其相交。所以撞擊區域能夠書寫撞擊座標。
// 給以下圖中的一個多邊形實行撞擊座標
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [0, 0, 50, 300],
y: -100,
boundsArea: [
// 測試座標,非精準座標,圖中紅點的座標,從左到右
{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},
]
});
複製代碼
理想中應該是以下黃色區域構成的碰撞檢測區域。
而實際倒是以下黃色區域,空氣牆???用戶反饋爲何沒撞到就死翹翹了。(看了Hilo碰撞檢測這部分的實現源碼,沒太看懂多邊形的處理。。)
解決辦法,相似雪碧圖使用,恩...主要是懶得切圖
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [0, 0, 100, 100],
y: 0,
boundsArea: [
// 測試座標,非精準座標,圖中紅點的座標,從左到右
{x: 0, y: 0},
{x: 0, y: 100},
{x: 100, y: 100},
{x: 100, y: 0},
]
});
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [100, 0, 100, 200],
y: 0,
boundsArea: [
// 測試座標,非精準座標,圖中紅點的座標,從左到右
{x: 0, y: 0},
{x: 0, y: 200},
{x: 100, y: 200},
{x: 100, y: 0},
]
});
new Hilo.Bitmap({
// 繪製的圖片
image: 'imgurl',
// 測試座標,非精準座標
rect: [200, 0, 100, 100],
y: 0,
boundsArea: [
// 測試座標,非精準座標,圖中紅點的座標,從左到右
{x: 0, y: 0},
{x: 0, y: 100},
{x: 100, y: 100},
{x: 100, y: 0},
]
});
複製代碼
其實就是將1張圖裁剪成了3張圖,裁剪出來的區域撞擊座標都中規中矩。過於不規則的圖形只能儘可能寫的粗糙一些。
這麼輕鬆就解決了嗎???固然NO!!!回顧下第四點,部分機型遊戲場景顯示不全。上面裁剪的3張圖裏,最後一張圖又觸發了safari的bug。o(╥﹏╥)o,因此仍是乖乖切圖,或者雪碧圖留一點安全區域吧!
並且後來我才知道雪碧圖對於CANVAS來講更耗性能,還不如多切點圖呢~