表面

应用表面

在正常绘制事件中,GameMaker 实际上并不直接绘制到屏幕,而是绘制到称为 应用程序表面表面

该表面基本上是一个空白的 " 画布",可以在需要时在绘制到屏幕之前对其进行操作,并且在大多数情况下,GameMaker 会为您处理此操作 (尽管您也可以在着色器、缩放和缩放代码中自行操作它) 许多其他事情 - 下面给出了更多详细信息)。

定制表面

除了应用程序表面之外,您还可以创建自己的表面并使用它们在游戏中创建令人惊叹或微妙的特效。

例如,您可以使用表面 " 捕获 " 实例,然后将其销毁,通过这种方式,您可以创建贴花效果,其中实例的精灵显示在表面上,就好像它仍然存在一样,允许诸如碎片、血液等,没有任何实际的处理开销。

您可以使用表面做的另一件事是将它们用作要操纵的纹理,或 " 动态 " 创建精灵,或创建复杂的叠加层。事实上,表面的用途是无穷无尽的!

使用表面

表面的基本用途如下:

surf = -1;

if (!surface_exists(surf))
{
    surf = surface_create(960, 540);
}

surface_set_target(surf);

draw_clear_alpha(c_black, 0);
draw_sprite(spr_icon, 0, 48, 48);

surface_reset_target();

draw_surface(surf, 0, 0);

surface_free(surf);

表面规则

普通表面非常易于使用,但使用它们时需要遵循一些基本规则:

注意 对于精灵或其他视觉资源,这种情况似乎不会发生 (但实际上会发生!),因为它们也存储在常规内存 (RAM) 中,并且当它们从纹理内存 (VRAM) 中删除时当游戏重新获得焦点时,它们会立即从常规记忆中恢复。

if (view_current == 0)
{
    surface_set_target(surf);
    with (obj_Effect)
    {
        var _vx = camera_get_view_x(view_camera[1]);
        var _vy = camera_get_view_y(view_camera[1]);
        draw_sprite(sprite_index, image_index, x - _vx, y - _vy);
    }
    surface_reset_target();
}
else
{
    draw_surface(surf, 0, 0);
}

注意 这不适用于 应用程序界面 ,仅适用于用户创建的界面。

需要注意的一件事是,如果您需要将整个显示绘制到表面 (包括图块、背景等),您可以简单地访问应用程序表面本身 (有关更多详细信息,请参阅下文),或者您可以使用以下命令将表面分配给视口:变量 view_surface_id[0..7] 与此一样,该视口中的所有可见内容都将绘制到相应的表面。

功能参考

以下函数用于处理表面(这些函数专用于创建和操作表面,但要将它们实际绘制到屏幕,应使用下面可以找到的特定绘制函数):

绘制表面具有以下函数:

注意 在处理表面时,由于表面存储在纹理内存中,因此它们可能随时不再存在。在直接引用表面之前,您应该 始终 使用 surface_exists 检查表面是否存在。

最后,您有两个用于在缓冲区中存储和检索表面的函数:

应用程序表面事件顺序

如上所述,GameMaker 实际上并不将大多数内容直接渲染到屏幕上,而是将它们渲染到 应用程序界面 。这本质上是一个表面 - 就像您可以使用表面函数自己制作的任何表面一样 - 因此它可以被操纵、绘制、发送到着色器等。基本上,您通常对您创建的表面执行的任何操作都可以也可应用于应用表面。

注意 您对应用程序界面唯一 不能 做的就是释放它。它始终存在,尽管访问它的句柄可能会改变。

当您运行游戏时,系统会在您进入的每个新房间中首次调用 绘制事件 时创建此表面,这意味着在此之前不会绘制任何内容。不过,您仍然可以在 创建事件 或任何其他事件中获取应用表面位置并调整其大小,而不会出现任何错误,并且使用的值将与创建表面时相关。创建和绘制应用程序表面的实际事件顺序如下:

使用此表面意味着您可以使用着色器轻松创建令人难以置信的过渡,或者将屏幕包裹在3D形状周围,或者简单地将低分辨率游戏缩放到任何分辨率屏幕...可能性是无穷的!

要访问此表面,您需要使用内置全局变量 application_surface,该变量在以下页面中进行了说明:

 

您还拥有一些专为与应用程序界面一起使用而设计的功能: