godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
91.23k stars 21.22k forks source link

Jittery physics and random teleportation #73228

Open toxicrecker opened 1 year ago

toxicrecker commented 1 year ago

Godot version

4.0.rc1

System information

Windows 10, Forward+, GTX 1650 SUPER

Issue description

The physics are jittery and I experience random teleportations on this object picking system I created from a tutorial

https://user-images.githubusercontent.com/62395124/218495485-b653b9d7-f6b3-45a6-90b8-65fe27aa28d9.mp4

https://user-images.githubusercontent.com/62395124/218495491-e3a46ebc-b2f6-4614-8f9c-f009bc758e01.mp4

Here is the script:

extends CharacterBody3D

@export var speed: float = 5.0
@export var jump_velocity: float = 4.5
@export var sensitivity: float = 3
@export var pull_power: float = 10
#@export var rotation_power: float = 1

@onready var neck := $neck
@onready var camera := $neck/camera
@onready var hand := $neck/camera/hand
@onready var interaction := $neck/camera/interaction
@onready var joint := $neck/camera/joint
@onready var static_object := $neck/camera/static_object
var gravity: Variant = ProjectSettings.get_setting("physics/3d/default_gravity")
var picked_object: RigidBody3D
var locked: bool = false

func _unhandled_input(event):
    if event is InputEventMouse:
        Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
    elif event.is_action_pressed("ui_cancel"):
        Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
    if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
        if event is InputEventMouseMotion:
            neck.rotate_y(-event.relative.x * 0.001 * sensitivity)
            camera.rotate_x(-event.relative.y * 0.001 * sensitivity)
            camera.rotation.x = clamp(camera.rotation.x, deg_to_rad(-60), deg_to_rad(75))
            #if picked_object:
            #   static_object.rotate_x(deg_to_rad(event.relative.y * rotation_power))
            #   static_object.rotate_y(deg_to_rad(event.relative.x * rotation_power))

func _physics_process(delta):
    # Add the gravity.
    if not is_on_floor():
        velocity.y -= gravity * delta

    # Handle Jump.
    if Input.is_action_just_pressed("jump") and is_on_floor():
        velocity.y = jump_velocity

    # Get the input direction and handle the movement/deceleration.
    # As good practice, you should replace UI actions with custom gameplay actions.
    var input_dir: Vector2 = Input.get_vector("left", "right", "forward", "backward")
    var direction: Vector3 = (neck.transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
    if direction:
        velocity.x = direction.x * speed
        velocity.z = direction.z * speed
    else:
        velocity.x = move_toward(velocity.x, 0, speed)
        velocity.z = move_toward(velocity.z, 0, speed)

    if Input.is_action_just_pressed("use"):
        if picked_object:
            picked_object.set_linear_velocity(velocity)
            picked_object = null
            joint.set_node_b(joint.get_path())
        else:
            var collider = interaction.get_collider()
            if collider and collider is RigidBody3D:
                picked_object = collider
                joint.set_node_b(picked_object.get_path())
    if picked_object:
        var obj_origin: Vector3 = picked_object.global_position
        var target: Vector3 = hand.global_position
        picked_object.set_linear_velocity((target - obj_origin) * pull_power)

    move_and_slide()

Steps to reproduce

N/A

Minimal reproduction project

https://drive.google.com/file/d/1VmlvV8PlkvpRIBFsC1qRw-yzETUzKbwO/view?usp=share_link

toxicrecker commented 1 year ago

the issue still exists in rc2

Clonkex commented 1 year ago

Looking at the first video, it's expected that you should be flung into the air if you flick your screen around all over the place while holding the object. The object is taking the shortest path to the target location, so if you turn too quickly the shortest path will be through your character controller. This is a common problem regardless of the game engine. I believe the usual solution is to temporarily disable collision between the character controller and the held object, and then reenable it again when the object is dropped.

The glitch at 0:16 in the first video is strange, though. That could definitely be a physics engine bug.

As for the second video, it's very common for physics objects to jitter and bounce when you try to force them into another object, again regardless of game engine. The only question is whether it's jittering a reasonable amount.

toxicrecker commented 1 year ago

About the glitch, it definitely is a physics bug and about the jitter when I try to force it into ground, that is not an issue in Godot 3, that is not an issue for the first few seconds in Godot 4 either. For the first few seconds, everything works as expected but then gradually everything gets bugged out.

About being flung into air, I fixed that by adding the player as an exception to box's collisions.

toxicrecker commented 1 year ago

I think it'd be reasonable to add a bug label to this issue because I think this is something that should be fixed on priority. Pickable objects are not a rare thing to see in video games and if something like this can happen in this thing, it can happen with other physics related objects as well. But I don't know much about how Godot works so I'll leave that up to the maintainers to decide.

Calinou commented 1 year ago

I believe the usual solution is to temporarily disable collision between the character controller and the held object, and then reenable it again when the object is dropped.

To make this work more reliably, you can even disable collision for the dragged object entirely, and use a simple RayCast (or ShapeCast) to position it in the game world while the player is dragging it. Once the player is done dragging the object, reenable collision for it.