完美像素相机

原文地址:GameMaker: Smooth pixel-perfect camera
原作者:Yellowafterlife

这是一个迷你教程,主要是介绍在 GameMaker 中实现一个可以完美匹配亚像素(sub-pixel)位移的相机系统!

思路

假设你现在做了一个像素风的游戏

当相机移动时,你可能会发现这个移动并不顺滑——尤其是当移动速度小于 1 像素每帧时,或是相机移动带有加减速等

(毕竟,你画面的最小单位就是 1 个像素了)

一个常见的解决方案是增加 application_surface 的尺寸来匹配输出分辨率

这么做可行,但也会带来一些新的问题,尤其在画面旋转、缩放、错位或其它一些像素匹配失真的问题上(可以看到画面中旋转的方块变得不够像素化了)。当然,针对不同视觉风格的游戏,以及你个人的品位好恶而言,这些代价有时候是可以接受的,而有的时候则显得无法忍受。

而我的解决方案是将相机的尺寸在高度和宽度上各增加 1 像素,确保相机坐标可以进行四舍五入的换算,然后在把相机表面绘制到画面上时进行差值偏移。

这样依赖就可以实现一个丝般顺滑的可移动亚像素相机了!

代码

我在 GitHub 上发布了完整的项目示例,这里我简单介绍一下思路:
我们将渲染一个视图到一个新的表面(surface)上。
虽然我们也可以直接绘制到 application_surface 上,但是调整这个表面尺寸会对长宽比和其它一些计算产生副作用,因此尽量避免这么做。

create 事件

既然 application_surface 会被我们自定义的表面所覆盖从而不可见,那我们不妨直接禁用它,我们也会在这里调整视图尺寸

application_surface_enable(false);
// game_width, game_height的值基于你的游戏分辨率 
game_width = camera_get_view_width(view_camera[0]);
game_height = camera_get_view_height(view_camera[0]);
// 在GMS1里使用set view_wview 和 view_hview 函数来替代
camera_set_view_size(view_camera[0], game_width + 1, game_height + 1);
display_set_gui_size(game_width, game_height);
view_surf = -1;

End Step 事件

把视图本身约束在整数坐标中,防止随着视图移动而出现小数坐标从而导致画面抖动。
我们也会在这里确保表面绑定到视图上

// 在GMS1里用 set view_xview 和 view_yview 来代替
camera_set_view_pos(view_camera[0], floor(x), floor(y));
if (!surface_exists(view_surf)) {
    view_surf = surface_create(game_width + 1, game_height + 1);
}
view_surface_id[0] = view_surf;

(相机会标记视图的左上角)

Draw GUI Begin 事件

我们根据视图坐标绘制一个屏幕大小的表面

if (surface_exists(view_surf)) {
    draw_surface_part(view_surf, frac(x), frac(y), game_width, game_height, 0, 0);
    // 或者 draw_surface(view_surf, -frac(x), -frac(y));
}

Cleanup 事件

最后,当我们不再使用时移除表面

if (surface_exists(view_surf)) {
    surface_free(view_surf);
    view_surf = -1;
}

在 GMS1 中,你应该在 Destroy 或 RoomEnd 事件中执行这个操作。

以上。

2021-04-28 15:14
Comments
Write a Comment