- 2022-03-03
最近在用canvas做小游戏,在电脑上看着没有什么问题,但是一在手机上运行就发现写在canvas里面的图片很模糊,跟h5的图片有非常惨烈的对比,找了半天的解决办法…
一、原因
出现这个问题的主要原因有两个:
-
首先是canvas本身的绘图方式,比如我们需要绘制1px的线,与在网页中不同,canvas会先设定一个中线,然后在中线的左右两侧扩散0.5px,但是这个扩散出去的0.5px占不满1px,所以会用颜色的一半来填充1px,这样不仅绘制的线条变成了2px,也变得模糊了。
-
其次是因为手机上存在设备像素比,比如iphone 7屏幕宽度是375,但是物理像素为750(这也是设计图会有两倍图甚至三倍图的原因),不同型号的手机设备像素比不同,我们需要手动获取。
二、解决方法
首先,先获取设备像素比
let n = window.devicePixelRatio
然后,只需要把cnavas放大n倍绘制,然后再缩放至正常大小就可以了
<canvas :style="'width: ' + width + 'px;height: ' + height + 'px;'"
:width='width * n' :height='height * n'></canvas>
style的大小是我们实际需要的尺寸,和css一样
canvas本身需要传入width和height尺寸,这里传入n倍的宽高就可以了
另外,此时画布的大小从375变成了750,所以我们绘制图片或者计算尺寸都需要乘n,别忘了
this.context.drawImage(
img * n,
sx,
sy,
swidth,
sheight,
x * n,
y * n,
width * n,
height * n
)
三、注意
-
人物有运动的话,运动的距离也需要 * n,别忘记了
-
设备像素比需要在使用之前先获取到,使用设备像素比主要有两个场景:声明canvas的width和height属性、调用drawImage方法。
所以我一般会加一个判断,获取到设备像素比之后才开始渲染canvas元素:
<canvas v-if="n" :style="'width: ' + width + 'px;height: ' + height + 'px;'"
:width='width * n' :height='height * n'></canvas>
- 如果是全屏的canvas,还要在获取到屏幕宽度之后开始渲染,全部的是这样:
<canvas v-if="n && width"
:style="'width: ' + width + 'px;height: ' + height + 'px;'"
:width='width * n' :height='height * n'>
</canvas>
<script>
// (写在vue里面粘过来的,懂我意思就可以了;D)
this.n= window.devicePixelRatio
this.$nextTick(() => {
this.width = document.getElementById('component').clientWidth
this.height = document.getElementById('component').clientHeight
})
</script>