Context-based steering - i'm so close!

4.3.stable.official

A physics process in another script constantly runs update_target_position through a group call and sets the Vector3 “go” to our target position, thats plugged into the context array, and my dude freaks out. sometimes it snakes around in big circles, other times gets stuck on the wall its supposed to avoid, and on a rare occasion actually makes it where it’s supposed to go. It’s kind of doing what it’s supposed to sometimes, but clearly something about this is very wrong, and i have no idea what. the actual movement script, what comes after choose_direction() in the physics process, works fine when a static coordinate is plugged into it, suggesting that the issue is in the arrays. problem is, as far as i can tell, those work correctly too, according to debug

var ray_directions : PackedVector3Array = []
var interest = []
var danger = []
@export var look_ahead = 4 # The length of the rays, ive fiddled with this number a lot with no results
@export var num_rays = 8
var chosen_dir = Vector3.ZERO
var go = Vector3.ZERO

func _ready():
	interest.resize(num_rays)
	danger.resize(num_rays)
	ray_directions.resize(num_rays)
	for i in num_rays:
		var angle = i * 2 * PI / num_rays
		ray_directions.set(i, Vector3.FORWARD.rotated(Vector3.UP, angle))

func update_target_position(target_position) -> void: 
# This target position is the position of my click, set by a group call from another script
	go = target_position - global_position
	go = go.normalized()

func _physics_process(delta):
	# Populate context arrays
	set_interest()
	set_danger()
	choose_direction()
		var current_direction = -global_transform.basis.z # Get current forward direction (assuming character faces -Z) # Get direction to target (ignoring Y axis)
	 # Get direction to target (ignoring Y axis)
	var to_target = chosen_dir - global_position.normalized()
	to_target.y = 0 # Ignore height difference
	# Calculate the angle difference
	var target_direction = to_target.normalized()
	# Get the angle between current direction and target direction
	var angle_to_target = current_direction.signed_angle_to(target_direction, Vector3.UP)
	if angle_to_target != 0: # If we're not rotated enough
		if current_steer < max_steer: # Accelerate steering
			current_steer += steer_accel * delta
	else: # If we are rotated enough
		current_steer = 0
	# Calculate rotation step for this frame
	var turn_step = current_steer * delta
	# Clamp the rotation to be no more than what we need
	turn_step = min(abs(angle_to_target), turn_step) * sign(angle_to_target)
	# Apply the rotation
	rotate_y(turn_step)
	# Move forward
	if current_velocity < max_speed:
		current_velocity += accel * delta
	velocity = -global_transform.basis.z * current_velocity
	velocity.y = 0.0
	move_and_collide(velocity)


func set_interest():
	for i in num_rays: # This seems to set interest correctly
		var d = ray_directions[i].normalized().dot(go)
		interest[i] = d

func set_danger():
	var space_state = get_world_3d().direct_space_state
	for i in num_rays: #shoot some rays
		var query = PhysicsRayQueryParameters3D.create(position, position + ray_directions[i] * look_ahead)
		query.exclude = [self]
		var result = space_state.intersect_ray(query)
		danger[i] = 5 if result else 0 # in debug the danger array returns a 5 in the direction of the wall its running against so this works

func choose_direction():
	for i in num_rays:
		interest[i] = interest[i] - danger[i]
	chosen_dir = Vector3.ZERO
	for i in num_rays:
		chosen_dir += ray_directions[i] * interest[i]
		chosen_dir = chosen_dir.normalized()

It’s a big chunk, so thanks a lot if you do decide to take a look at it