Перемещение в 2D пространстве

Введение

Каждый новичок задаётся вопросом: "Как я могу перемещать свой персонаж?". В зависимости от стиля игры, у тебя могут быть специальные требования, но в основном перемещения в большинстве 2D игр основаны на небольшом числе различных способов.

Для этих примеров мы будем использовать CharacterBody2D, но принципы будут применимы и к другим типам узлов (Area2D, Rigidbody2D).

Настройка

Каждый из примеров показанных ниже использует одинаковые настройки сцены. Начинайте с добавления CharacterBody2D с двумя дочерними узлами: Sprite2D и CollisionShape2D. Вы можете использовать иконку Godot ("icon.png") в качестве текстуры спрайта или воспользоваться любой другой 2D картинкой которая имеется.

Откройте Проект -> Настройки проекта и выберите вкладку "Список действий". Добавьте следующие действия (для справки InputEvent):

../../_images/movement_inputs.webp

8-стороннее движение

В этом примере мы хотим, чтобы игрок использовал четыре клавиши для выбора движения в заданном направлении (клавиши - стрелки: вверх/влево/вниз/вправо или W/A/S/D). Термин 8 - позиционное перемещение исходит из факта, что игрок может перемещаться по диагонали удерживая одновременно две клавиши.

Добавьте скрипт к телу персонажа, а затем добавьте следующий код:

extends CharacterBody2D

@export var speed = 400

func get_input():
    var input_direction = Input.get_vector("left", "right", "up", "down")
    velocity = input_direction * speed

func _physics_process(delta):
    get_input()
    move_and_slide()

В функции get_input() мы используем Input get_vector() для проверки четырех ключевых событий и возврата суммы в виде вектора направления.

Тога мы сможем установить скорость умножением этого вектора направления, который имеет длину 1, на нашу желаемую скорость.

Совет

Если вы никогда прежде не использовали векторную алгебру, или желаете освежить память, то можете посмотреть применение векторной алгебры в Godot Векторная математика.

Примечание

Если код выше ничего не делает при нажатии клавиш, проверьте заново установки входных действий как описано в Настройка части этого урока.

Вращение + перемещение

Этот стиль движения иногда называют "Астероид-стиль" потому что он похож на классическую аркадную игру. Нажатие влево/вправо вращает персонаж, вверх/вниз перемещает его вперёд или назад по направления персонажа.

extends CharacterBody2D

@export var speed = 400
@export var rotation_speed = 1.5

var rotation_direction = 0

func get_input():
    rotation_direction = Input.get_axis("left", "right")
    velocity = transform.x * Input.get_axis("down", "up") * speed

func _physics_process(delta):
    get_input()
    rotation += rotation_direction * rotation_speed * delta
    move_and_slide()

Здесь мы добавили две переменные для отслеживания направления и скорости вращения. Вращение применяется напрямую к свойству rotation тела.

Чтобы задать скорость, мы используем transform.x тела, который является вектором, указывающим в направлении «вперед» тела, и умножаем его на скорость.

Вращение + перемещение с помощью мыши

Этот стиль перемещения - вариация предыдущего. Сейчас направление устанавливается перемещением мыши а не клавиатурой. Благодаря функции "look at", персонаж будет всегда смотреть на курсор мыши. Перемещения вперёд/назад остаются прежними.

extends CharacterBody2D

@export var speed = 400

func get_input():
    look_at(get_global_mouse_position())
    velocity = transform.x * Input.get_axis("down", "up") * speed

func _physics_process(delta):
    get_input()
    move_and_slide()

Здесь мы используем метод Node2D look_at(), чтобы указать игроку на позицию мыши. Без этой функции можно получить тот же эффект, установив угол примерно так:

rotation = get_global_mouse_position().angle_to_point(position)

Нажми и двигайся

В последнем примере для перемещения персонажа используется только мышь. Нажатие на экран заставит игрока двигаться в указанном направлении.

extends CharacterBody2D

@export var speed = 400

var target = position

func _input(event):
    # Use is_action_pressed to only accept single taps as input instead of mouse drags.
    if event.is_action_pressed(&"click"):
        target = get_global_mouse_position()

func _physics_process(delta):
    velocity = position.direction_to(target) * speed
    # look_at(target)
    if position.distance_to(target) > 10:
        move_and_slide()

Заметьте проверку``distance_to()``, которую мы выполняем перед перемещением. Без этого теста, тела может начать дрожать пытаясь достичь заданной позиции, так как оно может её проскакивать при перемещении и пытаться вернуться назад, снова её проскакивая.

Если убрать комментарий для look_at(), то тело будет еще и смотреть в том направлении, куда двигается.

Совет

Этот приём ещё может использоваться как основа для "следящего" персонажа. Позицией цели может быть любой объект в направлении которого вы хотите перемещаться.

Подведение итогов

Вы можете найти эти примеры полезными как основа для вашего проекта. Не стесняйтесь использовать их и экспериментировать с ними, чтобы увидеть, что вы можете сделать.

Вы можете загрузить проект примера здесь: 2d_movement_starter.zip