用Surface实现转场特效(二)

原文地址:How to Make 3 Screen Transitions in GameMaker using Surfaces

欢迎回来! 这是转场特效指南的第二部分,我们将一起实现一些屏幕转场效果。 如果您不太清楚之前的准备工作,可以先去看一下第一部分

这些是我们将要实现的转场效果:

之所以使用表面(surface)来实现这些,是因为我们可以用它实现同时显示两个场景(room)画面的效果。 表面基本上就是我们可以在其上绘制内容的空白画布,会将所有绘制的内容保存起来。 然后,我们可以像访问变量一样访问它,并像绘制精灵一样将其绘制到屏幕上。

我提供了一个gmz项目文件,因此您可以下载该文件并亲自查看所有代码,希望这将有助于您将这些转场效果集成到游戏中,并帮助您学习如何在GameMaker中使用表面。

四分旋转转场:

让我们看一下我们将要尝试的第二个转场。 在此,我将不重复我们在第一个转场中所做的准备工作,而是讨论二者不一样的地方。

obj_transitionquarters:

创建(Create)事件 :

var halfheight = surface_get_height(application_surface)/ 2
var halfwidth = surface_get_width(application_surface)/ 2

spr_roomtl = sprite_create_from_surface(application_surface,0,0,Halfwidth,Halfheight,false,false,0,0);
spr_roomtr = sprite_create_from_surface(application_surface,halfwidth,0,Halfwidth,Halfheight,false,false,Halfwidth,0);
spr_roombl = sprite_create_from_surface(application_surface,halfwidth,halfheight,halfwidth,halfheight,false,false,halfwidth,halfheight);
spr_roombr = sprite_create_from_surface(application_surface,0,halfheight,halfwidth,halfheight,false,false,0,halfheight);

room_goto(room_second)//我们已经记录了旧 room的画面,因此我们可以立即转到下一个房间。 
    

与我们在第一个转场中制作 room截屏的方式相同,在此我们将创建4个图像,每个图像占据屏幕的四分之一,并且每个图像都有一个单独的原点。

之所以将其直接变成精灵,是为了让我们可以给每个四分之一画面各自不同的原点来进行旋转。

绘制(Draw)事件 :

///转场绘制 

if (currentframe > 0) {
    //给所有内容绘制淡入淡出 
    draw_set_colour(c_black)
    draw_set_alpha(1-EaseInQuad(currentframe,0,1,maxframes))
    draw_rectangle(0,0,room_width,room_height,false)
    draw_set_alpha(1)

    //将参数中传入的帧数转换为介于0到90之间的角度数字
    var rot = EaseOutCubic(currentframe,0,90,maxframes)

    draw_sprite_ext(spr_roomtl,0,0,0,1,1,rot,c_white,1)
    draw_sprite_ext(spr_roomtr,0,room_width,0,1,1,rot,c_white,1)
    draw_sprite_ext(spr_roombl,0,room_width,room_height,1,1,rot,c_white,1)
    draw_sprite_ext(spr_roombr,0,0,room_height,1,1,rot,c_white,1)

}
    

此绘制事件分为两个部分,在上半段,我只是在整个屏幕上绘制了一个黑色矩形,该矩形逐渐淡出。 在这个矩形前面,我绘制了4张旋转的图像。

由于我在创建代码时设置了原点,因此每个图像的原点设置方式都使得原点位于图像中朝向其定位方向的最远点(比如左上角的图原点在左上角,而右下角的图原点在右下角)。 因此,当我们旋转每个图像时,它会围绕其原点旋转,看起来就像绕着对应的角在旋转。

这就是这个转场所需的一切。 记住,如果您不太明白其中的任何内容,可以随时下载项目文件,以了解具体的实现方式。

条状下落转场:

现在让我们看一下这个转场的最终效果:

乍一看,要把一个 room 这样拼接起来好像挺难的,但是,我们将其分解,就会发现它实际上是一个非常简单的效果。

obj_transitionbars:

对于这个转场,我将直接单独提供所有的代码,以免您要从前面的转场代码中寻找相关内容然后拼合起来:

创建(Create)事件 :

currentframe = 0
maxframes = 110

persistent =  true; //改变 room 时,避免销毁该对象

numberofbars = 8

//复制旧 room 的表面 ,这样我们就可以开始在新 room 的最上层进行显示
sur_oldroom = surface_create(room_width,room_height);
surface_copy(sur_oldroom,0,0,application_surface)

widthtouse = room_width
heighttouse = surface_get_height(application_surface)/numberofbars

//在这里我们初始化变量,这些变量将用来确定要在哪里显示下降的条状 
for(i = 0; i <numberofbars; i ++){
    barstopy [i] =(room_height / numberofbars)* i
    bary[i] = -100
    barspeed [i] = 1
    baroffset [i] = maxframes-(((maxframes / numberofbars)* i)-15
}

room_goto(room_second)    //我们已经记录了旧房间的表面,因此我们可以立即转到下一个房间。 
    

我认为有必要提醒各位,一旦创建了转场对象,它就会记录屏幕上的图像,然后切换 room。 然后,它会在新 room的最上层绘制旧 room 的图像,因此对于玩家而言,画面上看起来我们依然在原来的 room 里。

我们使用 surface_create() 和 surface_copy() 可以截取游戏的屏幕截图。

我还使用了一个循环,在该循环中,我们将初始化一些数组,这些数组将用于保存有关需要绘制下降的各个条状的信息。 所有这些数组都以单词bar开头,因此很容易知道它具体是什么。

步(step)事件 :

currentframe++

if (currentframe> maxframes){
    instance_destroy()//转场已完成,请销毁它
}

//我们现在在第二个 room,因此记录该 room 的画面。 
if (currentframe== 2){ 
    for(i = 0; i <numberofbars; i ++){
        spr_bar [i] = sprite_create_from_surface(application_surface,0,heighttouse * i,widthtouse,heighttouse,false,false,0,0);
    }
}
    

这个步事件正在做3件事;
首先,它递增计数器的数值,以告诉我们转场的进度。
其次,它检查转场是否已完成,如果已完成,则删除该对象。
最后,它检查我们是否在第二帧上,如果我们在第二帧上,我们知道房间已更改,因此我们需要记录新 room 的画面。

我们用循环单独保存每个要绘制的条状图,并从 heighttouse * i 控制图像的位置,这意味着每个循环将向下记录屏幕的不同部分。 然后,我们将所有这些单独的图像保存到spr_bar数组中。

绘制(Draw)事件 :

if (currentframe > 1) {
    if(surface_exists(sur_oldroom)){
        draw_surface(sur_oldroom,0,0)
    }

    for(i = 0; i <numberofbars; i ++){
        if(currentframe> baroffset [i]){
            if(bary [i] <barstopy [i]){
                bary [i] + = barspeed [i]
                barspeed [i] + = 2
            }else{
                bary [i] = barstopy [i]
            }
        }
        draw_sprite(spr_bar [i],0,0,bary [i])
    }

}
    

在绘制事件中,我们要做的第一件事是在新 room 最上方绘制旧 room 的画面,这掩盖了我们已经在新 room 里的事实。 然后,我们将在此之上绘制之前在step事件中保存的条形图。

这些条形图有两种,下落和固定在目标位置。 我们将每个条形图进行循环判断,并确定需要绘制的位置。 如果它处于下落状态,我们还需要控制其速度以适应帧变化。

GUI 绘制(Draw GUI)事件:

if(currentframe== 1){ 
    if(surface_exists(sur_oldroom)){
        draw_surface(sur_oldroom,0,0)
    }
}
    

在Draw GUI事件中,一旦当我们从旧 room 切换到新 room ,我们就立刻刷新绘制旧 room 的图像,这是为了让我们能够第一时间捕获屏幕画面,并向用户隐藏它。 如果我们不这样干,在换 room 时会出现轻微的闪烁。

销毁(Destroy)事件:

for(i = 0; i <numberofbars; i ++){
    sprite_delete(spr_bar [i])
}

surface_free(sur_oldroom)

我们需要做的最后一件事是在销毁对象时,要删掉专场过程中用过的图像。 销毁事件中的这个小循环会不断循环判断相关图像并将其从内存中删除。

就这些! 我说过,它并不像看起来那么难。 只要使用1个对象和不到50行代码,我们设法完成了看起来很复杂的转场效果。

如果您希望获得更多有关转场的灵感,我一直在使用GameMaker收集我在游戏和电影中看到的各种屏幕转场,您可以查看这些屏幕转场来帮助自己制作游戏。

我的网站上有其他适用于GameMaker的指南: www.davetech.co.uk ,我还在Twitter上发布了我从事的其他游戏开发工作: @DavesInHisPants

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