ramokz / phantom-camera

👻🎥 Control the movement and dynamically tween 2D & 3D cameras. Built for Godot 4. Inspired by Cinemachine.
https://phantom-camera.dev/
MIT License
1.97k stars 65 forks source link

Initial setup for `_follow_spring_arm_node` is delayed for first time assignment of `Properties.follow_target_node` #193

Closed ZenithStar closed 1 month ago

ZenithStar commented 6 months ago

Issue description

When in ThirdPersonFollow mode and follow_target is assigned to something non-null for the first time, the initial setup for _follow_spring_arm_node is triggered, but not until the next _process tick of the PhantomCamera3D. # The default behavior is for the spring arm orientation to be initialized to the orientation of the PhantomCamera3D, however, I would like for it to initialize to the orientation of the follow_target that was just assigned. If I try to set it immediately after I assign follow_target (pcam._follow_spring_arm_node.basis = pcam.get_follow_target_node().global_basis), the initialization code inside PhantomCamera3D._process will overwrite it on the next process tick.

This is only a problem for the first assignment of follow_target. Subsequent assignments will not trigger the initialization code and so I can immediately set the orientation of the spring arm. Currently, a simple workaround for my use case is to add a small delay so that _process can tick once before I assign the orientation:

if not pcam.get_parent() == pcam._follow_spring_arm_node:
    get_tree().create_timer(0.01).timeout.connect(func(): pcam._follow_spring_arm_node.basis = pcam.get_follow_target_node().global_basis )
else:
    pcam._follow_spring_arm_node.basis = pcam.get_follow_target_node().global_basis

IMO, the best solution would be to take any initialization code out of _process and instead trigger it from its own function when conditions for initialization have been met.

Steps to reproduce

  1. Create a scene with a PhantomCamera3D in Follow Mode: Third Person without assigning a follow target.
  2. Assign a follow target and immediately try to pcam.set_third_person_rotation. This assignment will apply, but will be immediately overwritten.
eliaskowitz commented 5 months ago

i ran into the same issue of needing to initialize some properties of the third person spring_arm on ready and it not working. instead of a using a timer i added a signal to the phantom camera that emits after it reparents the spring_arm. that seemed to work for my use case and it might work for yours. i don't know if its a good solution over all or not though

ramokz commented 2 months ago

Is this still an issue in 0.7?

ZenithStar commented 2 months ago

Yes. I didn't realized it when I made this change, but there's still initialization code inside PhantomCamera3D._process Moving the rest of the initialization code into _ready() allows for me to change the workaround code from

if not pcam.get_parent() == pcam._follow_spring_arm:
    get_tree().create_timer(0.01).timeout.connect(func(): pcam._follow_spring_arm.basis = pcam.follow_target.global_basis )
else:
    pcam._follow_spring_arm.basis = pcam.follow_target.global_basis

into

pcam._follow_spring_arm.set.call_deferred("basis", pcam.follow_target.global_basis)
ramokz commented 2 months ago

Can see you're assigning a basis value to the springarm node, would adding a setter function to the addon script make that easier?