godotengine / godot

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

SpringArm Node Bug: Spring Arm ignores collision when 'spring_length' is being updated #48990

Open Riftwalkerparanoia opened 3 years ago

Riftwalkerparanoia commented 3 years ago

SpringArm Node Bug: Spring Arm ignores collision when _springlength is being updated

Godot version: Godot Engine v3.3.stable.offical

OS/device including version: W10 64bit // i7-4770k @ 3.50GHz // 8gig DDR3 ram // RTX 3060ti

Godot Files: Springarm Issue.zip

Issue wright up:

I am having an issue with the Spring Arm Node when trying to use it as a 3D camera arm. My camera is set up to be able to lerp between two, technically three, positions during gameplay; Distant free view and Over the shoulder view. I'm taking inspiration form MGSV if that can give you an idea. The problem is when I update the arm length, it ignores the collision of any object it collides with.

Node order: image

Footage: Please excuse the jittery video, the source doesn't have this problem but viewing it on WEB is weird

https://user-images.githubusercontent.com/7089869/119253361-c53afb00-bb65-11eb-95e8-4e62471dcca4.mp4

When you see the spring arm working, i.e. not going through the floor, it's because _springlength is not being updated but when it is going through the floor, the arm is interpolating between positions

Here's the Code:

extends Camera

export(NodePath) onready var arm = get_node( arm )
export(NodePath) onready var piv = get_node( piv )

                                                   # Points to where the camera is interpolating between
export(Vector3) var camera_zoom_offset : Vector3 = Vector3( 0.7,  0.5,  3.0)
export(Vector3) var camera_free_offset : Vector3 = Vector3( 0.0,  0.0,  7.0)

export( float ) var sensitivity        : float   = 5.0
export(Vector2) var vertical_clamp     : Vector2 = Vector2(deg2rad(-50), deg2rad(30))

var cam_pos : Vector3 = Vector3()

#-------------------------------------------------------------------------------

func _process(delta: float) -> void:
    _aim_camera(delta)

func _input(event: InputEvent) -> void:
    _cam_in(event)

#-------------------------------------------------------------------------------

func _aim_camera(delta):
    var to_vec : Vector3 # stores the target vector; where the camera is going

    if Input.is_action_pressed("aim"):                    # Triggers the camera to move over the players shoulder 
        if Input.is_action_just_pressed("aim_switch"):
            camera_zoom_offset.x *= -1                    # Switches which shoulder the camera is looking over

        cam_pos = lerp(cam_pos, camera_zoom_offset, delta * 7) # Interpolates between current position and to a target pos
        to_vec = camera_zoom_offset   # used to stop the arm distance from changing, you'll see

    else:                                                          # If we are not aiming; not in shoulder view
        cam_pos = lerp(cam_pos, camera_free_offset, delta * 5) # Interpolates between pos to pos
        to_vec = camera_free_offset                            # Again, set up to be used later

        if ((cam_pos - camera_free_offset).length() < 0.02):# rounds up the lerp to make stopping updating the arm length...
            cam_pos = camera_free_offset                # ... just a bit easier and faster

    if ((cam_pos - to_vec).length() != 0):     # If the camera / arm length is still changing, don't stop updating
                                               # Else don't update the arm length if it's not changing
        transform.origin  = cam_pos            # This is where in the video you see it working until it starts in
        arm.spring_length = transform.origin.z # ... interpolating between positions

func _cam_in(event):                             # This is where I control the camera
    if event is InputEventMouseMotion:           # I'm not going to go into detail hear
        var mouse : Vector2 = -GlobalInput.Mouse(sensitivity, event)   # made a global script to make the syntax less bulky 
        piv.rotate_y( deg2rad( mouse.x ) )    
        arm.rotate_x( deg2rad( mouse.y ) ) 
        arm.rotation.x = clamp(arm.rotation.x, vertical_clamp.x, vertical_clamp.y)`

#------------------------------------------------------------------------------------------------------------------------------------------

# This is from my global input script and apply to the _cam_in function ^^^

func Mouse(sensitivity:float=1,event=InputEventMouseMotion) -> Vector2:
    var mouseDir = Vector2(event.relative.x, event.relative.y) # Note: always Add 'event' When calling from another script
    mouseDir * sensitivity * get_process_delta_time()
    return mouseDirextends Camera

Edits made for better formatting.

madmiraal commented 3 years ago

@Riftwalkerparanoia, please provide a minimal reproduction project as per the issue template.

Riftwalkerparanoia commented 3 years ago

@Riftwalkerparanoia, please provide a minimal reproduction project as per the issue template.

Sorry about that, The zip is now at the top of the original post

CarlosRios commented 2 years ago

I can confirm that the same issue is going on in my project using the latest build as of now. Dynamically updating the length of the SpringArm seems to cause the issue

Calinou commented 2 years ago

using the latest build as of now

Which exact Godot version are you using? "latest" is a moving target :slightly_smiling_face:

duchainer commented 2 years ago

That would be 49ac05550e4ce3b3489fad0a2addd907af1f5898 for me too.

Vivraan commented 1 year ago

Has this issue been resolved yet?

Zireael07 commented 1 year ago

@Vivraan It's open, so no. And plz don't spam identical comments on related issues

Vivraan commented 1 year ago

I am concerned as there is a similar issue I am facing while working with spring arm 3D where it clips through geometry still.

andzejsp commented 11 months ago

Still happening for me too without adjusting the length of the arm.

kyushu commented 8 months ago

I have this issue with Godot 4.2.1, spring arm doesn't collide with wall if character is too close to the wall