Hilo开发H5小游戏踩坑笔记

第一次开发小游戏,用的是Hilo框架。因为项目开发时间比较紧张,对游戏和CANVAS都没有了解过。代码虽然写的很烂,可是仍是记录下踩过的坑吧!本文为碎碎念模式,并不深刻,写错的地方但愿多多指点。javascript

1、CANVAS横屏适配处理

游戏是微信内的一款横屏游戏。若是强制横屏,提示用户去控制横竖屏开关并不友好。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、点击事件失效

以下图所示,游戏结束场景的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?不管横屏仍是竖屏点击事件都不生效。至少【再玩一次】按钮事件仍是生效的,只是不许罢了。

缘由,观察上述图。【分享】按钮在初始化的过程当中是在游戏画布右侧,也就是手机屏幕外部。通过测试发现,发现绘制时在手机屏幕外的区域点击事件都不会生效。解决方法如【再玩一次】,不管横屏仍是竖屏都计算坐标判断。

3、音乐播放兼容

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();
复制代码

4、部分机型游戏场景显示不全

游戏中可能有某些元素是常常复用的,所以会单独切出来。以下图左侧

如上图右侧所示效果,最开始的实现方式以下。在初始化的时候就将公用元素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):

  1. 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的选择区域的宽高

注:

  1. 在 Chrome 和 Firefox 下,最终的选择区域超出源图像的部分不会被绘制。
  2. 在 IE 和 Edge 下,最终的选择区域超出源图像的部分会用图像的边界像素来填充。
  3. Safari 7.1 额外要求 sx + sWidthsy + sHeight 不超过源图像的宽高,不然 drawImage() 函数不会绘制任何图像。(未在更高版本的 Safari 上测试)
  4. 在支持 canvas 的老版本的 Firefox 上,有着和 IE 等浏览器相似的对 sx, sy, sWidth, sHeight 的限制,在新版本中,这些限制已经被移除。

而咱们的元素在部分机型上不能显示就是由于触发了第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,
});
复制代码

参考文章

5、碰撞检测,撞击坐标不许确

用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来讲更耗性能,还不如多切点图呢~

相关文章
相关标签/搜索