Hilo开发H5小游戏踩坑笔记

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

一、CANVAS横屏适配处理

游戏是微信内的一款横屏游戏。如果强制横屏,提示用户去控制横竖屏开关并不友好。

解决方案,游戏场景做成如下图紫色部分结构,游戏宽高和手机屏幕调换。如果手机为竖屏,那么将游戏旋转90°即可。

注:所述【横屏】为用户打开了允许横屏的开关并横屏,真正的横屏。

竖屏

代码如下所示:

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°即可,也就是恢复最初的样子。如下:

横屏
// 横屏
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;
}

横屏没想象那么顺利,我们的游戏是在微信场景。当用户开启横屏开关并横屏后,微信内置浏览器头也会占一大部分区域。这样我们的游戏场景旋转后明显是显示不全的。

image

解决方案就是利用Hilo的api resize下舞台

// 解决微信横屏浏览器头部 导致高度变化的问题
this.stage.resize(height, width, true);   

最后有几个注意点:

1、注意旋转过程中的宽高切换

2、注意单位适配问题

3、注意微信浏览器头,就因为这个头的变化。整个游戏都需要处理,所以还是尽量不要自己处理。。。

参考文章

二、点击事件失效

如下图所示,游戏结束场景的2个按钮。

左侧旋转90°后变成右侧横屏,但是竖屏下的横屏(也就是旋转90°得来的)【再来一次】按钮点击事件会失效,但是点击红色区域(没有按钮,大致绘制并不精准)部分这个时间会被触发。

而用户横屏(开启了横屏开关,自然横屏)【再来一次】按钮点击事件不会失效。

image

绘制时坐标以游戏场景左上角为(0,0),而旋转90°后坐标以游戏场景左下角为(0,0)。因为旋转90°后游戏场景左下角变成了视觉上的左上角。因此竖屏下的横屏点击红色区域生效就是因为,Hilo的点击事件是绑定在元素绘制时坐标区域上(猜测,没有看源码)。旋转后,按钮的点击事件生效区间就变成了根据绘制的x、y也就是红色区域。

image

那么如何解决这个问题,如上图所示,旋转后的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();

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

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

image

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

参考文章

五、碰撞检测,撞击坐标不准确

用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},
    ]
});

理想中应该是如下黄色区域构成的碰撞检测区域。

image

而实际却是如下黄色区域,空气墙???用户反馈为什么没撞到就死翘翘了。(看了Hilo碰撞检测这部分的实现源码,没太看懂多边形的处理。。)

image

解决办法,类似雪碧图使用,恩...主要是懒得切图

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345