移动及控制

本快速入门指南的 前一节 给出了一些将东西画到屏幕上的例子,但如果你不能移动它们,那么只画东西并不是很好……。因此,在这一节中,我们将为您的对象提供一些移动的例子,以及不同类型游戏的一些基本控制方案。所有的示例都是使用 GML 可视化和 GML 代码给出的,所以您可以使用您觉得更舒服的任何一个。注意,我们不会在这里做太深入的解释,因为我们希望你尽快开始制作东西,所以我们鼓励你在进行过程中探索任何链接,并使用手册的 "搜索" 功能来寻找关于任何你不确定的东西的其他信息。

在继续之前,您可能希望从开始页创建一个新项目(GML或GML可视化),并添加(或创建)几个精灵以及一个或两个对象--因为我们将提供一些代码,您可以使用这些代码进行测试-并确保项目有空间放置实例。不要太担心你制作的精灵看起来像什么,即使是一个简单的白色方块也可以,一旦你准备好了,你就可以开始制作下面列出的例子了。

 

向鼠标移动向鼠标移动

让对象移动并与玩家交互的最简单方法之一是使用鼠标,在本例中,我们将向您展示如何使用一些基本代码使对象移动到用户单击鼠标左键LMB Icon的任何位置。

首先,打开一个对象,为其指定一个精灵,然后为其指定一个全局鼠标左键按下事件

Adding The Mouse Left Button Down Event

我们使用全局鼠标事件,因为它们检测到房间中任何位置的单击,而常规鼠标事件仅在鼠标实际在实例边界框内单击时才检测到单击。在这种情况下,我们希望添加以下操作或代码:

GML VisualTo Move Instance Towards Mouse

move_towards_point(mouse_x, mouse_y, 2);

在这里,我们告诉实例向屏幕上的某个位置移动,在本例中是"mouse_x"和"mouse_y"位置("mouse_x"和"mouse_y"是始终保持当前鼠标光标位置的内置变量)。GML 可视化通过设置"方向"和"速度"实例变量,而GML使用函数 move_towards_point() (这也只在一个简单易用的函数中设置速度方向变量)来实现这一点。

将此对象的一个实例放置在房间中,然后点击播放按钮 Play Icon,然后在房间周围单击 LMB Icon,使该实例向鼠标移动:

Animation Of Instance Moving Towards Mouse太棒了!对象的实例现在向您单击的位置移动,如果您按住按钮,该实例将继续跟随鼠标光标。然而,有一个问题……。单击一次并释放后,实例将继续移动并最终离开房间!我们有许多方法可以修复此问题,您可以选择哪种方法取决于您想要做什么,但目前最简单的修复方法是只需添加一个全局鼠标按钮释放事件,因此现在将其添加到对象并给出以下代码:

GML VisualTo Set The Instance Speed

speed = 0;

这样,只要按住鼠标按钮,实例就会一直跟随鼠标光标,而当您松开按钮时,它将停止移动。按播放 Play Icon 并立即测试它。

在我们离开这个例子之前,我们需要解决最后一个问题...。如果您单击并按住鼠标按钮,但不移动光标,则实例将朝向光标移动,然后绕着它“振动”。这是因为实例一次移动的速度超过1个像素,因此会“过度拍摄”该位置,然后尝试向后移动,然后再次过度拍摄,依此类推。(如果问题不是很明显,请将移动速度设置为5或类似的值以查看问题)。

Animation Showing Instance Vibrating要解决此问题,我们需要使用以下代码向对象添加一个步事件

GML VisualActions For The Step Event

var _dist = point_distance(x, y, mouse_x, mouse_y);

if (_dist <= speed)
{
    speed = 0;
}

在这里,我们只检查从实例到鼠标位置的距离,如果它等于或小于当前速度,则将速度设置为0。这会使实例在足够接近鼠标位置时停止,并且我们不会遇到讨厌的"振动"问题。

 

键盘的4向和8向移动键盘的4向和8向移动

在本指南的开头,我们向您展示了以下操作和代码,用于在每个游戏步骤中将实例向右移动两个像素:

GML VisualExample

x = x + 2;

这种类型的移动称为位置移动,因为我们实质上是在每次运行代码时拿起实例并将其放在新位置。在本例中,我们要做的是向您展示如何使用这种移动方式在4个方向上移动实例:向上、向下、向左和向右。

首先,打开一个对象并为其指定一个精灵。现在,我们可以在这一点上添加各种键盘事件,并在每个事件中让实例向所需的方向移动,但是,我们希望玩家一次只能向一个方向移动,并且只使用键盘事件来做这件事比使用代码要复杂一些。相反,我们将使用步事件 - 您现在应该将其添加到对象 - 以及使用箭头键移动的以下操作或代码:

GML VisualStep Event Movement Actions

if (keyboard_check(vk_left))
{
    x = x - 2;
}
else if (keyboard_check(vk_right))
{
    x = x + 2;
}
else if (keyboard_check(vk_up))
{
    y = y - 2;
}
else if (keyboard_check(vk_down))
{
    y = y + 2;
}

我们使用" if... else if... else if..." 结构来确保实例一次只能向一个方向移动,因此实例应该只能向上、向下、向左或向右移动,但不能沿对角线移动。将该对象的一个实例放置在房间中,然后按下 播放 按钮 Play Icon 立即测试它!如果一切正常,您应该会看到如下内容:

Animation Showing 4-Way Keyboard Movement

我们可以修改这个代码,将4向移动转换为8向移动也很容易……。只需从代码块中删除“Else”命令,使一切看起来如下所示:

GML VisualStep Event Movement Actions

if (keyboard_check(vk_left))
{
    x = x - 2;
}
if (keyboard_check(vk_right))
{
    x = x + 2;
}
if (keyboard_check(vk_up))
{
    y = y - 2;
}
if (keyboard_check(vk_down))
{
    y = y + 2;
}

现在,当您按下播放按钮Play Icon时,它将如下所示:

Animation Showing 8-Way Keyboard Movement

对于使用 GML 代码的用户来说,最后一件值得注意的事情是 ...。当使用 GML 可视化时,您可以从下拉列表中选择想要使用的键盘键,但使用 GML 就没有那么简单了。您可以使用许多 键盘常量  -- 就像上面代码中显示的箭头键常量一样 -- 但字母数字键没有常量。它们的处理方式略有不同,需要使用函数 ord()。下面的代码向您展示了如何使用 WASD 而不是箭头键来执行此操作:

if (keyboard_check(ord("A")))
{
    x = x - 2;
}
if (keyboard_check(ord("D")))
{
    x = x + 2;
}
if (keyboard_check(ord("W")))
{
    y = y - 2;
}
if (keyboard_check(ord("S")))
{
    y = y + 2;
}

 

游戏手柄移动游戏手柄移动

我们已经介绍了鼠标移动和键盘移动,这意味着是时候介绍 游戏手柄 移动了。现在,我们将不介绍数字键盘,因为它的工作原理与使用键盘一样 (只需将上述示例中的键盘功能更改为 gamepad_button_check()如果手柄按钮按下 ),因此在此示例中,我们将查看使用模拟杆进行移动。

首先,我们需要检测正在使用的游戏手柄。游戏手柄被赋予一个从 0 到 11 的 ID 值,因此我们将使用 "for" 循环来检测任何连接的游戏手柄的 ID,并将该 ID 值存储在一个变量中以备将来使用。因为我们只想设置第一个连接的游戏手柄,而不是所有的游戏手柄,所以我们将在检测到游戏手柄后使用 "Break" 命令,以便它 " 中断 " 循环 (例如,如果第一个连接的游戏手柄是 ID4,则循环将只运行 5 次,检查 ID 值 0-4,然后在遇到游戏手柄时退出循环)。因此,创建 (或打开) 一个对象,为其指定一个精灵,然后添加一个具有以下内容的 创建事件

Getting Gamepad ID Using DnD

gamepad_id = -1;

for (var i = 0; i < 12; i += 1;)
{
    if (gamepad_is_connected(i))
    {
        gamepad_id = i;
        gamepad_set_axis_deadzone(gamepad_id, 0.2);

        break;
    }
}

请注意,在上面的代码中,我们为游戏手柄设置了死区。这是因为不同品牌的游戏手柄上的模拟杆会有不同的敏感度,有时它们会非常敏感,如果你不设置死区,它们可能会在你的游戏中造成不必要的移动。因此,我们将死区设置为类似 0.2 的值,以告诉 GameMaker 忽略该 绝对值 下的所有游戏手柄操纵杆。

要添加实际的移动,我们需要一个步事件,因此现在添加该事件,并为其提供以下 GML 可视化或 GML:

Get Gamepad Input Using DnD

if (gamepad_id > -1)
{
    var _h = gamepad_axis_value(gamepad_id, gp_axislh);
    var _v = gamepad_axis_value(gamepad_id, gp_axislv);
    x += _h * 4;
    y += _v * 4;
}

在这里,我们正在检查 杆是否水平或垂直移动。轴函数返回一个介于 -1 和 1 之间的值,因此对于水平轴,-1 为左,0 不移动,1 为右,而对于垂直轴,它为 -1,表示向上,0 表示不移动,1 表示向下。还请注意,这些值介于 -1 和 1 之间,因此-例如-水平轴可能返回值 0.5,这意味着操纵杆处于 " 静止 " 位置的中间,并完全向右推。出于这个原因,我们将该值乘以 4( 实际上可以乘以任何值,具体取决于您希望实例移动的速度 )- 这意味着实例的速度将根据在杆轴上移动的程度而有所不同。

将该对象的一个实例放置在一个房间中,按下播放按钮Play Icon,然后使用连接的游戏板的左手柄四处移动。您应该会看到类似这样的内容:

Animation Showing Gamepad Movement

 

高级8向移动高级8向移动

在这个最后的例子中,我们将重新访问我们的8向移动代码,并解决它存在的一个问题,即对角线移动实际上比上/下/左/右移动更快。这只是因为当沿对角线移动时,您将沿着由 X/Y 移动值创建的直角三角形的斜边移动:

Image Showing Why Diagonal Movement Is Faster

为了更清楚地了解发生了什么,让我们删除所有文本和精灵,并简单地显示相同的移动线旋转 45°,因此它是水平的:

Simplified Image SHowing Diaginal Movement Is Faster

正如您所看到的,差异非常明显,如果实例每步移动超过1或2个像素,那么对角线移动就会变得非常明显!那么,我们如何限制这一点呢?有很多方法可以做到这一点,但我们将只关注其中的一种,因为它引入了几个函数和概念,这些函数和概念将在稍后的游戏中对您有用。

为了处理这个问题,我们将不得不将来自独立按下的键的输入值存储在变量中,然后检查它们并根据已经按下的键的组合进行移动。因此,您将需要一个分配了精灵的对象,并且需要为其提供一个带有以下操作或代码的步事件

GML VisualStep Event Actions To Define Movement Variables

注意 我们已将上面的可视操作拆分到两列中,以便于可视化,但在可视编辑器中,它将被连续放置。

var _left = keyboard_check(vk_left);
var _right = keyboard_check(vk_right);
var _up = keyboard_check(vk_up);
var _down = keyboard_check(vk_down);
var _hspd = _right - _left;
var _vspd = _down - _up;

我们需要添加更多代码才能实际移动,但在此之前,让我们先解释一下这一点。我们想要将左 / 右 / 上 / 下转换为相等的水平和垂直速度值,因此,我们得到每个关键点的值,然后对其进行一些基本数学运算,以获得速度值。这是因为如果一个键被按下,那么检查操作或函数将返回 "1",如果它 没有 被按下,则函数将返回 0。因此,例如,如果按下右键,则 "_hspd" 的值为 "1-0=1",如果按下左键,则 "_hspd" 的值为 "0-1=-1"( 如果同时按下这两个键,则为 "1-1=0",因此实例不会移动)。请记住,在 GameMaker 房间中,要向右移动,我们要添加到 x 位置,要向左移动,我们要减去。因此,此代码将为我们提供一个正值或负值,我们可以根据键盘输入进行相加或相减,以水平或垂直移动。

现在,我们可以添加实际移动实例的代码,因此-仍然在步事件中,在上面的代码之后-添加以下代码:

GML VisualStep Event Actions To Move The Instance

if (_hspd != 0 || _vspd != 0)
{
    var _spd = 4;
    var _dir = point_direction(0, 0, _hspd, _vspd);
    var _xadd = lengthdir_x(_spd, _dir);
    var _yadd = lengthdir_y(_spd, _dir);
    x = x + _xadd;
    y = y + _yadd;
}

上面的代码首先检查两个表达式中是否有一个为真,即水平或垂直速度变量是否不为0。请注意 "if" GML 检查如何使用符号 "||"。在编程时,这意味着 "",所以--用通俗易懂的语言--你是在检查

if the variable _hspd does not equal zero
or
if the variable _vspd does not equal zero

通过这种方式,您可以在 "if" 检查中将多个表达式串在一起,并且有多种不同的方法可以计算这些表达式(有关更多信息,请在此处参阅有关表达式的小节)。

代码的下一部分将 ;实际移动速度的值存储在一个变量中,然后使用 _hspd_vspd 值获得方向,这些值可以是 -1、0 或 1。方向函数检查 (0,0),因为我们没有使用房间坐标,而是希望根据变量值将其计算为从 0°到 360°的方向。下面的图表说明了正在发生的事情,而不是试图用语言来解释:

Example Image Showing Direction Around (0,0) Origin

注意GameMaker 中的方向是按逆时针计算的,所以 0° 和 360° 是向右,90° 是向上,180° 是向左,270° 是向下。

最后,我们使用 lengthdir_x()lengthdir_y() 函数来实际移动变量。这些是 向量 函数,它们获取长度 (距离) 和方向,然后根据这些值计算给定轴上的新位置 (有关更深入的说明,请参阅函数说明)。

这一次要理解的东西很多,如果你还不完全理解,也不要担心!你迟早会的!现在要做的就是将这个对象的一个实例添加到一个房间中,然后按下播放按钮Play Icon,您应该会得到丝滑的8向移动,而不会出现任何与对角移动相关的问题:

Animation Showing Improved 8-Way Keyboard Movement

 

有了这些例子 - 和之前的绘制 - 我们希望你有足够的理解来开始制作你自己的项目!本快速入门指南的最后一页包含您所学到的一些内容的摘要以及指向其他学习材料的链接。