GMS2官方教程文档翻译-My First Game Chap2我的第一个小行星游戏第二章

  • 官方的教程,页面在这里:https://www.yoyogames.com/zh-CN/tutorials/make-your-own-arcade-classic

  • 自留备份用,可以对照教程来看。在页面下载完实例之后就会在默认浏览器中弹出教程

  • 由于版本更新不同,不贴教程里的所有图片

  • 专栏里的链接不指向任何地方,原文档里全是指向内部链接。所有的Next都在原文档里

  • B站这个专栏编辑器真难用

  • 本章介绍了很多互动功能,碰撞、子弹、消失动画等等。理解和代码比较多

2、攻击和碰撞

2.1 碰撞遮罩

In this chapter, we’re going to add in bullets and have collisions for them with the asteroids, as well as collisions for the asteroids with the player ship.

NOTE: If you have problems seeing the images in this tutorial, you can expand the tutorial window by dragging the edge into the IDE.

NOTE: If you close the accompanying video then you can get it back by clicking here

Since we haven’t defined any bullet objects or sprites, let’s first deal with the collision between the player ship object “obj_ship” and the asteroid objects “obj_asteroid“. Now, collisions in GameMaker Studio 2 are based off of what is called the collision mask, which is defined in the Sprite Editor:

在本章中,我们将添加子弹,并使其与小行星发生碰撞,以及使小行星与玩家的飞船发生碰撞。

注意:如果你看不清本教程中的图片,你可以通过拖动边缘到IDE中来扩展教程窗口。

注意:如果你关闭了附带的视频,那么你可以通过点击这里重新获得它。 由于我们还没有定义任何子弹对象或精灵,让我们首先处理玩家飞船对象 “obj_ship “和小行星对象 “obj_asteroid “之间的碰撞。现在,GameMaker Studio 2中的碰撞是基于所谓的碰撞遮罩的,它是在精灵设置中定义的。

This “mask” is the area that will be used by GameMaker Studio 2 to detect collisions, so that two instances are considered “in collision” when their collision masks overlap, or a mouse click is detected when the mouse x/y position is inside the defined mask area. There are a number of different mask options to choose from, including the mode – whether the mask should be defined automatically or manually – and the type – the shape that should be used to generate the mask.

这个 “遮罩 “是GameMaker Studio 2用来检测碰撞的区域,所以当两个实例的碰撞掩码重叠时,就被认为是 “碰撞”,或者当鼠标的X/Y位置在定义的遮罩区域内时,就检测到了鼠标点击。有许多不同的遮罩选项可供选择,包括模式–遮罩应该自动还是手动定义–和类型–应该用来生成遮罩的形状。

If you look through the type options, you’ll see that there is a precise option. This makes the collision mask “pixel perfect”, so that transparent areas will be ignored. You might think that this is the best option of all, as it means that all your collisions will be realistic, but it’s not. Calculating collisions is costly at the best of times, and using a precise pixel-perfect check for everything would increase the cost of doing collisions greatly. This is why we generally use rectangular collision masks, as they are relatively fast to check and deal with.

如果你看一下类型选项,你会看到有一个精确选项。这使得碰撞蒙版 “像素完美”,因此透明区域将被忽略。你可能认为这是所有选项中最好的,因为它意味着你的所有碰撞都是真实的,但事实并非如此。在最好的情况下,计算碰撞的成本是很高的,而对所有的东西使用精确的像素完美检查会大大增加做碰撞的成本。这就是为什么我们通常使用矩形碰撞掩码,因为它们检查和处理的速度相对较快。

That said, for our player object, we’ll be using a Diamond collision mask. This is still a faster mask type than “precise”, and has the benefit that is fits the “nose” of our ship sprite nicely. So, select the diamond type now, and set the mode not manual, then position the mask over the ship sprite, as shown below:

也就是说,对于我们的玩家对象,我们将使用一个钻石形状碰撞遮罩层。这仍然是一个比 “精确 “更快的掩码类型,并且有一个好处,就是它很适合我们的飞船精灵的 “鼻子”。所以,现在选择钻石类型,并将模式设置为非手动,然后将遮罩放在飞船精灵上,如下图所示。

【钻石形状(四边形)遮罩层调整贴到了示例的飞船上】

You’ll notice that the “wings” of the player ship sprite aren’t covered by the mask, which means that they will not detect collisions. In general, this is fine and pretty much normal for video games. Players don’t want every little thing to kill them, and as long as the collision mask is consistent and they can discover what area is okay and what area isn’t, then it’s fine. What would be worse would be a rectangular collision mask, as some things would be considered in a collision when visually they aren’t, and so the player would feel cheated.

With that done, let’s open each of the asteroid sprites and set the collision mask for them. We don’t need anything fancy here, so leave the mode on Automatic and set the type to ellipse:

你会注意到,玩家飞船精灵的 “翅膀 “并没有被遮罩层覆盖,这意味着它们不会检测到碰撞。一般来说这没什么问题,对电子游戏来说也很正常。玩家不希望每一个小东西都能杀死他们,只要碰撞遮罩是不发生变化的,他们能发现什么区域可以被碰到,什么区域不可以被碰到。最糟糕的是一个超出飞船绘画部位矩形的碰撞遮罩层,因为有些东西会被认为是正在被碰撞但是看起来却不是,所以玩家会感到被欺骗。

完成这些后,让我们打开每个小行星的精灵,为它们设置碰撞遮罩。我们在这里不需要什么调整,所以使用自动模式,把类型设为椭圆

When you’ve given each asteroid sprite an ellipse collision mask, we can move on and code the collisions themselves…

Click the “Next” button to continue…

当你给每个小行星精灵一个椭圆的碰撞掩码后,我们就可以继续对碰撞本身进行编码了……

点击 “下一步 “按钮,继续…

2.2 碰撞

We need to add another event to our player object “obj_ship“, so open that now and add a Collision Event between the ship object and the asteroid object “obj_asteroid“:

我们需要为我们的玩家对象 “obj_ship “添加另一个事件,所以现在打开它,在飞船对象和小行星对象 “obj_asteroid “之间添加一个碰撞事件。

We could instead add a collision event to the asteroid object to look for collisions between them and the player ship, but in general you want to have the instance there is least of (in this case “obj_ship“) do the checking, as less checks means better performance, so having one instance checking for a collision is better than having 10 instances checking for the same collision.

In this event we’re simply going to add this code:

我们可以为小行星对象添加一个碰撞事件,以寻找它们与玩家飞船之间的碰撞,但一般来说,你想让最少的实例(在本案例中是 “obj_ship”)进行检查,因为更少的检查意味着更好的性能【更少耗费运行内存,崩溃可能性更少】,所以让一个实例检查碰撞比让10个实例检查同一碰撞要好。【也就是指定所有怪物要比一个个设置所有怪物更节省资源】

在这个事件中,我们要简单地添加这段代码:

instance_destroy();

We’ll add more things to this event later to control lives and stuff, but for now all we’re doing is destroying the instance (removing it from the game room), and if you test the game now, you’ll see that the ship “disappears” (is destroyed) when it collides with an asteroid.

Click the “Next” button to continue…

我们以后会在这个事件中添加更多的东西来控制生命之类的东西,但现在我们所做的就是摧毁这个实例(将其从游戏室中移除),如果你现在测试游戏,你会看到当飞船与小行星相撞时 “消失 “了那就可以了。

点击 “下一步 “按钮,继续…

2.3 射击

Asteroids can now destroy the player, but we haven’t got any mechanism for the player to destroy the asteroids! Let’s add that now…

The first thing we need to do is make the bullet sprite, so make a new Sprite Resource, call it “spr_bullet” and set its size to 2x2px:

小行星现在可以摧毁玩家,但我们还没有任何机制让玩家摧毁小行星!现在让我们加入这个机制。

我们需要做的第一件事是制作子弹的精灵,所以制作一个新的精灵资源,将其称为 “spr_bullet”,并将其大小设置为2x2px。

Now, edit the sprite in the Image Editor and colour it white, so that you get a 2x2px white square. Close the Image Editor, and then set the origin of the sprite to Middle Center and leave the collision mask on its default properties, which are perfectly fine for this sprite.

The next thing to do is make a new object, call it “obj_bullet” and assign it this new sprite that you’ve just created:

现在,在图像编辑器中编辑这个精灵,给它涂上白色,这样你就得到一个2x2px的白色正方形。关闭图像编辑器,然后将精灵的原点设置为 “居中”,并将碰撞遮罩保留在默认属性上,这对这个精灵来说设置简单的遮罩就好。

接下来要做的是建立一个新的对象,将其称为 “obj_bullet”,并将你刚刚创建的这个新精灵分配给它。

We can go back to the player ship object now, and open up the Step Event again. We are going to add the following code to detect a key press and then create an instance of the bullet object:

我们现在可以回到玩家飞船对象,再次打开步骤事件。我们将添加以下代码来检测一个按键,然后创建一个子弹对象的实例。

if (keyboard_check_pressed(vk_space))
{
instance_create_layer(x, y, “Instances”, obj_bullet);
}

So, we’re using keyboard_check_pressed() instead of the previously used keyboard_check() function, because we only want to create 1 bullet for every key press. If we just used keyboard_check(), then we’d be creating a new bullet instance every step the key is held down (so 60 bullets in one second since our game is at 60FPS). We obviously don’t want that and by using the _pressed function, the “if” will only evaluate to true once each time the key is pressed, and no more even if it’s held down.

所以,我们使用keyboard_check_pressed()而不是之前使用的keyboard_check()函数,因为我们只想为每一个按键创建一个子弹。如果我们只使用键盘检查(),那么每按一次键就会创建一个新的子弹实例(所以一秒钟有60颗子弹,因为我们的游戏是60FPS的)。我们显然不希望这样,通过使用pressed函数,”if “将只在每次按键时评估为真,即使按键被按下也不会再有。

This code means that every time the player presses the spacebar !, a bullet will be created on the layer named “Instances”. A layer is simply a plane on which we place instances in the room editor, and if you look in the room editor you can see in the top left corner (by default) the list of layers in the room. You can add or remove layers here too, and each layer has a “depth” value associated with where the higher the depth, the “further” from the viewer it is and the lower the depth, the “closer” to the viewer, so that a layer at depth 100 will be drawn under a layer at depth -200.

We’re not quite finished with that code yet though… When created, the bullet won’t be moving and even if it was, it wouldn’t know which direction to move in. So, to solve that, we need to tell it the direction to move using code.

这段代码意味着,每次玩家按下空格键,就会在名为 “Instances “的图层上创建一个子弹。图层只是一个平面,我们在房间编辑器中把实例放在上面,如果你在房间编辑器中看到,你可以在左上角(默认情况下)看到房间中的图层列表。你也可以在这里添加或删除图层,每个图层都有一个 “深度 “值,深度越高,离观察者越 “远”,深度越低,离观察者越 “近”,所以一个深度为100的图层会被画在一个深度为-200的图层之下。

The function instance_create_layer() returns an instance ID value, which is the unique ID for the instance that it created. We can use this ID to set values and properties on the instance, straight after it has been created, as shown in the following code:

instance_create_layer()函数返回一个实例ID值,这是它创建的实例的唯一ID。我们可以使用这个ID来设置实例的值和属性,就像下面的代码所示,在它被创建之后。

if (keyboard_check_pressed(vk_space))
{
var inst = instance_create_layer(x, y, “Instances”, obj_bullet);
inst.direction = image_angle;
}

What’s going on here then? Well, we have create a local variable called “inst“, and we’re using it to store the returned instance ID from the create function. A local variable is a “use and throw away” variable, that will only exist for the duration of the script or the event that it was declared in. This is useful for data that we don’t need to hang around (for more information on variables and variable scope, please see the manual).

We then use this variable to set the direction of movement for the instance we just created. When we use the ID value followed by a point”.” like this, we are telling GameMaker Studio 2 that the “direction variable we are setting is in the instance stored in the “inst” variable, and not in the instance running the main code block. So, i this way we are setting the bullet direction to match the angle of rotation of the ship sprite.

The final thing we need to do is set the speed of the bullet. Now, you could do this in the player object using inst.speed = VALUE, as we did for the direction, but that’s unnecessary as the speed for all bullets is always going to be the same, and generally accessing an instance this way is only used for values that are going to change (like the direction). So, we need to go back to the bullet object “obj_bullet” and add in a Create Event with this code:

这里发生了什么?好吧,我们创建了一个名为 “inst “的局部变量,我们用它来存储从创建函数返回的实例ID。局部变量是一个 “用完即丢 “的变量,它只在脚本或事件的持续时间内存在,它被声明在其中。这对那些我们不需要挂在那里的数据很有用(关于变量和变量范围的更多信息,请看手册)。

然后我们使用这个变量来设置我们刚刚创建的实例的运动方向。当我们像这样使用ID值后面的点”. “时,我们是在告诉GameMaker Studio 2,我们正在设置的 “方向变量是存储在 “inst “变量中的实例,而不是运行主代码块的实例。所以,这样我们就把子弹的方向设置为与飞船精灵的旋转角度一致。

我们需要做的最后一件事是设置子弹的速度。现在,你可以在玩家对象中使用inst.speed = VALUE来做这件事,就像我们对方向所做的那样,但这是不必要的,因为所有子弹的速度都是一样的,而且一般来说,以这种方式访问一个实例只适用于那些要改变的值(如方向)。所以,我们需要回到子弹对象 “obj_bullet”,用这段代码添加一个创建事件:

speed = 6;

You can test the game now, and you should see that every time you press the keyboard spacebar down, a single bullet will be released, and you have to release and press the spacebar again to create more:

你现在可以测试游戏了,你应该看到,每次你按下键盘上的空格键,就会有一颗子弹被释放出来,你必须释放并再次按下空格键来创造更多的子弹。

Click the “Next” button to continue…

点击“Next”继续

2.4 更多遮罩

We need our bullets to destroy the asteroids, so to do that we need to open the object “obj_bullet” (if it’s not already open) and add a Collision Event to it with the object “obj_asteroid“:

我们需要创建的子弹来摧毁小行星,所以要做到这一点,我们需要打开对象 “obj_bullet”(如果它还没有打开),并为它添加一个与对象 “obj_asteroid “的碰撞事件。

The first thing we’re going to do in this event is tell the bullet to destroy itself using instance_destroy():

在这个事件中,我们要做的第一件事是用instance_destroy()告诉子弹要销毁自己。

instance_destroy();

You might think that this will prevent any further code from running after the function is called, but in GameMaker Studio 2 destroying an instance doesn’t happen until the end of the event, so although we’ve called this function, it doesn’t exit the event and the instance won’t actually be removed from the room until the collision event is resolved.

你可能认为子弹击中目标就会自动消失,但在GameMaker Studio 2中,需要摧毁一个实例直到事件结束。所以尽管我们已经调用了这个函数,它并没有实际意义上退出事件,在碰撞事件被解决之前,实例实际上不会被从房间中移除。

What other code do we need? Well, we want the bullet to destroy the asteroids it hits, and we also want it to “split” the bigger asteroids into smaller ones. To do this we need to be able to access the instance ID of the asteroid that is being detected as colliding with the bullet, and for that we’ll use the special keywordother“. This keyword, when used in the collision event, will reference the “other” instance in the collision, so in our game, the bullet is colliding with an asteroid, so “other” will reference the unique ID of the asteroid.

To use this keyword we’ll do this:

我们还需要哪些代码呢?好吧,我们希望子弹能够摧毁它所击中的小行星,我们也希望它能够将较大的小行星 “分割 “成较小的小行星。要做到这一点,我们需要能够访问被检测到与子弹相撞的小行星的实例ID,为此我们将使用特殊的关键词 “其他”。这个关键字,在碰撞事件中使用时,将引用碰撞中的 “其他 “实例,所以在我们的游戏中,子弹与小行星碰撞,所以 “其他 “将引用小行星的唯一ID。

为了使用这个关键词,我们要这样做。

with (other)
{

}

Here we introduce the with() statement. When you call “with (instance)” you are telling GameMaker Studio 2 that everything within the curly brackets {} afterwords should be run as if it was native to the instance. So, in this case, while the code is in the bullet object, it will be run as if it was in the asteroid object. This means that we can access variables and run functions on the asteroid in the collision.

Like the bullet, we also want the asteroid to destroy itself, so we fill in the code like this:

这里我们介绍一下with()语句。当你调用 “with (instance) “时,你是在告诉GameMaker Studio 2,后面的大括号{}内的所有内容都应该被运行,就像它在实例中一样。因此,在这种情况下,当代码在子弹对象中时,它将被当作在小行星对象中运行。这意味着我们可以在碰撞中访问小行星上的变量和运行函数。

和子弹一样,我们也希望小行星能够自我毁灭,所以我们这样填入代码:

with (other)
{
instance_destroy();
}

Now, because we changed the scope of the code to the “other” instance in the collision (the asteroid instance), the instance_destroy() function will destroy the asteroid. We also want to “split” the asteroid based on what size the sprite is, so for that we’d add the following:

现在,由于我们将代码的范围改为碰撞中的 “另一个 “实例(小行星实例),instance_destroy()函数将销毁小行星。我们还想根据精灵的大小来 “分割 “小行星,所以为此我们要添加以下内容:

with (other)
{
instance_destroy();
if (sprite_index == spr_asteroid_huge)
   {
   repeat(2)
       {
       var new_asteroid = instance_create_layer(x, y, “Instances”, obj_asteroid);
       new_asteroid.sprite_index = spr_asteroid_med;
       }
   }
}

Here we’re showing just the code for when the other asteroid in the collision is a “huge” asteroid. What it’s doing is checking the sprite of the asteroid, and if it’s a “huge” sprite, then it will create 2 new asteroids and assign them the “medium” sprite. Two things to note here: the first is the use of the repeat() statement, which will simply repeat the code contained within the {} that follow by the number of times given (in this case, 2), and the second thing to note is how we change the asteroid sprite index. You’ll remember that we set it to a random sprite in the Create Event of the object, and here we’re overwriting it it with a different value. This works because the moment an instance is created, its create event is run and then the code continues in the event that created the instance.

We can duplicate this code for the medium asteroid, so that it will look like this:

这里我们只展示了当碰撞中的另一个小行星是 “巨大 “小行星时的代码。它所做的是检查小行星的精灵,如果它是一个 “巨大 “的精灵,那么它将创建两个新的小行星,并将它们分配给 “中等 “的精灵。这里有两件事需要注意:第一件事是使用了repeat()语句,它将简单地重复后面的{}中包含的代码,重复的次数是给定的(在这里是2),第二件事要注意的是我们如何改变小行星的精灵索引。你会记得我们在对象的创建事件中把它设置为一个随机的精灵,而在这里我们要用一个不同的值来覆盖它。这样做是因为当一个实例被创建时,它的创建事件被运行,然后代码在创建实例的事件中继续。

我们可以为中型小行星复制这段代码,这样它就会看起来像这样:

with (other)
{
instance_destroy();
if (sprite_index == spr_asteroid_huge)
   {
   repeat(2)
       {
       var new_asteroid = instance_create_layer(x, y, “Instances”, obj_asteroid);
       new_asteroid.sprite_index = spr_asteroid_med;
       }
   }
else if (sprite_index == spr_asteroid_med)
   {
   repeat(2)
       {
       var new_asteroid = instance_create_layer(x, y, “Instances”, obj_asteroid);
       new_asteroid.sprite_index = spr_asteroid_small;
       }
   }
}

We’ve used the “if.... else if...” code format for this. Using “else” is simply a way to have another set of code run when an “if” evaluates to false, and adding another “if” after the “else” we are saying:

我们为此使用了 “if…. else if… “的代码格式。使用 “else “只是一种方法,当一个 “if “评估为false时,让另一组代码运行,并在我们所说的 “else “之后增加一个 “if”。

if (this_evaluates_to_true) then do this {} else if (that_evaluates_to_true) then do that {}

We could add another “else if” after that to check for a small asteroid sprite, but instead we’ll do something slightly different…

Click the “Next” button to continue…

我们可以在这之后添加另一个 “else if “来检查小行星的精灵,但我们将做一些稍微不同的事情……

点击 “下一步 “按钮,继续…

2.5 碎片

We’re going to add a “debris” effect into our game, and not just for the small asteroids, but for whenever any asteroid is destroyed. For that you need to create a new sprite, set it to be a 1×1 pixel only, then colour it white. This will be our debris sprite, so give it an appropriate name like “spr_debris“, and then you can close the Sprite Editor, as we don’t need to change its collision mask or do anything else.

我们要在我们的游戏中添加一个 “碎片 “效果,而且不仅仅是单个的小行星,而是任何小行星被摧毁时的效果。为此,你需要创建一个新的精灵,将其设置为只有1×1像素,然后将其染成白色。这将是我们的碎片精灵,所以给它一个合适的名字,比如 “spr_debris”,然后你可以关闭精灵编辑器,因为我们不需要改变它的碰撞遮罩或做其他事情。

Now we need to make a new object, called “obj_debris“. Create it and name it now, and assign it the sprite you just created, “spr_debris“. We’ll give this object a Create Event where we’ll use the following code to give it a random direction and some momentum:

现在我们需要创建一个新的对象,叫做 “obj_debris”。现在就创建它并为其命名,并将你刚刚创建的精灵 “spr_debris “分配给它。我们将给这个对象一个创建事件,我们将使用下面的代码给它一个随机的方向和一些动力。

direction = irandom_range(0, 359);
speed = 1;

We also want to give this object a Step Event, so do that now. In this event we’ll make instances of the object fade out and then destroy themselves when they are no longer visible. To do this we’ll be working with the image_alpha, which is a built in variable that controls the transparency (alpha) of the sprite assigned to the instance. A value of 1 is fully opaque and a value of 0 is fully transparent, and what we’ll have our object do is gradually lower the image_alpha from 1 to 0 with this code:

我们还想给这个对象一个步骤事件,所以现在就做。在这个事件中,我们将使对象的实例淡出,然后在它们不再可见时销毁自己。为了做到这一点,我们将使用image_alpha,这是一个内置变量,控制分配给该实例的精灵的透明度(alpha)。值为1是完全不透明的,值为0是完全透明的,而我们要让我们的对象做的是用这段代码将image_alpha从1逐渐降低到0。

image_alpha = image_alpha – 0.01;
if (image_alpha <= 0)
{
instance_destroy();
}

This will take a small amount off the image_alpha and when it gets equal-to or below zero, the instance destroys itself. Note that we don’t do the check as “if (image_alpha == 0)“! Most numbers in GameMaker Studio 2 are floating point which means they can get minute rounding errors that can accumulate and cause issues with exact “==” checks. In the above case, it may be that the image_alpha value never reaches exactly zero and instead hits a number like 0.0000002, which would then roll over to be -0.0900002 and so never be exactly zero… which is why we check if it’s less than or equal to 0. This may seem a bit contrary to common sense, but it’s a fact of life when programming!

这将从image_alpha中抽取一小部分,当它等于或低于0时,该实例就会自我销毁。注意,我们不做 “if (image_alpha == 0) “这样的检查。GameMaker Studio 2中的大多数数字都是浮点数,这意味着它们可能会出现微小的四舍五入误差,这些误差会累积起来,导致精确的”==”检查出现问题。在上面的例子中,image_alpha的值可能从来没有达到过精确的0,而是达到了像0.0000002这样的数字,然后会滚动到-0.0900002,所以永远不会精确到0…这就是为什么我们检查它是否小于或等于0。

NOTE: If you want to know the reasons why this happens, then please take a moment to read this web page: What Every Programmer Should Know About Floating-Point Arithmetic.

注意:如果你想知道发生这种情况的原因,那么请花点时间阅读这个网页。关于浮点运算,每个程序员都应该知道什么。

The final thing to do now is add some code to create these instances when the bullet hits the asteroids, and, just because we can, let’s add them into the player object when it hits an asteroid and is destroyed too. So, open up the bullet object “obj_bullet” and in the Collision Event with “obj_asteroid“, edit the code so it looks like this:

现在要做的最后一件事是添加一些代码,在子弹击中小行星时创建这些实例,而且,只是因为我们可以,让我们在玩家对象击中小行星并被摧毁时将其加入。所以,打开子弹对象 “obj_bullet”,在与 “obj_asteroid “的碰撞事件中,编辑代码,使其看起来像这样。

with (other)
{
instance_destroy();
if (sprite_index == spr_asteroid_huge)
   {
   repeat(2)
       {
       var new_asteroid = instance_create_layer(x, y, “Instances”, obj_asteroid);
       new_asteroid.sprite_index = spr_asteroid_med;
       }
   }
else if (sprite_index == spr_asteroid_med)
   {
   repeat(2)
       {
       var new_asteroid = instance_create_layer(x, y, “Instances”, obj_asteroid);
       new_asteroid.sprite_index = spr_asteroid_small;
       }
   }
repeat(10)
   {
   instance_create_layer(x, y, “Instances”, obj_debris);
   }
}

Then, open the player ship object “obj_ship” and in its Collision Event with “obj_asteroid“, and add the following after instance_destroy():

repeat(10)
{
instance_create_layer(x, y, “Instances”, obj_debris);
}

Run the game now, and shoot some asteroids! If all has gone well, then they should explode into smaller asteroids and create a nice puff of debris:

现在运行游戏,并射击一些小行星 如果一切顺利,那么它们应该会爆炸成更小的小行星,并产生一蓬漂亮的碎片。

Click the “Next” button to continue…

2.6 清空

Before we finish this section of the tutorial, we need to do some cleaning up. In programming, there are many ways you can leave things lying around that will “clog-up” the computers memory and cause performance issues or worse. In general this kind of error is called a memory leak, and it’s something you want to avoid at all costs in your own proects, meaning that you have to be careful to make sure that your game is programmed efficiently, and you don’t leave things when no longer needed, but instead destroy them in some way.

在我们完成本节教程之前,我们需要做一些清理工作。在编程中,有很多方法可以让你的东西到处乱放,从而 “堵塞 “计算机内存,导致性能问题或更糟。一般来说,这种错误被称为内存泄漏,这是你在自己的程序中要不惜一切代价避免的,也就是说,你必须小心翼翼地确保你的游戏是有效的编程,当不再需要时,你不会留下东西,而是以某种方式销毁它们。

In our game as it stands, we have a memory leak! Our room is only 500x500px, and we wrap our player and our asteroid instances if they go outside that area. But what about our bullets? They fly out the room space… and then what? Well, then nothing! Once outside the room, they are just taking up memory space without actually performing any useful task in our game, so we want to destroy them when they can no longer be seen.

We want to add an Outside Room event to our bullet object “obj_bullet“, so do that now:

在我们目前的游戏中,我们有一个内存泄漏!我们的房间只有500x500px。我们的房间只有500x500px,如果我们的玩家和小行星的实例超出了这个区域,我们就把它们包起来。但是我们的子弹呢?他们飞出了房间的空间……然后呢?嗯,然后什么都没有了! 一旦出了房间,它们就只是占用了内存空间,而没有在我们的游戏中执行任何有用的任务,所以我们要在它们不再被看到时销毁它们。

我们想给我们的子弹对象 “obj_bullet “添加一个 “房间外 “事件,所以现在就做。

This event will only be triggered when the instance x/y position goes outside the room edges. In this event we’ll simply add:

这个事件只有在实例的X/Y位置超出房间边缘时才会被触发。在这个事件中,我们将简单地添加。

instance_destroy();

That’s all we need to tell the instance that if it leaves the room, it should destroy itself. Memory leak averted!

Click the “Next” button to continue on to the next part – Score, Lives and Effects

这就是我们需要告诉实例,如果它离开这个房间,它应该销毁自己。避免了内存泄漏!

点击 “下一步 “按钮,继续下一部分–分数、生命和效果……

资源下载: