Help figuring out an aim assist system with a controller

Godot Version

4.6.1

Question

Ive gotten this far with trying to create an autoaim system for the player. Once Ive gotten the closest target, how do I make the play look that way? I want the player to look that way the moment I hit aim and be able to rotate afterwards like how the autoaim in resident evil 1 (the DS version) works.

	elif aim and is_on_floor():
		move_speed = 0.0
		rotation_speed = 5.0
		can_shoot = true
		aiming = true
		# auto aim
		_look.get_closest()
		var _closest_target = _look.get_closest()
		if _closest_target == CharacterBody3D and _closest_target.damagable and aiming:
			rotation.y = move_toward(rotation.y, _closest_target.position.y, 1.0)

You can use Node3D::look_at().

1 Like

How is this used though? cause when I tried it before, it made the player go crazy.

like, if my target is _closest*_*target, would it be look_at(_closest_target)?

Should be look_at(closest_target.global_position)

3 Likes
	# auto aim
	_look.get_closest()
	var _closest_target = _look.get_closest()
	if _closest_target is CharacterBody3D and _closest_target.damagable and aiming:
		look_at(_closest_target.global_position)

It still doesnt do anything at all. If I remove the if “_closest_target is CharacterBody3D” part, it goes insane till if looks at something that isnt a CharacterBody3D and crashes.

How does this function look like?
_look.get_closest()

1 Like
func get_closest():
	var distance:Vector3 = Vector3.ZERO
	var closest = null
	for bodies in get_overlapping_bodies():
		if (bodies.global_position - global_position).length() >       distance.length():
			distance = bodies.global_position - global_position
			closest = bodies
	if closest == null:
		return
	else:
		return closest

You have a wrong sign in this function - you’re essentially checking for the farthest body, not the closest.

See here my working mockup:

Here’s the scene tree:

Here’s the code on the Area3D node:

extends Area3D


func _process(delta: float) -> void:
	var closest_body: Node3D = get_closest()
	if closest_body:
		look_at(closest_body.global_position)


func get_closest() -> Node3D:
	var closest_distance: float = INF
	var closest_body: Node3D = null
	for body in get_overlapping_bodies():
		var distance: float = global_position.distance_squared_to(body.global_position)
		if distance < closest_distance:
			closest_distance = distance
			closest_body = body
	return closest_body

You can see in the video that the “canon” in the middle switches targets to whichever capsule is closest, and will not move if both of the capsules are outside of range.

See if you can translate that into your project.

My code detect all bodies within the area’s range, so if you need to detect only specific bodies, you should adjust the collision layers and masks appropriately.

I suspect your _closest_target.damagable and aiming variables might also be causing issues, you should print() their values to make sure they are what you expect them to be.

1 Like

If I understand your point, you should turn your character and look at using a LookAtModifier3D on the skeleton

Um… So, it worked at printing the target, the main issue was the view cone I made kept looking at the player cause it was inside the player but after I fixed that, it looks at the closest enemy and prints it but now if I replace that with the “look_at()” which made the player start rotation really fast T~T

Thx for the help upto this point tho.

Show your code again with the changes you made.

1 Like

Without knowing your code, I only can share what I’m using to turn a character I’m using:

#-----------------------------------------------------
func update_model_facing():

if movement.length() > 0:
	model.global_rotation.y = lerp_angle( model.global_rotation.y, _input_controller.target_rotation, get_physics_process_delta_time() * rotation_speed )

I call this on _physics_process
@export var rotation_speed = 12.0

And in my case the target_rotation is based on the camera rotation:

if event is InputEventMouseMotion:
camera_mount.rotation.x -= event.relative.y * mouse_sensitivity / 1000.0
camera_mount.rotation_degrees.x = clamp(camera_mount.rotation_degrees.x, -90.0, 30.0)
camera_mount.rotation.y -= event.relative.x * mouse_sensitivity / 1000.0

target_rotation = fposmod(camera_mount.rotation.y, 2.0 \* PI)
1 Like

This is the view cone, called _look in the player script

This is the player

Here, nothing happens,

If I get closer and hit aim, he starts spinning around, not the view cone tho, which inverts

Do you have any other code that rotates the player? Like rotate with mouse, or arrow keys, etc. If so, you might need to disable it when aiming, otherwise these 2 systems might be fighting over each other.

1 Like

I dont think so, but something I noticed is the view cone doesnt rotate with the player so Im not sure why that is. My movement code was from the GDquest tutorial, https://www.youtube.com/watch?v=JlgZtOFMdfc&t=46s&pp=ygUMZ2RxdWVzdCBnb2R0 so Idk if the way movement and rotation is handled by that is different.

Rotation speed is changed but I dont have any code outside of that touching rotation

Solved that by moving the view cone to the player_skin node I have for the model

Still rotates the player super fast when he sees anything.

Can you record a short video?

1 Like

One thing I figured out is its been registering the floor as the closest object which Im figuring out how to fix. Its the look_at() thing that I dont understand.

Changed it to this, not it only rotates the Player_skin. this make the player look at the closest enemy, but then does this