|
|
|
 |
Reply From: |
idletalent |
I found this question yesterday when I was searching for a solution to the same problem, and decided to leave this tab open in case I figured it out.
I’m no Godot expert, so this might not be the best way to do this, but it’s working for my use case, and might help you get where you want to be.
First I want to bring something about PathFollow to your attention. You say the problem is that it takes a scalar for its offset, which it does as unit_offset
, but there is also a property for its actual offset (just called offset
) which is as long as the path.
I’m also using get_closest_offset()
instead of get_closest_point()
because it will return something I think is easier to work with.
To solve the problem of converting the Player’s World Space to the Path’s Local Space to be able to use get_closest_offset()
, I made a Position3D as a child of the Path, called it follow_target
, then in _physics_process()
matched it’s global_transform.origin
to the player:
follow_target.global_transform.origin = player.global_transform.origin
Then I get the translation (i.e. local space) of the follow_target
and use that to get_closest_offset()
of the path.curve, and set it as the PathFollow’s offset.
path_follow.set_offset(path.curve.get_closest_offset(follow_target.get_translation()))
This works fine for straight paths, and probably works for linear paths that don’t double back on themselves, but if you have a horseshoe-shaped camera path (which I did), it can make the PathFollow rush from end to end (i.e. the player can be closest to the beginning of the path, then closest to the end of the path without passing through any of the intermediate points).
To solve this, I created a second path, which I called reference_path
, which is a straight line from the beginning to the end of the path I want to lock the camera to.
Then I use the above code to set the offset on the reference_path
, then copy the unit_offset
of the PathFollow on the reference_path
to the unit_offset
of the PathFollow on the camera_path
.
N.B. using unit_offset
for this part because the paths are different lengths, so their regular offsets won’t match up.
So that whole script keeps a PathFollow in the position I want the camera, and looks like this:
extends Spatial
onready var reference_path: = $ReferencePath
onready var reference_path_follow: = $ReferencePath/PathFollow
onready var path_follow: = $Path/PathFollow
onready var follow_target: = $Path/FollowTarget
onready var player = get_tree().get_nodes_in_group("player")[0]
func _physics_process(_delta: float) -> void:
follow_target.global_transform.origin = player.global_transform.origin
reference_path_follow.set_offset(reference_path.curve.get_closest_offset(follow_target.get_translation()))
path_follow.set_unit_offset(lerp(path_follow.unit_offset, reference_path_follow.get_unit_offset(), 1))
Then I pass the path_follow
to my CameraRig as rails_cam_position
, and in the _physics_process()
, I lerp from the camera_rig.global_transform.origin to the rails_cam_position.global_transform.origin
.
func physics_process(delta: float) -> void:
camera_rig.global_transform.origin = Vector3(lerp(camera_rig.global_transform.origin, camera_rig.rails_cam_position.global_transform.origin, 10 * delta)
My camera uses look_at()
to always face the player, so none of this code takes the path’s rotation into consideration, so if you get weird rotation issues, you’ll want to tinker with your PathFollow’s Rotation Mode settings, I guess.
I hope this is helpful 
This worked really well for me. Thanks!
jmtstorres | 2020-08-28 13:46