监听玩家的输入

在上一课 创建第一个脚本 的基础上,让我们看看任何游戏的另一个重要特征:将控制权交给玩家。为了增加这一点,我们需要修改 sprite_2d.gd 的代码。

../../_images/scripting_first_script_moving_with_input.gif

在 Godot 中,你有两个主要工具来处理玩家的输入:

  1. 内置的输入回调,主要是 _unhandled_input()。和 _process()一样 ,它是一个内置的虚函数,Godot 每次在玩家按下一个键时都会调用。它是你想用来对那些不是每一帧都发生的事件做出反应的工具,比如按 Space 来跳跃。要了解更多关于输入回调的信息,请参阅 使用 InputEvent

  2. Input 单例。单例是一个全局可访问的对象。Godot 在脚本中提供对几个对象的访问。它是每一帧检查输入的有效工具。

我们这里将使用 Input 单例,因为我们需要知道在每一帧中玩家是否想转身或者移动。

对于转弯,我们应该使用一个新的变量:direction。在我们的 _process() 函数中,将 rotation += angular_speed * delta 替换成以下代码。

GDScriptC#

  1. var direction = 0
  2. if Input.is_action_pressed("ui_left"):
  3. direction = -1
  4. if Input.is_action_pressed("ui_right"):
  5. direction = 1
  6. rotation += angular_speed * direction * delta
  1. var direction = 0;
  2. if (Input.IsActionPressed("ui_left"))
  3. {
  4. direction = -1;
  5. }
  6. if (Input.IsActionPressed("ui_right"))
  7. {
  8. direction = 1;
  9. }
  10. Rotation += _angularSpeed * direction * (float)delta;

我们的 direction 局部变量是一个乘数,代表玩家想要转向的方向。0 的值表示玩家没有按左或右方向键。1 表示玩家想向右转,而 -1 表示他们想向左转。

为了产生这些值,我们引入了条件和 Input 的使用。条件以 GDScript 中的 if 关键字开始,以冒号结束。条件是关键字和行末之间的表达式。

为了检查当前帧玩家是否按下了某个键,我们需要调用 Input.is_action_pressed()。这个方法使用一个字符串来表示一个输入动作。当该按键被按下时,函数返回 true,否则这个函数将返回 false

上面我们使用的两个动作,“ui_left”和“ui_right”,是每个 Godot 项目中预定义的。它们分别在玩家按键盘上的左右箭头或游戏手柄上的左右键时触发。

备注

打开“项目 -> 项目设置”并点击“输入映射”选项卡,就可以查看并编辑项目中的输入动作。

最后,当我们更新节点的 rotation 时,我们使用 direction 作为乘数:rotation += angular_speed * direction * delta

``var velocity = Vector2.UP.rotated(rotation) * speed``和``position += velocity * delta``两行代码注释,像这样:

GDScriptC#

  1. #var velocity = Vector2.UP.rotated(rotation) * speed
  2. #position += velocity * delta
  1. //var velocity = Vector2.Up.Rotated(Rotation) * _speed;
  2. //Position += velocity * (float)delta;

这将忽略在没有用户输入的情况下在圆中移动图标位置的代码。

如果你用这段代码运行场景,当你按下 Left(左方向键)和 Right(右方向键) 时,图标应该会旋转。

按“上”时移动

为了只在按键时移动,我们需要修改计算速度的代码。取消注释代码,并将以 var velocity 开头的行替换为下面的代码。

GDScriptC#

  1. var velocity = Vector2.ZERO
  2. if Input.is_action_pressed("ui_up"):
  3. velocity = Vector2.UP.rotated(rotation) * speed
  1. var velocity = Vector2.Zero;
  2. if (Input.IsActionPressed("ui_up"))
  3. {
  4. velocity = Vector2.Up.Rotated(Rotation) * _speed;
  5. }

我们将 velocity 的值初始化为 Vector2.ZERO,这是内置 Vector 类型的一个常量,代表长度为 0 的二维向量。

如果玩家按下“ui_up”动作,我们就会更新速度的值,使精灵向前移动。

完整脚本

这是完整的 sprite_2d.gd 文件,仅供参考。

GDScriptC#

  1. extends Sprite2D
  2. var speed = 400
  3. var angular_speed = PI
  4. func _process(delta):
  5. var direction = 0
  6. if Input.is_action_pressed("ui_left"):
  7. direction = -1
  8. if Input.is_action_pressed("ui_right"):
  9. direction = 1
  10. rotation += angular_speed * direction * delta
  11. var velocity = Vector2.ZERO
  12. if Input.is_action_pressed("ui_up"):
  13. velocity = Vector2.UP.rotated(rotation) * speed
  14. position += velocity * delta
  1. using Godot;
  2. public partial class MySprite2D : Sprite2D
  3. {
  4. private float _speed = 400;
  5. private float _angularSpeed = Mathf.Pi;
  6. public override void _Process(double delta)
  7. {
  8. var direction = 0;
  9. if (Input.IsActionPressed("ui_left"))
  10. {
  11. direction = -1;
  12. }
  13. if (Input.IsActionPressed("ui_right"))
  14. {
  15. direction = 1;
  16. }
  17. Rotation += _angularSpeed * direction * (float)delta;
  18. var velocity = Vector2.Zero;
  19. if (Input.IsActionPressed("ui_up"))
  20. {
  21. velocity = Vector2.Up.Rotated(Rotation) * _speed;
  22. }
  23. Position += velocity * (float)delta;
  24. }
  25. }

如果你运行这个场景,你现在应该能够用左右方向键进行旋转,并通过按 Up 向前移动。

../../_images/scripting_first_script_moving_with_input.gif

总结

总之,Godot中的每个脚本都代表一个类,并扩展了引擎的一个内置类。在我们sprite的例子中,你的类所继承的节点类型可以让你访问一些属性,例如在“精灵” 例子中的 rotationposition 。你还继承了许多函数,但我们在这个例子中没有使用这些函数。

在 GDScript 中,放在文件顶部的变量是类的属性,也称为成员变量。除了变量之外,你还可以定义函数,在大多数情况下,这些函数将是类的方法。

Godot 提供了几个虚函数,你可以定义这些函数来将类与引擎连接起来。其中包括 _process() ,用于每帧将更改应用于节点,以及 _unhandled_input() ,用于接收用户的输入事件,如按键和按钮。还有很多。

Input 单例允许你在代码中的任何位置对玩家的输入做出反应。 尤其是,你在 _process() 循环中使用它。

在下一课 使用信号 中,我们会让节点触发脚本中的代码,让脚本和代码之间产生联系。