8-way animation with mouse click

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

Hello guys!
I’m sorry for my english, but can anyone help me with animation problem?
I’m using pretty easy code to move my character in the game and trying to animate the movement. So it easily works with only 2 directions left and right, and when I’m trying to add up/down animation does not work. I understand why it happens, but don’t know the solution to make it work.

extends KinematicBody2D


export var move_speed = 200
var target = Vector2()
var velocity = Vector2()

func _input(event):
	if event.is_action_pressed('rightclick'):
		target = get_global_mouse_position()

func _physics_process(delta):
	velocity = position.direction_to(target) * move_speed
	if position.distance_to(target) > 5:
		velocity = move_and_slide(velocity)
	if velocity < Vector2(1,0):
		$AnimatedSprite.play("runleft")
	if velocity > Vector2(-1,0):
		$AnimatedSprite.play("runright")
	if velocity < Vector2(1,1): <---- does not work
		$AnimatedSprite.play("rundown") 
:bust_in_silhouette: Reply From: njamster

According to vector2.h, comparing vectors works like this:

bool operator<(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator>(const Vector2 &p_vec2) const { return Math::is_equal_approx(x, p_vec2.x) ? (y > p_vec2.y) : (x > p_vec2.x); }

That means the y-components of vectors are completely ignored during comparison, unless the x-components are approximately equal to each other. Which is really unlikely, given that you compare your characters velocity (a potentially very big value!) to a value of just 1. So your first and third condition are basically the same!

Of course you could compare the x- and y-components individually to arrive at your desired result. But that will become messy real quick. So here’s my solution:

# get the velocity-vectors angle in degrees
var exact_angle = rad2deg(velocity.angle())

# round the angle to the next closest multiple of 45
var rounded_angle = int(round(exact_angle/45)*45)

match rounded_angle:
	0:
		print("Right")
	-45:
		print("Up Right")
	-90:
		print("Up")
	-135:
		print("Up Left")
	180, -180:
		print("Left")
	135:
		print("Down Left")
	90:
		print("Down")
	45:
		print("Down Right")

thank you very much for your kind answer. I added your code, now it looks like this and always prints me right, wherever I’m trying to click

extends KinematicBody2D


export var move_speed = 200
var target = Vector2()
var velocity = Vector2()
var exact_angle = rad2deg(velocity.angle())
var rounded_angle = int(round(exact_angle/45)*45)

func _input(event):
	if event.is_action_pressed('rightclick'):
		target = get_global_mouse_position()

func _physics_process(delta):
	velocity = position.direction_to(target) * move_speed
	if position.distance_to(target) > 5:
		velocity = move_and_slide(velocity)
	match rounded_angle:
		0:
			print("Right")
		-45:
			print("Up Right")
		-90:
			print("Up")
		-135:
			print("Up Left")
		180, -180:
			print("Left")
		135:
			print("Down Left")
		90:
			print("Down")
		45:
			print("Down Right")

shuvia | 2020-02-18 12:55

You need to recalculate the exact_angle- and rounded_angle-variables each frame anew as they depend on the velocity which can change every frame as well. Right now you’re doing in globally, so it’s calculated exactly once for your default velocity of (0, 0). Here’s how it should look instead:

extends KinematicBody2D

export var move_speed = 200
var target = Vector2()
var velocity = Vector2()

func _input(event):
    if event.is_action_pressed('rightclick'):
        target = get_global_mouse_position()

func _physics_process(delta):
    velocity = position.direction_to(target) * move_speed
    if position.distance_to(target) > 5:
        velocity = move_and_slide(velocity)
    var exact_angle = rad2deg(velocity.angle())
    var rounded_angle = int(round(exact_angle/45)*45)
    match rounded_angle:
        0:
            print("Right")
        -45:
            print("Up Right")
        -90:
            print("Up")
        -135:
            print("Up Left")
        180, -180:
            print("Left")
        135:
            print("Down Left")
        90:
            print("Down")
        45:
            print("Down Right")

njamster | 2020-02-18 13:10

Thank you very much, now it works perfectly. I only need to find the solution to idle state right now!

shuvia | 2020-02-18 13:19