This is the testing Godot forums! All forum posts unique to this forum will be deleted! Please use the main forums here for any posts you want to keep. All forum rules still apply.

How to set sprite animation based on players angle to mouse click?

NS2SONS2SO Posts: 1Member

Hi, I've recently started a project in Godot, but I'm already stuck on something.

I'm making an isometric game where I want to move the player with the mouse, by clicking on a point and making the player move there. The movement works like i want it to, but the problem is that i don't know how to get the players angle to the mouse click position.

Here's the code:
`extends KinematicBody2D

var moving = false
var point = Vector2()
var event = InputEvent()
var direction = Vector2()

const speed = 200

onready var anim = self.get_node("AnimatedSprite") # animated sprite

enum ANIM_STATE { # animation states
SOUTH,
SOUTH_EAST,
SOUTH_WEST,
WEST,
EAST,
NORTH,
NORTH_EAST,
NORTH_WEST
}

enum IDLE_STATE {
I_SOUTH,
I_SOUTH_EAST,
I_SOUTH_WEST,
I_WEST,
I_EAST,
I_NORTH,
I_NORTH_EAST,
I_NORTH_WEST
}
var State = null
var Idle_State = null

var angle = null # player angle to mouse click
var walk_angle = angle
var idle_angle = walk_angle
func _ready():
set_fixed_process(true)
set_process_input(true)

func _input(event): # if mouse btn 1 clicked, sets click position as vector2
if event.type == InputEvent.MOUSE_BUTTON:
if event.button_index == BUTTON_LEFT and event.pressed:
point = Vector2(event.x, event.y)
check_angle()
moving = true
func _fixed_process(delta):

update_idle_sprite()

if moving:              #moves player
    var direction = point - self.get_global_pos()
    update_walk_sprite()
    if abs(direction.length()) < 5:  #sets exact position of player 
        self.set_global_pos(point)
        moving = false
        return

    direction = direction.normalized()
    var motion = direction * speed * delta
    motion = self.move(motion)

    var slide_attempts = 4
    while(is_colliding() and slide_attempts > 0):
        motion = get_collision_normal().slide(motion)
        motion = move(motion)
        slide_attempts -= 1

func check_angle(): # supposed to check angle of player to mouse click point
var checkangle = round(self.get_global_pos().angle_to_point(point) * 5) /1
angle = checkangle
print(angle)

func update_walk_sprite(): # updates walk sprites based on angle value

if moving:

    if walk_angle == 2 or 0 or 1 or -0 or -1 or -2 :
        State = ANIM_STATE.NORTH
    elif walk_angle == 3 or 4 or 5 or 6 : 
        State = ANIM_STATE.NORTH_WEST
    elif walk_angle == 7 or 8 or 9 or 10 :
        State = ANIM_STATE.WEST
    elif walk_angle == 11 or 12 or 13 or 14 : 
        State = ANIM_STATE.SOUTH_WEST
    elif walk_angle == 16 or -16 or -15 or 15:
        State = ANIM_STATE.SOUTH
    elif walk_angle == -3 or -4 or -5 or -6 : 
        State = ANIM_STATE.SOUTH_EAST
    elif walk_angle == -7 or -8 or -9 or -10 : 
        State = ANIM_STATE.EAST
    elif walk_angle == -11 or -12 or -13 or -14 : 
        State = ANIM_STATE.NORTH_EAST


    if (State == ANIM_STATE.SOUTH):
        anim.play("walking90")
    elif (State == ANIM_STATE.SOUTH_EAST):
        anim.play("walking135")
    elif (State == ANIM_STATE.EAST):
        anim.play("walking180")
    elif (State == ANIM_STATE.NORTH_EAST):
        anim.play("walking225")
    elif (State == ANIM_STATE.NORTH):
        anim.play("walking270")
    elif (State == ANIM_STATE.SOUTH_WEST):
        anim.play("walking45")
    elif (State == ANIM_STATE.WEST):
        anim.play("walking0")
    elif (State == ANIM_STATE.NORTH_WEST):
        anim.play("walking315")

func update_idle_sprite(): # updates idle sprite based on angle value

if not moving:

    if angle == 2 or 0 or 1 or -0 or -1 or -2 : 
        Idle_State = IDLE_STATE.I_NORTH
    elif angle == 3 or 4 or 5 or 6 : 
        Idle_State = IDLE_STATE.I_NORTH_WEST
    elif angle == 7 or 8 or 9 or 10 : 
        Idle_State = IDLE_STATE.I_WEST
    elif angle == 11 or 12 or 13 or 14 : 
        Idle_State = IDLE_STATE.I_SOUTH_WEST
    elif angle == 16 or -16 or -15 or 15: 
        Idle_State = IDLE_STATE.I_SOUTH
    elif angle == -3 or -4 or -5 or -6 : 
        Idle_State = IDLE_STATE.I_SOUTH_EAST
    elif angle == -7 or -8 or -9 or -10 : 
        Idle_State = IDLE_STATE.I_EAST
    elif angle == -11 or -12 or -13 or -14 : 
        Idle_State = IDLE_STATE.I_NORTH_EAST


    if (State == IDLE_STATE.I_SOUTH):
        anim.play("idle90")
    elif (State == IDLE_STATE.I_SOUTH_EAST):
        anim.play("idle135")
    elif (State == IDLE_STATE.I_EAST):
        anim.play("idle180")
    elif (State == IDLE_STATE.I_NORTH_EAST):
        anim.play("idle225")
    elif (State == IDLE_STATE.I_NORTH):
        anim.play("idle270")
    elif (State == IDLE_STATE.I_SOUTH_WEST):
        anim.play("idle45")
    elif (State == IDLE_STATE.I_WEST):
        anim.play("idle0")
    elif (State == IDLE_STATE.I_NORTH_WEST):
        anim.play("idle315")
`

When I print(angle) it show various numbers in the output feed (from -16 to -0 to the right of the player and from 16 to 0 to the left), but only the North walking and idle animations function properly, the rest don't play at all. I think the angle value is always at 0 despite what the output feed says, the player loads in as a static sprite facing south, but if i click anywhere, the animations for walking and idle( 0 angle value for both) are facing north, like I specified in the code .

I don't have much coding experience(at all) and I completely stumped. If anyone could help me, I'd very much appreciate it!
Thank you in advance. :)


Tags :

Best Answer

  • SomnivoreSomnivore Posts: 102
    edited December 2017 Accepted Answer

    If you play an animation that's already playing, it replays that animation; if done every frame, it replays over and over, making it look like it's not being animated at all since it never gets past the first frame. You'd need to keep track of last frame's state so you can compare with this frame's state, that way you only play an animation when the state has changed.

    if lastState == State: return

    Elsewhere, once you're done with everything else...

    lastState = State

    Alternatively you can check to see if the animator's current animation is the same as the animation you're trying to play:

    elif State == IDLE_STATE.I_SOUTH and anim.get_current_animation() != "idle90":

    You can then wrap that into a convenience function called, for example, func play_once(anim_name), which just checks to see if the animator is already playing the given animation before attempting to play it:

    func play_once(anim_name): if anim_name == anim.get_current_animation(): return anim.play(anim_name)

    If the angle is a decimal you'd want to instead check in-between numbers using ranges, observe:

    if angle >= -2 and angle < 2:

    Otherwise if the angle is -1.002 and you're checking for -1 or -2, neither are hit. Even if using whole numbers it's more convenient and readable than several ors.

    An easy way to see what's going on in code is to insert dummy prints into places you think might be going wrong, e.g. print("Hello!") (or whatever explitive you're feeling at the moment when your damn code won't work); I used this method when I had this same problem with anims seeming to not want to play, and it turned out that it was getting printed every single frame, so I knew anim.play() was getting fired every frame, which led me to realizing what the issue was. Also useful to see whether certain parts of code are getting fired or not. Of course you could also set breakpoints but then everything has to stop for those. Just don't forget to remove your prints once you're done with them, otherwise you'll have a hard time trying to remember where you left them, leading to annoying outputs getting in the way of the stuff you really wanna know.

Answers

  • SomnivoreSomnivore Posts: 102Member
    edited December 2017 Accepted Answer

    If you play an animation that's already playing, it replays that animation; if done every frame, it replays over and over, making it look like it's not being animated at all since it never gets past the first frame. You'd need to keep track of last frame's state so you can compare with this frame's state, that way you only play an animation when the state has changed.

    if lastState == State: return

    Elsewhere, once you're done with everything else...

    lastState = State

    Alternatively you can check to see if the animator's current animation is the same as the animation you're trying to play:

    elif State == IDLE_STATE.I_SOUTH and anim.get_current_animation() != "idle90":

    You can then wrap that into a convenience function called, for example, func play_once(anim_name), which just checks to see if the animator is already playing the given animation before attempting to play it:

    func play_once(anim_name): if anim_name == anim.get_current_animation(): return anim.play(anim_name)

    If the angle is a decimal you'd want to instead check in-between numbers using ranges, observe:

    if angle >= -2 and angle < 2:

    Otherwise if the angle is -1.002 and you're checking for -1 or -2, neither are hit. Even if using whole numbers it's more convenient and readable than several ors.

    An easy way to see what's going on in code is to insert dummy prints into places you think might be going wrong, e.g. print("Hello!") (or whatever explitive you're feeling at the moment when your damn code won't work); I used this method when I had this same problem with anims seeming to not want to play, and it turned out that it was getting printed every single frame, so I knew anim.play() was getting fired every frame, which led me to realizing what the issue was. Also useful to see whether certain parts of code are getting fired or not. Of course you could also set breakpoints but then everything has to stop for those. Just don't forget to remove your prints once you're done with them, otherwise you'll have a hard time trying to remember where you left them, leading to annoying outputs getting in the way of the stuff you really wanna know.

Leave a Comment

Rich Text Editor. To edit a paragraph's style, hit tab to get to the paragraph menu. From there you will be able to pick one style. Nothing defaults to paragraph. An inline formatting menu will show up when you select text. Hit tab to get into that menu. Some elements, such as rich link embeds, images, loading indicators, and error messages may get inserted into the editor. You may navigate to these using the arrow keys inside of the editor and delete them with the delete or backspace key.