我是 HullQin,公众号 线下团聚游戏 的作者(欢送关注公众号,发送加微信,交个敌人),转发本文前需取得作者 HullQin 受权。我独立开发了《联机桌游合集》,是个网页,能够很不便的跟敌人联机玩斗地主、五子棋等游戏,不免费没广告。还开发了《Dice Crush》加入 Game Jam 2022。喜爱能够关注我 HullQin 噢~我有空了会分享做游戏的相干技术。
背景
canvas
是前端经常会用到的货色,尤其是对于游戏开发者、图表开发者而言。
响应式设计(网页元素可自适应各种屏幕宽度的设计)对于前端,也是十分重要的基本功之一。
前端开发者实现响应式设计的计划有多种,曾经列举在之前的文章里了:《2 行代码,让你的 UI 适配挪动端、PC 端,快来珍藏》。文中次要讲述的办法是用 width=device-width
这个 viewport 联合 min-width
实现的,这个思路挺牛逼的,因为这同样实用于 canvas。强烈推荐没看的同学看一下,这个思路真的超级实用。
什么是极致用户体验
1. 一屏展现全副 canvas
然而本文要讲的响应式 canvas,为了谋求极致的用户体验 ,提出了更严格的限度: 要求一屏能展现残缺个 canvas。
为什么要有这种限度?
尤其是针对游戏开发,不论在 PC 端、挪动端,都不心愿用户须要高低滚动来看到残缺画面。甚至很多挪动端游戏的交互是须要用户手指滑动的,这须要 canvas 监听用户滑动操作,用户就无奈通过滑动来实现页面高低滚动了,导致看不到一部分网页。
所以这个限度是齐全正当的,齐全关照到了极致用户体验。
2. canvas 比例与页面初始比例统一
要求 canvas 比例跟 页面的初始比例 保持一致,这样用户不会有空空的感觉。然而之后如果用户缩放了浏览器,要求 canvas 比例放弃不变(这其实是技术上不得不做的一种斗争)。
为什么只要求跟页面初始比例雷同
- 因为 canvas 在绘制后,要批改比例,那么外部所有元素的坐标都须要重绘,很多物理引擎计算须要从新做,对性能影响较大;
- 而且开发成本也相当高,canvas 不像 Dom,页面宽度变了后浏览器可主动计算新布局,canvas 扭转布局是须要开发者手动计算每个元素的新地位的;
- 页面初始比例确定后,大概率页面比例不会批改了。尤其是挪动端,用户简直无奈批改页面尺寸(浏览器小窗的状况并不多)。
依据以上 3 点,得出结论:动静改 canbas 比例是开发成本极高、收益很低(用户应用次数少)的,即 ROI 很低,所以没必要动静批改 canvas 比例,只须要 canvas 比例放弃页面的初始比例,就能达到很好的用户体验了。
此外,canvas 比例经常有些极限值,如果屏幕比例超出 canvas 比例极限值,应该放弃在极限值。例如画面宽高比例要求在 1:1
至1:2
,那么屏幕太宽时,就只能设置 canvas 比例为极限的 1:1
了;而屏幕太窄时,只能设置 canvas 比例为极限的1:2
。间接看例子:
- 例如屏幕太宽的场合,超过了 canvas 比例极限值,则高度塞满,宽度留白:
- 例如屏幕太窄的场合,超过了 canvas 比例极限值,则宽度塞满,高度留白:
- 例如屏幕比例在 canvas 比例的 2 个极限值之间,那么高度、宽度都塞满:
实在体验下上述成果
下面口述,你可能不太分明,我间接给你个案例,看看什么是极致用户体验:
参考我之前的文章《《合 成 大 西 瓜》重 制 版!(联 机 版 在 做 了)》,我复刻了《合成大西瓜》游戏,用 canvas 实现的,它就为了谋求极致用户体验,实现了上述 2 条规定。
体验地址: https://game.hullqin.cn/dxg
解决方案
应用 transform 的 scale
倡议不要扭转 canvas 的 width
和height
,你可能会把 canvas 外部的宽高属性和 css 宽高搞混!如下图:这 2 个红框里的属性,有着不同的作用。
咱们间接批改 transform
的scale
属性,这样是能够实现等比例缩放的,齐全不影响外部布局!
然而批改 scale
后,元素看起来变小了,它理论还是占了 width
和height
那么大,还是会呈现滚动条。最简略的解决办法:给它的父元素设置overflow: hidden
。
设置 canvas 初始比例,放弃在极限值之间
咱们间接上代码,解释在正文:
export const Height = 1408; // 要求画面高度固定,宽度随比例放大、放大
let width = 704; // 如果屏幕【太宽】,就会用这个宽度
const {innerWidth, innerHeight} = window; // 获取初始页面尺寸
if (innerHeight > innerWidth * 1.3) { // 如果初始页面尺寸不是【太宽】width = Height * innerWidth / innerHeight; // canvas 宽高比就跟初始页面宽高比保持一致
if (width < 320) width = 320; // 如果发现屏幕【太窄】,就设置一个极限最小宽度
}
export const Width = width; // 导出计算后的 canvas 最终宽度
监听 resize,动静设置 canvas 比例
接下来,就是要设置 canvas 的 scale 初始比例和动静设置比例了。
// 注:变量 canvas 是个画布的 dom element,变量 root 是 canvas 的父元素。const resetSize = () => {const { innerWidth, innerHeight} = window;
if (innerWidth / innerHeight > Width / Height) { // 如果放缩后屏幕【宽】,就用屏幕高度计算放缩
root.style.height = `${innerHeight}px`; // 高度撑满
root.style.width = `${innerHeight / Height * Width}px`;
// 设置新算进去的 scale
canvas.style.transform = `scale(${innerHeight / Height})`;
} else { // 如果放缩后屏幕【窄】,就用屏幕宽度计算放缩
root.style.width = `${innerWidth}px`; // 宽度撑满
root.style.height = `${innerWidth / Width * Height}px`;
// 设置新算进去的 scale
canvas.style.transform = `scale(${innerWidth / Width})`;
}
};
canvas.style.width = `${Width}px`;
canvas.style.height = `${Height}px`;
resetSize(); // 页面初始时,执行一次,设定 canvas 的款式
window.onresize = resetSize; // 监听 resize 事件,页面尺寸变动时,放弃宽高比、动静放缩 canvas
写在最初
我是 HullQin,公众号 线下团聚游戏 的作者(欢送关注公众号,发送加微信,交个敌人),转发本文前需取得作者 HullQin 受权。我独立开发了《联机桌游合集》,是个网页,能够很不便的跟敌人联机玩斗地主、五子棋等游戏,不免费没广告。还开发了《Dice Crush》加入 Game Jam 2022。喜爱能够关注我 HullQin 噢~我有空了会分享做游戏的相干技术。