我试图根据屏幕尺寸动态扩展我的画布游戏。我理解如何基于屏幕大小来调整画布大小,但我也希望调整内容的大小。基本上我希望游戏在每台设备上看起来都一样。我目前的问题是当有4k屏幕的人玩游戏时,他们可以很容易地看到整个地图。当有人拥有一个非常小的屏幕时,他们几乎看不到任何东西。有一种简单有效的方法吗?我试图做以下事情:
var maxWidth = 1920;
var maxHeight = 1080;
...
function resize() {
c.width = screenWidth = window.innerWidth;
c.height = screenHeight = window.innerHeight;
widthToHeight = screenWidth / screenHeight; // ASPECT RATIO
var scalerAmnt = (maxWidth + maxHeight )
/ (screenWidth + screenHeight);
context.scale(scalerAmnt, scalerAmnt);
}
如果我像这样缩放画布,则会产生不希望的结果。它偏离中心,而且太大了。如您所见,我已设置最大宽度和高度。基本上我试图让游戏在每台设备上看起来都像在具有该分辨率的机器上一样。
现场演示:www.vertix.io
答案 0 :(得分:8)
你将面临一些问题。
如果未设置ctx.imageSmoothingEnabled = false
,高分辨率显示将显示模糊,如果未设置ctx.imageSmoothingEnabled = true
,低分辨率显示将显示混叠效果。
最好是不要超过最大分辨率。这是任意的,我的选择是使用大多数人使用的屏幕分辨率。 Screen stats的一个示例有许多站点提供此信息。选择最近的人报告您的人口统计目标。
对于大于此值的显示,不增加分辨率只会增加DOM元素的大小。
canvas.width
和canvas.height
设置画布的大小。 canvas.style.width
和canvas.style.height
设置了分辨率。
对于分辨率较低的显示,会降低画布分辨率以适合屏幕分辨率。没有必要为设备提供额外的像素来渲染不会被看到。我个人会重新渲染所有图形,以便在加载图像时为低分辨率显示更正res。同样,这是为了阻止设备渲染比所需更多的像素(移动设备无法处理太多),并且因为平滑方法有很多不足之处(即完全错误)请参阅此视频解释原因{{3} }
小心降低分辨率。如果你有一个100by100像素的图像,需要将它减少到93by93,它看起来并不好。仔细选择每个渲染元素的图形尺寸,以便尽可能减少最常见的分辨率。
同样允许在比赛场地大小的一些摆动空间,他们不必都是完全相同的大小。
更好的是将图形存储为基于矢量的图像(例如SVG或用于矢量渲染的自定义格式直接指向画布),然后在加载时以正确的分辨率在设备上渲染图像。
因此,你留下了方面。你无能为力,有些屏幕会比其他屏幕显示更多的游戏场地。你必须决定在宽度和高度上可以播放的最小尺寸的场地是什么,并确保它不会在那之下。
但是,尽管如此,大部分工作已经完成,你无法回头重做所有工作,所以这里是简单的解决方案。
var nativeWidth = 1024; // the resolution the games is designed to look best in
var nativeHeight = 768;
// the resolution of the device that is being used to play
var deviceWidth = window.innerWidth; // please check for browser compatibility
var deviceHeight = window.innerHeight;
您有两种缩放选项。缩放以适合或缩放以填充。
// A: This will ensure that the scale fills the device but will crop
// some of the top and bottom, or left and right of the play field.
// use the max scale.
var scaleFillNative = Math.max(deviceWidth / nativeWidth, deviceHeight / nativeHeight);
// B: this will ensure that all screens will see all of the native playscreen size
// but some displays will have extra playfield on the sides or top and bottom.
// use the min scale
var scaleFitNative = Math.min(deviceWidth / nativeWidth, deviceHeight / nativeHeight);
将画布分辨率和大小设置为
canvas.style.width = deviceWidth + "px";
canvas.style.height = deviceHeight + "px";
canvas.width = deviceWidth;
canvas.height = deviceHeight;
现在您需要设置渲染比例
// ctx is the canvas 2d context
ctx.setTransform(
scaleFitNative,0, // or use scaleFillNative
0,scaleFitNative,
Math.floor(deviceWidth/2),
Math.floor(deviceHeight/2)
);
这已将屏幕中心设置为原点。
<强>更新强>
我的原始答案出错了。
要获得本机res左上角的偏移量是
var offSetToNativeTop = -nativeHeight/2; // incorrect
var offSetToNativeleft = -nativeWidth/2; // incorrect
应该......
var offSetToNativeTop = (-nativeHeight/2)*scaleFitNative; // correct
var offSetToNativeleft = (-nativeWidth/2)*scaleFitNative; // correct
或
var offSetToNativeTop = (-nativeHeight/2)*scaleFillNative; // correct
var offSetToNativeleft = (-nativeWidth/2)*scaleFillNative; // correct
对由此给您带来的任何不便表示歉心。
要获得设备左上角的偏移量
var offsetDeviceTop = -(deviceHeight/scaleFitNative)/2;
var offsetDeviceLeft = -(deviceWidth/scaleFitNative)/2;
获取设备的playfield显示大小
var deviceDisplayWidth = deviceWidth/scaleFitNative;
var deviceDisplayHeight = deviceHeight/scaleFitNative;
不要忘记平滑。
if(scaleFitNative < 1){
ctx.imageSmoothingEnabled = true; // turn it on for low res screens
}else{
ctx.imageSmoothingEnabled = false; // turn it off for high res screens.
}
你也可以在个别渲染项目上进行,具体取决于它的规模和个人喜好,看看它们的平滑程度,减少和平滑的扩展或不平滑的大小。
这应该可以为您提供渲染所有设备图形所需的一切
答案 1 :(得分:1)
在尝试使用Blindman67实现该方法后,我找到了一种更快更短的方法来使用CSS实现相同的结果,而不是使用修改后的drawImage()函数以不同的方式绘制每个图像。
这是一个更简单的方法,请告诉我,如果我忽略了上述方法所解决的任何问题,尽管我相信所有问题都已得到解决。
- &gt;给定画布定义为:
canvas
等于html页面中的canvas元素。
要扩展到的所需原生分辨率(如果需要,请参阅Blindman67的澄清答案)定义为:
resW, resH
设备尺寸定义为:
devW, devH
//Noting that these values usually correspond to window.innerWidth, window.innerHeight, respectively.
(1)对于填充屏幕的刻度,裁掉多余的部分:
let f = Math.max(window.innerWidth / resW, window.innerHeight / resH);
//f is the factor by which we redefine our canvas size as show in the code in the following lines:
//Change the canvas elements 'direct' width and height properties
canvas.width = Math.floor(devW / f);
canvas.height = Math.floor(devH / f);
//Change the canvas elements 'css' width and height properties to fill
// the entire page.
canvas.style.width = '100%';
canvas.style.height = '100%';
(2)为了使画布内容适合屏幕,只需简单地简化:
集:
//Changing the 'css' canvas width size, making sure the width is always fitting.
canvas.style.width = '100%';
然后:
//Making the direct canvas width and height the desired native resolution's size
canvas.width = resW;
canvas.height = resH;
现在CSS自动处理缩放而不是依赖于drawImage的复杂功能。
虽然对于游戏(画布的主要功能),如果用户调整他或她的窗口大小,由于屏幕上将出现的空间,填充的比例可能更合乎需要。另一方面,如果您使用比例填充,玩家可以获得更加身临其境的视图,没有空格或没有缩放的时候以及其他具有更大屏幕的玩家都有优势的问题。
据我所知,这已经很晚了,但在寻找解决方案的数月之后,我终于明白了。所以对于其他可能需要参考的人我想在这里保留这个答案。
非常感谢您阅读。