How to get mouse direction to change sprite

Godot Version

v4.3

Question

I made a simple animatedsprite2d which changes depending on mouse direction. But, whenever I tried to get the angle from the sprite to the mouse cursor in degrees using the int(get_angle_to(get_global_mouse_position())), the sprite won’t change, and I get an error saying:

E 0:00:00:0276   two_way_sprite.gd:4 @ @implicit_new(): Parameter "get_viewport()" is null.
  <C++ Source>   scene/main/canvas_item.cpp:1112 @ get_global_mouse_position()
  <Stack Trace>  two_way_sprite.gd:4 @ @implicit_new()

Any help is welcome, here’s the code:

extends AnimatedSprite2D

@onready var anim = get_node("/root/TwoWaySprite")
var direction = int(get_angle_to(get_global_mouse_position()))
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
	pass

# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
	if direction >= -90 && direction <= 90:
		anim.play("south")
	if direction < -90 && direction > 90:
		anim.play("north")

I am not sure it will work, but can you define the direction in the process function like this:

var direction := Vector2.ZERO
#...
func _process(delta: float) -> void:
	direction = int(get_angle_to(get_global_mouse_position()))
    #...
1 Like

simply add @onready before getting your direction.

@onready var direction

The problem must be code running order inside the egnine.

@kozxd2000 yeah you are right but as he using the direction variable multi times in the process function, he also need to assign its value for multi times in the process function. So there is no need to use @onready and define it early.

1 Like

Oh, you are right! I didn’t think it though that part.

1 Like

Good to know.

Unfortunately, this solution did not work. The value type of int cannot be assigned to a vector of type Vector2.

Sorry this was just a mistake, to fix it change this code to:

var direction := 0

Thanks. It did work somehow. But the sprites switch at wierd intervals.
So, I converted it from radians to degrees by simply adding the rad_to_deg() function.
So, I added this at the end:

if Input.is_action_just_released("spacebar"):
		print (str(direction))

The output seems to be that the 0 degrees is somewhere in the south-east of the object. Placing your mouse directly south of the object gives you “57”.
I managed to fix this issue by deleting the int() function and replacing it with this:
direction = (rad_to_deg(get_angle_to(get_global_mouse_position())) - 90)
Now comes the problem, the sprite will always point “south”. If the sprite is initially set to “north”, putting your mouse cursor to below the sprite causes it to be set to “south” and you can’t change it back to “north”.
Similarly, if I expand the if statements to 4 ways as in this:

        if direction >= -45 && direction <= 45:
		anim.play("south")
	if direction <= -135 && direction >= 135:
		anim.play("north")
	if direction > -135 && direction < -45:
		anim.play("east")
	if direction < 135 && direction > 45:
		anim.play("west")

The only sprites showing are “south”, “east”, and “north”, with “south” and “east” occupying their respective places and “north” being north and also occupying “west”.
How do I fix that?

1 Like

If you only want the cardinal directions it may be better to avoid angles all together and compare the largest distance from the player to the mouse.

var diff: Vector2 = get_global_mouse_position() - global_position
if absf(diff.x) > absf(diff.y):
	# X is greater, east/west
	if diff.x < 0.0:
		anim.play("west")
	else:
		anim.play("east")
else:
	# Y is greater or equal, north/south
	if diff.y < 0.0:
		anim.play("north")
	else:
		anim.play("south")

It might not be shorter, but the math will be faster for the computer every frame.

2 Likes

This somehow fulfills as an answer, although I am expecting that direction variable be kept, so if I want to have the object point at another object instead of a cursor, then I’ll just have the variable set to the angle from the object to the other object.

Thank you.

You could replace get_global_mouse_posittion() with a target.global_position for looking at other Node2Ds; again if you only want cardinal directions.

1 Like