Rotate cannon to the enemy

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Godot_Starter

I have a cannon (KinematicBody2D) with an Area2D. If the Enemy (also a KinematicBody2D) enters the Area2D or if the Enemy is already in the Area2D, the cannon should rotate in the direction of the enemy.

How can I do that?

Thanks for answers!

:bust_in_silhouette: Reply From: njamster

Everything I wrote in this answer to another question of you applies here as well. But instead of calling move_and_collide you would now set the rotation like this:

rotation = velocity.angle()

That’s assuming your cannon’s sprite (or whatever you use to indicate the direction) is facing right by default. Otherwise you’d need to add an offset. Furthermore this will rotate the cannon immediately, which might or might not be what you want.

If you want it to turn around slowly, try this instead:

var difference = abs(rotation - velocity.angle())
if velocity.angle() > rotation:
    rotation += min(difference, 0.01)
else:
    rotation -= min(difference, 0.01)

Here 0.01 is the maximum value (in radians) your cannon will rotate in one frame.

The problem is, sometimes a Enemy goes into the Area2D and while the canone kills the enemy, the next enemy goes in the area2D. And when the first Enemy dies, the canon doesnt shoot at the secound Enemy.

EDIT: If there are much Enemys the cannon sometimes doesnt rotate at all

Godot_Starter | 2020-02-27 17:57

I already pointed out to you that there would be issues:

Note that this script has a few issues when there are multiple player characters: The enemy won’t follow the character closest to it, but instead the character that entered it’s area last. And will stop once a character leaves the area regardless of whether there still are other players in the area.

Instead of keeping track of just one enemy, you could maintain a list:

extends KinematicBody2D

var targets_in_reach = []

func _physics_process(delta):
    if not targets_in_reach.empty():
        var target = targets_in_reach.front()
        # ...

func _on_Area2D_body_entered(body):
    targets_in_reach.append(body)

func _on_Area2D_body_exited(body):
    targets_in_reach.erase(body)

This will always follow the enemy that is inside the area for the longest time. This might or might not what you want, but I hope you get the idea.

njamster | 2020-02-27 18:53