Searching for the best path-switching solution
Asked Answered
P

1

0

Hi ! We are building an endless runner set in a mazy city where the player can take many different routes. The path-following script which controls player direction is based off the get_closest_offset() function and seems to be running well. Our concern is the path-switching method to use to switch smoothly between different paths : as newcomers to the Godot engine AND programming, we are still trying different solutions without knowing which one would be the most suitable for a more fully-featured environment.
Using Godot 3.5.2

Current solutions :

1) A path-finder area in the player scene gets the path child of a path-switching area it comes across (code below), it's really prone to bug and need to be carefuly set in the engine

2) A larger path-switching area with two paths as exported variables compare the player distance from each of the paths closest offsets and interpolates player direction until it leaves the area (not written yet)
(possible setup, with the same paths as in the previous picture)

3) A navigation map ? We haven't used it before but it might be a suitable solution

So the question is, are there better solutions to achieve this, maybe without having to manually set path-switching areas, or even curved paths, again maybe with NavigationMaps ?

Here are the parts of the script for the first solution:
(The path script is based on the path-based-movement-demo (https://github.com/Pyxus/path-based-movement-demo) written by Pyxus.)

Player script

var h_input: float
var direction := Vector3.ZERO
var velocity := Vector3.ZERO

# Get the starting area child path
onready var current_path = get_new_path(get_node(starting_area))

func _physics_process(delta):
	# Interpolates between the old and new path
	var previous_direction = path_direction
	if path_inertia < 20.0:
		path_inertia += 0.1
	path_direction = get_path_direction(current_path, previous_direction, path_inertia)

	var look_at_target = translation + path_direction.rotated(Vector3.UP, PI * 2)
	if translation != look_at_target:
		look_at(look_at_target, Vector3.UP)

	direction = path_direction

	# Get input for lateral movement
	h_input = lerp(h_input,
		Input.get_action_strength("move_right")
		- Input.get_action_strength("move_left"), acceleration * delta
		)
	direction += h_input * transform.basis.x

	velocity = lerp(velocity, direction.normalized() * speed, acceleration * delta)

	velocity = move_and_slide_with_snap(velocity, snap, Vector3.UP)


#An area in the player scene detects path_switcher areas and get its child path as its current path
func _on_PathFinder_area_entered(area: Area) -> void:
	path_inertia = 1.0
	if get_new_path(area) != null:
		current_path = get_new_path(area)

Base class the player class extends

class_name KinematicPathTraveller
extends KinematicBody

const NEXT_POINT_OFFSET: float = 0.01
const INERTIA: float = 1.0

# Path-following script
func get_path_direction(path, previous_direction, inertia) -> Vector3:
	var closest_offset = path.curve.get_closest_offset(path.to_local(transform.origin))

	var point_a = path.curve.interpolate_baked(closest_offset)
	var point_b = path.curve.interpolate_baked(closest_offset + NEXT_POINT_OFFSET)

	var path_direction = lerp(previous_direction, point_a.direction_to(point_b), inertia * get_physics_process_delta_time())
	return path_direction

func get_new_path(area) -> Path:
	var new_path: Path
	for child in area.get_children():
		if child is Path:
			new_path = child
	return new_path
Packard answered 16/10, 2023 at 13:37 Comment(0)
A
0

Packard Iterate each frame through all nearby paths and see if their closest points are in range. If yes, determine for each such point at which side of the current path it is. Change the position to that nearest point if command to switch to a particular side was just pressed. This way you don't have to use areas at all, just a little bit of space partitioning so you iterate through as few paths as possible.
Once you implement abrupt switching it will be easy enough to animate a transition, either by manually lerping on a tween.

Algar answered 16/10, 2023 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.