帧(Frames)与步(Steps)
在讲对象(Objects)之前,得先了解一个 GM 的重要概念,叫做帧(Frames)。
游戏如何向玩家传递信息?显而易见,是把所有的游戏内容绘制到游戏窗口内,让玩家能够看到游戏的内容。
我们知道,游戏窗口内的图像不可能是一直静止不动的。例如玩家按下方向键,窗口内角色的位置就要改变,角色的图像就要重新画到角色移动后的位置上,而不能还保留在原地。
那么 GM 是怎么处理窗口内图像的变化?事实上是这样的,GM 每隔一段极短的时间(通常只有零点零几秒)就会清空窗口内的所有内容,再把所有物件的图像全部重新画一遍——也包括背景图片,而不管这个物件的图像有没有改变。
帧(Frames)的汉语本意,是描述画像的量词,如“一帧油画”。游戏进行一次绘制之后窗口内所显示的图像,称为“一帧”,每两帧之间的极短的时间间隔,叫做“一步”(非正式地也用“帧”来代表“步”的意思),游戏每一秒钟进行绘制的次数,叫做“帧率”(fps,即frames per second)(非正式地也叫“帧数”)。
可以理解为,帧指的是时间点,而步是指时间段。
面板介绍
首先,新建一个对象,你可以看到这个面板:
- 名称(Name):对象的命名规则请见上一节。
精灵(Sprite):可以为对象选择一个精灵,游戏运行时,这个对象就会以这个精灵的图像出现在屏幕中。
最好把对象名和精灵名一一对应,如 sprBlock 对应 objBlock。
精灵的下方有两个选项,可见(Visible),固体(Solid)。
可见(Visible)顾名思义,就是这个对象在游戏中是否可以被看见。或者说,这个对象在游戏中是否绘制自己的精灵。这个选项定义的只是初始状态,可见 状态并不是不可变的,可以使用代码改变可见状态。
固体(Solid)这个选项相当于是把对象分成了固体和非固体两类,以方便进行一些判定。当讲到“碰撞(Collision)”时会讲到他的用法。
深度(Depth):不同的对象在房间中重叠时,深度决定了谁在表层,谁在底层,即谁的精灵把谁的精灵覆盖。
深度值大,这个对象就在底层,会被深度值小覆盖;深度值小,这个对象就在表层,会覆盖别的对象。
深度值默认为 0,可以为负数,当深度值相同的对象重叠在一起时,根据他们被创建的时间顺序来决定位置,即先被创建的对象在底层被覆盖,后被创建的对象在表层。
- 保持(Persistent)这个属性决定在房间(Rooms)改变时是否销毁当前对象。一般用于控制全局的对象会勾选这个属性,平时用不上。
- 父对(Parent),笼罩层(Mask)将在后面的章节讲解。
事件(Events)
在讲解事件(Events)之前,首先声明一点,用 GameMaker 做游戏,是需要写代码的。如果不想写代码来做游戏,建议使用 RPG Maker 而不是 GameMaker。
代码的作用就只有一个,实现你想要实现的效果。
点击对象的面板中下方的“添加事件”(Add Event)按钮,会弹出下面的窗口:
这里有形形色色的事件类型可以供你选择。
什么是事件?
事件,可以理解为条件,即,写在某个事件下的代码,只有在该事件的条件被满足时才会执行。这是一个很抽象的概念,需要实际应用才能慢慢理解。
举个例子:
假如有一段代码,我们叫它代码 A,它可以实现游戏角色向左移动,又有另外一段代码,我们叫它代码 B,它可以实现游戏角色向右移动。那么问题来了,游戏要怎么知道什么时候执行代码 A,什么时候执行代码 B?根据我们的需要,我们可能会这样要求它:按下左键执行代码 A,按下右键执行代码 B。
那么我们要怎么样让代码 A 只在按下左键时执行,代码B只在按下右键时执行呢?在这里,“按下左键”和“按下右键”就是两个事件。只要在事件列表里找到按下左键和按下右键这两个事件,再把代码 A 和代码 B 分别写在两个事件中,能让游戏在正确的条件下执行正确的代码。
在 GM 里,一个对象的代码不是全部写在一起的,而是根据自身作用放在不同的事件(Events)里。
在下面的内容中,“实例”被用括号括起。由于“实例”的概念需要先讲解“房间”的概念才能理解,所以下文中的“实例”一词可以暂时不去考虑他的实际意义。
- 创建事件(Create Event):这个事件中的代码,只有在该对象(的实例)被创建时才会执行一次,之后不会再执行。
- 销毁事件(Destroy Event):这个事件中的代码,只有在该对象(的实例)被销毁时才会执行一次。
- 计时器事件(Alarm Event):你可以为这个事件设定一个倒计时(
alarm[x] = xx;
),倒计时结束后这个事件的代码才会执行且只执行一次。一共可以设 置12 个不同的计时器事件(0-11)(例如alarm[0] = 30;
代表30步后执行alarm的0号事件),同一个计时器事件用过之后可以再次使用。 - 步事件(Step Event):这个事件中的代码,每一步都会执行一次,优先级低于创建事件(即对象刚被创建时的第一步先执行创建事件再执行步事件)。步事件分为普通步事件,步开始(begin step)事件,步结束(end step)事件,这三者执行先后顺序不同(即优先级不同)。
- 碰撞事件(Collision Event):这个事件中的代码,当该对象(的实例)与其他对象(的实例)发生碰撞时会执行。
- 键盘事件(Keyboard Event)、按下键盘事件(Key Press Event)、放开键盘事件(Key Release Event)的区别是:当你按住键盘时,键盘事件每一步都会执行一次,直到你松开为止;按下键盘事件只在按下键盘的那一步执行一次,放开键盘事件只在松开键盘的那一步执行一次。
- 绘制事件(Draw Event):与步事件一样,是每一步都执行一次的事件,用于绘制图形的代码只有写在绘制事件里才有用。优先级与步事件不同。
- 触发器事件(Trigger Event):如果上面的事件中没有你想要的,你可以自定义一个触发器事件,当你填入的条件满足时,会执行该事件。这个事件目前而言毫无作用。
- “其他”中的各种事件,也都是在满足其条件下才会执行的事件,不再累赘讲述。其中的用户自定义事件只有在遇到代码:
event_user(x);
(x 代表事件编号)来调用才会执行一次。
GM每一步事件执行的顺序是:
- 步开始事件(Begin Step)
- 计时器事件(Alarm)
- 键盘事件(Keyboard)
- 鼠标事件(Mouse)
- 普通步事件(Step)
- 对象的实例进行移动(并非事件,就如同字面上理解,这时期 GameMaker 会移动对象的实例)
- 碰撞事件(Collision)
- 步结束事件(End Step)
- 绘制事件(Draw)
事实上,GM 里可以用步事件来代替大部分其他事件。在很多比较复杂的逻辑中,通常都使用步事件来取代这些事件,这是因为在同一个事件中,代码的执行顺序是从上到下的,因此可以自己控制代码的执行顺序。而写在多个事件中的代码,可能会因为GM默认的事件执行顺序导致 bug。之后我会逐步讲解如何用步事件代替其他事件。
动作(Action)
动作即使指面板最右边的各种按钮。动作可以实现一些简单的效果。
当你添加了一个事件之后,你可以通过拖动这些按钮到大方框内,为这个事件添加一些效果。
但是,在这里我并不提倡使用动作。动作能实现的效果十分有限。一旦习惯于使用动作,你的 GM 水平会受到限制。在本教程中,将一律使用代码进行教学。你唯一会用到的动作就是 control 下的代码框,这是用来写代码的地方: