Work in progress
The content of this page was not yet updated for Godot
4.2
and may be outdated. If you know how to improve this page or you can confirm
that it's up to date, feel free to open a pull request.
使用代码移动玩家¶
该轮到编写代码了!我们将使用先前创建的输入动作来移动角色。
右键单击 Player
节点,选择附加脚本为其添加一个新脚本。在弹出窗口中,先将模板设置为 空,后按下创建按钮 。
先定义类的属性。我们将定义移动速率(标量)、重力加速度,以及一个我们将用来移动角色的速度(向量)。
extends CharacterBody3D
# How fast the player moves in meters per second.
@export var speed = 14
# The downward acceleration when in the air, in meters per second squared.
@export var fall_acceleration = 75
var target_velocity = Vector3.ZERO
using Godot;
public partial class Player : CharacterBody3D
{
// Don't forget to rebuild the project so the editor knows about the new export variable.
// How fast the player moves in meters per second.
[Export]
public int Speed { get; set; } = 14;
// The downward acceleration when in the air, in meters per second squared.
[Export]
public int FallAcceleration { get; set; } = 75;
private Vector3 _targetVelocity = Vector3.Zero;
}
这是一个移动物体的常见属性。 target_velocity
是一个组合了速度和方向的 3D 向量。在这里,我们将其定义为属性,因为我们希望在帧之间更新并重用其值。
备注
这些值与二维代码完全不同,因为距离以米为单位。在 2D 中,一千个单位(像素)可能只对应于屏幕宽度的一半,而在 3D 中,它是一千米。
那么来编写移动的代码。首先在 _physics_process()
中使用全局 Input
对象来计算输入方向向量。
func _physics_process(delta):
# We create a local variable to store the input direction.
var direction = Vector3.ZERO
# We check for each move input and update the direction accordingly.
if Input.is_action_pressed("move_right"):
direction.x += 1
if Input.is_action_pressed("move_left"):
direction.x -= 1
if Input.is_action_pressed("move_back"):
# Notice how we are working with the vector's x and z axes.
# In 3D, the XZ plane is the ground plane.
direction.z += 1
if Input.is_action_pressed("move_forward"):
direction.z -= 1
public override void _PhysicsProcess(double delta)
{
// We create a local variable to store the input direction.
var direction = Vector3.Zero;
// We check for each move input and update the direction accordingly.
if (Input.IsActionPressed("move_right"))
{
direction.X += 1.0f;
}
if (Input.IsActionPressed("move_left"))
{
direction.X -= 1.0f;
}
if (Input.IsActionPressed("move_back"))
{
// Notice how we are working with the vector's X and Z axes.
// In 3D, the XZ plane is the ground plane.
direction.Z += 1.0f;
}
if (Input.IsActionPressed("move_forward"))
{
direction.Z -= 1.0f;
}
}
在这里,我们将使用 _physics_process()
虚函数进行所有计算。与 _process()
一样,它允许你每帧更新节点,但它是专门为物理相关代码设计的,例如运动学物体或刚体。
参见
要了解更多关于 _process()
和 _physics_process()
之间的区别,见 空闲处理与物理处理。
我们首先将一个 direction
变量初始化为 Vector3.ZERO
。然后,我们检查玩家是否正在按下一个或多个 move_*
输入,并相应地更新矢量的 x
和 z
分量。它们对应于地平面的轴。
这四个条件给了我们八个可能性和八个可能的方向。
In case the player presses, say, both W and D simultaneously, the vector will
have a length of about 1.4
. But if they press a single key, it will have a
length of 1
. We want the vector's length to be consistent, and not move faster diagonally. To do so, we can
call its normalized()
method.
#func _physics_process(delta):
#...
if direction != Vector3.ZERO:
direction = direction.normalized()
$Pivot.look_at(position + direction, Vector3.UP)
public override void _PhysicsProcess(double delta)
{
// ...
if (direction != Vector3.Zero)
{
direction = direction.Normalized();
GetNode<Node3D>("Pivot").LookAt(Position + direction, Vector3.Up);
}
}
在这里,我们只在方向的长度大于零的情况下对向量进行归一化,因为玩家正在按某个方向键。
在这种情况下,我们也会得到 Pivot 节点并调用其 look_at()
方法。该方法接受一个全局坐标系中要注视的空间位置和上方向。在这种情况下,我们可以使用 Vector3.UP
常量。
备注
节点的局部坐标,如 position
,是相对于它们的父节点而言的。全局坐标,比如 global_position
,是相对于你在视口中可以看到的世界主轴而言的。
在 3D 中,包含节点位置的属性是 position
。加上 direction
之后,我们就得到了离 Player 一米远的观察位置。
然后,更新速度。需要分别计算地面速度和下降速度。请确保 tab 缩进,使行在 _physics_process()
函数内部,而不在刚编写的条件外部。
func _physics_process(delta):
#...
if direction != Vector3.ZERO:
#...
# Ground Velocity
target_velocity.x = direction.x * speed
target_velocity.z = direction.z * speed
# Vertical Velocity
if not is_on_floor(): # If in the air, fall towards the floor. Literally gravity
target_velocity.y = target_velocity.y - (fall_acceleration * delta)
# Moving the Character
velocity = target_velocity
move_and_slide()
public override void _PhysicsProcess(double delta)
{
// ...
if (direction != Vector3.Zero)
{
// ...
}
// Ground velocity
_targetVelocity.X = direction.X * Speed;
_targetVelocity.Z = direction.Z * Speed;
// Vertical velocity
if (!IsOnFloor()) // If in the air, fall towards the floor. Literally gravity
{
_targetVelocity.