Захват и перемещение с помощью мыши

Проблема

Вы хотите захватывать и перемещать твердые тела с помощью мыши.

Решение

Работа с твердыми телами может быть непростой. Движением таких тел управляет физический движок Godot, и вмешательство в этот процесс часто приводит к неожиданным результатам. Ключевой момент — использование свойства mode тела. Это применимо как в 2D, так и в 3D.

Настройка тела

Начнем с создания объекта твердого тела, добавив Sprite2D и CollisionShape2D. При необходимости можно добавить PhysicsMaterial, чтобы задать свойства отскока и трения.

Мы будем использовать свойство freeze твердого тела, чтобы временно вывести его из-под контроля физического движка во время перетаскивания. Поскольку мы хотим, чтобы тело оставалось подвижным, нужно установить Freeze Mode в значение Kinematic вместо стандартного Static.

Поместите тело в группу с именем pickable. Это позволит использовать несколько экземпляров перетаскиваемых объектов в основной сцене. Присоедините скрипт к телу и подключите его сигнал _input_event.

extends RigidBody2D

signal clicked

var held = false

func _on_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if event.pressed:
            print("clicked")
            clicked.emit(self)

Мы будем отправлять сигнал при обнаружении клика мышью, включая ссылку на тело. Поскольку тел может быть много, основная сцена будет управлять тем, можно ли перетаскивать тело или если уже есть тело в состоянии удержания.

Если тело перетаскивается, мы обновляем его позицию, чтобы оно следовало за курсором мыши.

func _physics_process(delta):
    if held:
        global_transform.origin = get_global_mouse_position()

Наконец, вот две функции, которые вызываются при поднятии и отпускании тела. Установка freeze в true исключает тело из обработки физическим движком. Обратите внимание, что другие объекты все еще могут сталкиваться с ним. Если это не нужно, можно отключить collision_layer и/или collision_mask. Не забудьте включить их обратно при отпускании.

func pickup():
    if held:
        return
    freeze = true
    held = true

func drop(impulse=Vector2.ZERO):
    if held:
        freeze = false
        apply_central_impulse(impulse)
        held = false

В функции отпускания, после возврата freeze в false, тело снова переходит под контроль физического движка. Передавая необязательное значение импульса, мы можем добавить возможность «бросать» объект при отпускании.

Основная сцена

Создайте основную сцену с несколькими статичными препятствиями или TileMap и добавьте несколько экземпляров перетаскиваемого тела.

Вот скрипт для основной сцены. Начнем с подключения сигнала clicked для всех перетаскиваемых тел в сцене.

extends Node2D

var held_object = null

func _ready():
    for node in get_tree().get_nodes_in_group("pickable"):
        node.clicked.connect(_on_pickable_clicked)

Затем идет функция, к которой подключается сигнал. Эта функция устанавливает held_object, чтобы отслеживать текущее перетаскиваемое тело, и вызывает метод pickup() тела.

func _on_pickable_clicked(object):
    if !held_object:
        object.pickup()
        held_object = object

Наконец, при отпускании мыши во время перетаскивания выполняем обратные действия.

func _unhandled_input(event):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
        if held_object and !event.pressed:
            held_object.drop(Input.get_last_mouse_velocity())
            held_object = null

Обратите внимание на использование get_last_mouse_velocity() для передачи импульса объекту — будьте осторожны! Вы можете случайно запустить тела на высокой скорости, особенно если у них небольшая масса. Рекомендуется масштабировать это значение до разумного и ограничить его с помощью clamp(). Экспериментируйте, чтобы найти подходящие значения.

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

восемь − 6 =

Прокрутить вверх