Make an Action RPG in Godot 3.2 (P9 | Attacking Animation + State Machines)

Поділитися
Вставка
  • Опубліковано 2 лис 2024

КОМЕНТАРІ • 620

  • @uheartbeast
    @uheartbeast  4 роки тому +68

    Let's add in an attack animation! I also introduce a simple state machine and talk about input maps (Add WASD controls).
    Here is the Github repo for this project (under MIT license): github.com/uheartbeast/youtube-tutorials/tree/master/Action%20RPG
    This video was made possible by my wonderful Kickstarter backers. If you are interested in taking a deeper dive into the Godot game engine you can buy my 1-bit Godot Course at this link: www.heartgamedev.com/1-bit-godot-course-youtube

    • @uheartbeast
      @uheartbeast  4 роки тому +3

      @@MrRenanZX give it a try! There are lots of different ways to set things up. Use whichever you feel is best for you.

    • @MrRenanZX
      @MrRenanZX 4 роки тому +3

      @@uheartbeast Thanks, i notice what did you do when i review your video, it makes sense this solution because of the loop animation, but thanks for reply

    • @atalamcom1941
      @atalamcom1941 4 роки тому +5

      edit: FINALLY I SOLVED THE PROBLEM.
      I just need to re-type the Attack parameters, and it WORKED!
      finally
      Hey @HeartBeast ,
      I Have A Problem In RPG Action And I’m Stuck in it Too, The Problem Is Where I Fight In the Game.
      And When I Try To Fight In Down Direction It Fights In Up Direction, Same as Left & Right Direction.
      If You Know How To Solve it, Please msg Me.
      and Here's The Code
      extends KinematicBody2D
      const ACCELERATION = 500
      const MAX_SPEED = 80
      const FRICTION = 500
      enum {
      MOVE,
      ROLL,
      ATTACK
      }
      var state = MOVE
      var velocity = Vector2.ZERO
      onready var animationPlayer = $AnimationPlayer
      onready var animationTree = $AnimationTree
      onready var animationState = animationTree.get("parameters/playback")
      func _ready():
      animationTree.active = true
      func _physics_process(delta):
      match state:
      MOVE:
      move_state(delta)

      ROLL:
      pass

      ATTACK:
      attack_state(delta)

      func move_state(delta):
      var input_vector = Vector2.ZERO
      input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
      input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
      input_vector = input_vector.normalized()

      if input_vector != Vector2.ZERO:
      animationTree.set("parameters/idle/blend_position", input_vector)
      animationTree.set("parameters/Run/blend_position", input_vector)
      animationTree.set("parameters/ِِِِAttack/blend_position", input_vector)
      animationState.travel("Run")
      velocity = velocity.move_toward(input_vector * MAX_SPEED, ACCELERATION * delta)

      else:
      animationState.travel("idle")
      velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)

      velocity = move_and_slide(velocity)

      if Input.is_action_just_pressed("attack"):
      state = ATTACK

      func attack_state(delta):
      velocity = Vector2.ZERO
      animationState.travel("Attack")
      func attack_animation_finished():
      state = MOVE

    • @spinecho609
      @spinecho609 4 роки тому +1

      i have them working, but i notice they will not attack when moving diagonally?

    • @camalienator
      @camalienator 4 роки тому +1

      pleeease help, my code is like the video, but something i did wrong makes the game absolutely not responsive, my character no longer moves or attacks

  • @infiniteodyssey5318
    @infiniteodyssey5318 3 роки тому +359

    Who else agree that this is one of the best GODOT tutorials on UA-cam?

  • @TobiasSample
    @TobiasSample 3 роки тому +39

    If you put something like:
    func attacking(delta):
    animationState.travel("Attack")
    velocity = velocity.move_toward(Vector2.ZERO, FRICTION/2 * delta)
    velocity = move_and_slide(velocity)
    In the attack function, it will continue to slide a bit while you attack :D

    • @TampopoInteractive
      @TampopoInteractive 2 роки тому +3

      Great idea. I already had the friction in there, but it really needs that extra little slide by decreasing friction.

  • @Marekpetr4
    @Marekpetr4 4 роки тому +52

    15:35
    HeartBeast: "Remember that Up is down in here..."
    Me: *Pirates of the Caribbean 3 flashbacks*

  • @forgeflarion8362
    @forgeflarion8362 4 роки тому +246

    Will there be a tutorial about an inventory system? I have been loving these videos, thanks you!

    • @galvanizeddreamer2051
      @galvanizeddreamer2051 3 роки тому +56

      While it was not a part of this series, he did do a tutorial on an inventory system.
      Part 1: ua-cam.com/video/rdUgf6r7w2Q/v-deo.html
      Part 2: ua-cam.com/video/l28ui3KfeS0/v-deo.html

  • @ampstamp
    @ampstamp 3 роки тому +20

    These tutorials are so simple, and Godot is so easy to use that whenever I make a mistake, I'm easily able to figure out what it is and how to fix it. Thanks in part to the debug console which details what the problem might be in simple terminology, even giving suggestions instead of saying "ayo the game brokey"

  • @snakehound7678
    @snakehound7678 4 роки тому +38

    Another advantage of match I guess is, that you make shure, that every case excludes the other one. while if else statements could overlap in boolean values.
    I really love every tutorial session. Hope you all are save.

  • @EidoEndy
    @EidoEndy 4 роки тому +61

    Call Method track looks really powerful. It just screams potential for fighting game mechanics or timed hits.

    • @mokafi7
      @mokafi7 3 роки тому

      true

    • @limitzmain1453
      @limitzmain1453 3 роки тому

      jesus

    • @GabrielLima-gh2we
      @GabrielLima-gh2we 3 роки тому

      for real

    • @sensiblegh0st86
      @sensiblegh0st86 2 роки тому +3

      I haven't even watched the video yet but the possibility for timed hits makes me very excited as I've always wanted to make a game where blocking enemy attacks is the primary combat mechanic, which is similar to timed hits. Very very cool

  • @HussainAli-hn2ef
    @HussainAli-hn2ef 4 роки тому +104

    Guys remember: WHAT YOU CALL STUFF MATTERS
    In the Animation tree thing, when I created the Blend Space 2D I called it "Attacking," but in the code I just copied the video and wrote it as
    animationTree.set("parameters/Attack/blend_position", input_vector)
    when it should have been
    animationTree.set("parameters/Attacking/blend_position", input_vector).
    Also, for the input map, I named the attack key (space/J) "Attacking," but again I just copied him and wrote the code as
    if Input.is_action_just_pressed("attack"):
    when it should have been
    if Input.is_action_just_pressed("Attacking"):
    So A) make sure you follow him exactly, or B) if you deviate slightly make sure to account for it in the code!
    I know this is probably super obvious to most people but if there are any beginners like me out there I figured I would let you know just in case lol

    • @cristianbravo7081
      @cristianbravo7081 4 роки тому +3

      Yeah, Thanks dude.

    • @jesus2639
      @jesus2639 4 роки тому +11

      If only i read your comment before my panic attack.

    • @Lama_Sabactani
      @Lama_Sabactani 3 роки тому +6

      i just spent some time searching for an error that was exactly caused by distraction in my Animation Tree name. I wish I read your comment earlier lmao

    • @randydrew3743
      @randydrew3743 2 роки тому +2

      I have a bug in (if Input.is_just_pressed("attack"):) it might be that very problem. Thanks. Not at my computer right now but I will give it a try when I get back to it!

    • @ronniemarshall7684
      @ronniemarshall7684 2 роки тому +2

      God-fkng-dmn-it

  • @omartanah5854
    @omartanah5854 5 місяців тому +4

    instead of making the attack_animation_finished function you can attach a signal from the animationTree> beside the Inspector click on the Node tab > choose the signal animation finished and connect it to player from there you can make the signal function look like this:
    func _on_animation_tree_animation_finished(Attack):
    state = MOVE
    Make sure to change names according to what you have and make sure to make all the attack animations not on loop from the AnimationPlayer

  • @EverTheFractal
    @EverTheFractal 4 роки тому +5

    I got to this episode and stopped for three days while I remade all the sprites and assets myself because I wanted it to have a personal touch and I'm ready to continue.
    I don't know whether I should say it here or further in but I might as well just say it, I've learned so much in such a short amount of time that I'm just like... Damn. You're a good teacher.

  • @F4ngb0n3
    @F4ngb0n3 2 роки тому +7

    Bruh... 2 days of searching for adequate state management delivered in an understandable format for the code structure I am using, and bupkiss. THEN, I find your videos... you are a freaking legend my friend and I cant say thank you enough! This really assisted in rounding out my Dodge and Attack animations and implementing them with the movement correctly. Thank you again and will be regularly visiting!

  • @Xethenion
    @Xethenion 4 роки тому +74

    Was trying to figure out for almost an hour why i couldn't move.
    Turns out I forgot to add = MOVE to var state = MOVE. lol
    Great videos!

    • @severedhandfrenchfries4170
      @severedhandfrenchfries4170 3 роки тому +3

      Dude...same... I panicked

    • @DeviantCrow-i7z
      @DeviantCrow-i7z 3 роки тому +1

      I did the same dam thing.

    • @impliqued1910
      @impliqued1910 3 роки тому +1

      Thanks dude you really saved me!

    • @jackbellaudio
      @jackbellaudio 3 роки тому

      saved me a lot of time, thank you

    • @pfaprado
      @pfaprado 3 роки тому

      I had the same issue, I was like rewatching the damn thing to find if I had forgotten to add something. Thanks mate!

  • @QuoteNat
    @QuoteNat 3 роки тому +49

    I personally found the player character stopping in it's tracks when attacking to be a bit annoying, so I added these lines to attack_state to make the player slide a bit when they attack:
    velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
    velocity = move_and_slide(velocity)
    You'll also need to pass in delta for it to work properly.

    • @eldaria
      @eldaria 3 роки тому +3

      Thank you, good idea..

    • @TimTacTV
      @TimTacTV 3 роки тому

      This does literally nothing for me, anyone get this to work?

    • @TimTacTV
      @TimTacTV 3 роки тому +1

      @Nikola Zivlak I figured it out a different way (:

    • @TimTacTV
      @TimTacTV 2 роки тому +1

      @PlayStation Japan I don't remember lmao

    • @TimTacTV
      @TimTacTV 2 роки тому

      @PlayStation Japan figure it out
      Also make more Astro games 😂

  • @Luciaa4
    @Luciaa4 Рік тому +18

    For those of you who use Godot 4 and have this weird flickering between the Idle-State and the Attack-State and also get freezes like me:
    Make sure to turn AutoMode off! You do this byclicking on the tansitions between Idle and Attack and go to the right tab -> Advance -> Mode -> Enable (don't disable this). If you play the game it should work like in the video :)
    Actually people in the comments mentioned this for Godot 4 in the run video but I forgot that when watching this video xD

    • @Fusterlolz
      @Fusterlolz Рік тому +2

      I had forgotten about it too... So thank you for reminding me :p

    • @LeDonPraes
      @LeDonPraes Рік тому +2

      This one! This was so helpful!

    • @Rorshacked
      @Rorshacked 10 місяців тому

      Yes! Thank you!

    • @Chris-rb8ox
      @Chris-rb8ox 4 місяці тому

      thanks!

  • @novh4ck
    @novh4ck 4 роки тому +8

    Even though I have been closely following Godot since 2014 and I know most of the stuff you show I still watch this series because it's well executed and you show a lot of "hidden" features. Great job. :)

  • @cue_ball_jamal
    @cue_ball_jamal Рік тому +10

    for the transition from attack to move states and vice-versa, you can also connect the animation_finished signal to the player script. (this means once an animation has finished, a signal will sent and that function will be called.) Then, you can add a condition based on what state the player was when that animation played (in this case it will be ATTACK), so then you can set the player's state to MOVE. This avoids having to add a call_method() track to every attack animation

    • @tejaswithme3713
      @tejaswithme3713 Рік тому +1

      Ahh... Thank you man for this!!!

    • @blakealanfoster
      @blakealanfoster Рік тому

      Yeah, very easy and quick way of doing it, just make sure its the animation_finished signal from the animation tree and not the animation player and its super simple. It automatically sets up the method for you and all ya gotta do is add state=MOVE and you are done.

    • @dard1515
      @dard1515 Рік тому

      @@blakealanfoster How did you make this work? I have setup the same way you describe it but when I press attack I get stuck in the current Run or Idle animation instead.

    • @DnDBreakfastClub
      @DnDBreakfastClub Рік тому +1

      @@dard1515 I believe you have to turn off the looping in each animation (AttackUp, AttackDown, etc...). I am currently trying to figure out how I can make this work while still moving, though, since doing it this way stops your character movement until the animation is finished.

  • @ПростоМакс-ъ5п
    @ПростоМакс-ъ5п 4 роки тому +32

    instead of making animations on the left and right, you can just make an animation on one side and add a line of code "flip_h = true" and "flip_h = false"

    • @Reloecc
      @Reloecc 4 роки тому +15

      flip_h is just for the sprites, use scale -1 instead to flip all of your nodes (including collisions)

    • @Levirules
      @Levirules 4 роки тому +8

      @@Reloecc i have a feeling this will come in handy some day. Thanks.

    • @IgorogI1000
      @IgorogI1000 3 роки тому +4

      I am doing that, but considering it wont flip future hit boxes and hurt boxes, I think I'm going to follow Jan idea

    • @held2053
      @held2053 3 роки тому +8

      though, it only is useful, if the sprite looks the same-
      e.g. there is a scar or an eyepatch on the left/right side, you then need another image for it

  • @dragon3025_
    @dragon3025_ 4 роки тому +55

    in func attack_state(delta) I repeated the lines "velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)
    " then "velocity = move_and_slide(velocity)" to make the player slide to a halt instead of awkwardly stopping.

    • @ezrawallet
      @ezrawallet 3 роки тому +5

      very nice, appreciate you sharing this!

    • @TimTacTV
      @TimTacTV 3 роки тому

      This does literally nothing for me, anyone get this to work?

    • @cozmovortex
      @cozmovortex 3 роки тому +5

      @@TimTacTV If you change the friction to a smaller value (like 50) you'll 'see' it working. At a higher friction value it isn't really noticeable

    • @TimTacTV
      @TimTacTV 3 роки тому +1

      @@cozmovortex I got it to work another way :D

    • @troglodev2533
      @troglodev2533 3 роки тому +1

      @@TimTacTV HOW, I'd really like to know.

  • @erikahlundhelguera
    @erikahlundhelguera 4 роки тому +7

    On the technical side of if vs switch I just wanted to add that switch cases are faster than if statements since they're implemented with a combination of binary trees and jump tables.
    Basically with a long if/else list, if you're in the last state, you will have to run all the IFs until you reach the last one, while the switch/case will "jump around", if you run it several times each frame (multiple state machines, check the state in _process, _physics_process and _draw, etc.) it does make a difference at the end.
    Great video again HeartBeast, I find it funny that you mentioned using nodes for each state as that's exactly what I did for my pushdown automata. Still, I'm gonna follow what you did for the animation tree.

  • @randydrew3743
    @randydrew3743 2 роки тому +2

    I love the good morning, afternoon or evening, where ever you and when ever you are my name is Benjamin! It's so satisfying to hear after finishing one of these tutorials and starting another.

  • @user-ze7hp2jf5x
    @user-ze7hp2jf5x 4 роки тому +5

    dear god this is an amazing tutorial, far better than most of those out there that I did watch but never got a full grasp over the topics at hand, I even managed to add other functions just to test the waters, 11/10
    Edit:
    Also, you dont really need to add much collusion either, remember the move_and_slide method? well he showed exactly how to draw block areas with it if you want to add areas with hills you can walk on, or even draw buildings on top of them and adding a collusion map in needed areas if im not mistaken

  • @ahmadayazamin3313
    @ahmadayazamin3313 4 роки тому +3

    Hi HeartBeast,
    Even though I don't usually watch these tutorials completely, it helps so much when trying to solve some problems in my game. I am currently making my own rpg with my own assets and gameplay, and so far it has helped tremendously (especially some of the key concepts such as match statements). Thank you so much for these videos.

  • @codywinter4818
    @codywinter4818 3 роки тому +7

    Also: something I did slightly different,
    I didn't really like the idea of having momentum in the physics and then just forgetting about it when the attack is launched, so in my attack code I included instead the
    velocity = velocity.move_toward(Vector2.ZERO, friction * delta)
    velocity = move_and_slide(velocity)
    Since it takes no inputs and keeps the velocity moving back towards Vector2.ZERO its still smooth and you can't change any movement until its done animating but you will still slide a bit if you initiate an attack while running. It seems to be working well and I like it.

  • @TheMee147
    @TheMee147 4 роки тому +3

    Yo,
    I tried out a little bit and in the attack state function I did not set the velocity to zero, I copied
    "velocity = velocity.move_toward(Vector2.ZERO, FRICTION * delta)"
    from the move state func and added
    "velocity = move_and_slide(velocity)"
    into the attack state func. This makes the Player stop not so abrupt and it looks a bit smoother.
    Hope I do not run into problems with that in future videos. I am currently binge-watching this tutorial series and I am learning so much!
    I started a month ago with Godot and this tutorial is the best I found yet by far.
    Good work, dude :)

  • @simosavela2802
    @simosavela2802 Рік тому

    6:40 I just love how you corrected your words middle of the sentence. Great series! Thank you so much.

  • @dmreichard
    @dmreichard 4 роки тому +3

    This tutorial series is fantastic so far, thank you kindly for taking the time to put these videos together.
    I would also like to mention that in addition to passing delta to your state functions, you could also use 'get_physics_process_delta_time()' to retrieve the delta as well.

  • @Smaxx
    @Smaxx 4 роки тому +18

    Just one note regarding `attack_animation_finished()`: You basically recreated a signal that's already present in the AnimationPlayer. There's one firing whenever animations are done, so I'd just reuse that instead. This saves one from setting up all those callbacks, especially if there are more to come later.

    • @eubulos988
      @eubulos988 4 роки тому +9

      Unfortunately, AnimationPlayer signals are not emitted when animation is played from AnimationTree in Godot 3.2, see github.com/godotengine/godot/issues/28311. However, there is already PR for that github.com/godotengine/godot/pull/30508/files, but it is still open, what's more it is as of now set as 4.0 milestone, so dunno when will it be implemented.

    • @Mriganka2S
      @Mriganka2S 4 роки тому +3

      You don't even have to do that. What you could do is just put in auto-advance so that it transitions back to the moving state at the end of the animation.

    • @compartirlavida
      @compartirlavida 4 роки тому

      @@Mriganka2S How would you change the state back to MOVE, though? The animation will stop but you'll still be in the attack state.

    • @Mriganka2S
      @Mriganka2S 4 роки тому

      @@compartirlavida That is what auto-advance is for in the animation state machine node. Another thing you could do is to just check if an animation is playing with the get_node function for the playback parameter

    • @compartirlavida
      @compartirlavida 4 роки тому

      @@Mriganka2S When i do that, the node isn't changed immediately, there's a short delay between switching to the "Attack" node, so basically checking if get_current_node() == "Idle" on the next frame just resets the state back immediately. Having an animation_completed signal or something would make it much easier than having to add an intermediary variable to test if the state has changed or not.

  • @Balalti
    @Balalti Рік тому +8

    If your attack animation is stuck, make sure you put the "Call Method Track" is inserted exactly where the last frame is.

  • @DIMENSIONSTURNIER
    @DIMENSIONSTURNIER 4 роки тому +31

    Hope there will be a Video about "changing scenes"... so you could go back to them with the player in the correct position.
    When I enter "Scene B" from the Top of "Scene A" and I'm going back to "Scene A" I want, that the player is in the same position as he was before.
    Is there an easy way to do this?
    (btw. sorry if there are any grammatical issues.. I am not a native speaker.)

    • @jeffvenancius
      @jeffvenancius 4 роки тому +7

      I've had struggles with that. The way I've found was to use a Singleton. You see, when you change a scene, the later one doesn't exist anymore, but that never happens with singletons, they just keeps everything.
      Basically I've created a variable in there, which is a Vector2 with the next player position (actually, it's an export var, they are great 'cause you can change at will and they will work accordingly with the scene, not the script). When the player goes into a door, for example, the game will change the var to what you want before changing the scene, then on the _ready function you make the Player go there. Kinda hard of explain, but really, really easy, I swear. Probably he'll explain better. There is other ways too, of course.
      Oh, in my game I've made a way where the Player keeps his direction too.

    • @DIMENSIONSTURNIER
      @DIMENSIONSTURNIER 4 роки тому +1

      @@jeffvenancius Thanks a lot!

    • @ccgb92
      @ccgb92 4 роки тому +1

      You can simply call remove_child, and then when the new scene (or level) is loaded, call add_child

  • @OrgiinalPortugal
    @OrgiinalPortugal 3 роки тому +1

    Started this series following you and programming in C#. You make it very clear how everything clicks and is so easy too follow. Thank you a lot for this!

  • @zobdog205
    @zobdog205 4 роки тому +12

    Very nice artwork and released under MIT? Awesome work!

  • @romanrioter5503
    @romanrioter5503 3 роки тому +1

    State machines always confused me but this finally put the pieces in place. *Thanks @HeartBeast!*

  • @T1Oracle
    @T1Oracle 4 роки тому +5

    Awesome content!
    BTW, I noticed that you forgot to add the +0.1 to the animation tree y axis for attack so that it favors attacking right or left over up or down. Also, I find that when I add the velocity calculations for friction to the attack_state that the player costs to a stop more naturally while attacking. This makes it feel just a bit more fluid IMO.

    • @semudara9723
      @semudara9723 4 роки тому

      Awesome tip! Without that, I found that the player would stop suddenly, then keep sliding a bit AFTER the attack like the momentum was still there. I love the way the player now kind of slides to a stop while attacking, it looks cool! =)

  • @TampopoInteractive
    @TampopoInteractive 2 роки тому +5

    One minor issue I noticed is that if you hold in a different direction while/immediately after the attack animation is playing, the attack animation of that new direction will play briefly (approx 2 frames) before/after transitioning to the move state.

    • @sexybooru
      @sexybooru 2 роки тому

      Did you find a fix for that ?

    • @Matt-lm8tj
      @Matt-lm8tj Рік тому

      If someone have a fix that will be cool to share it

    • @SamSverko
      @SamSverko 11 місяців тому +3

      I was able to fix it for me (and hopefully for you): In the AnimationTree editor, I had two node connectors between "Idle" and "Attack". I removed the "Attack" -> "Idle" connector, which had a "Switch Mode" of "At End".

  • @ss2cire
    @ss2cire 4 роки тому +2

    I couldn't wait until today so i set up the attack animation on my own, the process was easy enough.
    I didnt' think about adding the state machine though so I had an if statement checking for my attack key but your setup was much better, either way great video. Keep up the good work!

    • @mindstreamx
      @mindstreamx 4 роки тому +1

      Same for me. Actually added roll as well but I need to see how the position will be updated. I can only think of the function call strategy as of now.
      EDIT: Ok finished Roll without function call and it looks pretty good. Maybe there is a better way but we will see.

    • @ss2cire
      @ss2cire 4 роки тому

      @@mindstreamx yup, I added Roll too =) I'm currently working on trying to add the "special" attack (spin) but cant figure it out :-\

    • @marktriestolive1781
      @marktriestolive1781 4 роки тому

      @@ss2cire am i thinking right about this? just add all attack animations and just bind the animation on a certain key and it will do it when pressed? :D

    • @ss2cire
      @ss2cire 4 роки тому +1

      @@marktriestolive1781 sure but you still need states to make sure you can go from attack to roll ... unless that's the intent... for a smple tame you'd probablly want mke sure all modes shkft from idle.
      but it's up to you! that's the nice rhing about the setup

    • @marktriestolive1781
      @marktriestolive1781 4 роки тому

      @@ss2cire yes, yes ofc. still a newb on the engine and i will apply what i just learned. now just waiting for dmg part and enemy ai to be added. oso, camera thing :D

  • @jamessteele9170
    @jamessteele9170 2 роки тому

    This is probably the best tutorial series for learning GODOT basics and good practices. Excellent work!

  • @tejaswithme3713
    @tejaswithme3713 Рік тому

    25July'23: Completed part 9. Noted everything down in my notebook. Very informative...!

  • @brunokaiser3497
    @brunokaiser3497 2 роки тому

    I'm really enjoying all your tutorials man! I watched a few other people teaching Godot, but amongst them, your style fits me the best!!

  • @daveseid5312
    @daveseid5312 4 роки тому

    Was previously stuck trying to understand enums, your tutorial explained it perfectly in a couple of minutes. Thanks!

  • @DyIanGaming
    @DyIanGaming 9 місяців тому

    These are the best goody tutorials I’ve ever seen, thank you

  • @pascalladal8125
    @pascalladal8125 4 роки тому +18

    Great vids again :) There's a bunch of things that triggered me as a programmer though. In order of importance in my opinion. The first one being VERY important.
    1) NEVER ADD A PARAMETER TO A METHOD IF YOU DON'T USE IT. (the delta in the attack_state method)
    It is really a bad practice to declare parameters in a method signature if you don't use it, even if you plan to use it. In fact, I'm quite sure the warning you have right now in your debugger is actually saying so. This is a great way of adding confusing, useless complexity to your code.
    Basically, if you need it, put it. If you don't, don't put it.
    2) DON'T MIX LOGIC IN YOUR METHODS TO ACCOMPLISH SOMETHING YOU WANT (adding the animationTree.set("parameters/Attack/blend_position", input_vector) in the move_state)
    Your reasoning behind it was very good, but the way you implemented it is somewhat hackish.
    It doesn't make sense that your move_state would do attack logic and it is also a great way to make your code very confusing as you scale up.
    You're saying you don't want the player to change direction when he is attacking and you don't have access to input_vector outside move_state. Good! Then find a way to access it. A really easy and intuitive manner to do this, and this is what I've done, is to declare a variable outside the move_state method that actually keep track of what you want -->
    --at top of the Player script
    var player_orientation_vector = Vector2.ZERO
    --inside the if statement that checks if you're pressing an input
    if input_vector != Vector2.ZERO:
    player_orientation_vector = input_vector
    animationTree.set("parameters/Idle/blend_position", player_orientation_vector)
    ...
    --then you can write your attack_state method as follow
    func attack_state():
    animationTree.set("parameters/Attack/blend_position", player_orientation_vector)
    animationState.travel("Attack")
    3) METHODS SHOULD ONLY DO WHAT IT SAYS IT DOES (move_state should not handle change of states.)
    Ok so this might be arguable since the attack button is pressed when in the MOVE state but in my opinion, it should only be aware of what it does when in MOVE state and not handle the switch between states. I'd put the check on the Attack button outside of it. (check code below in number 4)
    4) This one is probably cause I'm too perfectionist, but I hate it when built_in methods starts to do complex logic. Like, _physics_process handling player states.
    Doing something like this, will make your code more readable and easier to scale -->
    func _physics_process(_delta):
    _handle_player_state()
    func _handle_player_state():
    match state:
    MOVE:
    move_state()
    if Input.is_action_just_pressed("attack"):
    state = ATTACK
    ATTACK:
    attack_state()
    Hope it helps some people improve their code. Take care! :)

    • @treadsideways
      @treadsideways 4 роки тому

      I'm semi following along with his code, and am now fixing according to your notes, but I have a couple questions cuz I'm a noob at this.
      so can delta be taken out of the code completely, if it's taken out of action_state and move_state?
      also, unrelated but something I've been struggling weeks with; I want a function that allows my player to place a tile beneath them. I have a 16x16 auto tile ready, but don't know how to code that function in Godot. Would appreciate any assistance!!

    • @ВладимирКарацупа-ш7х
      @ВладимирКарацупа-ш7х 4 роки тому

      Can you post full improved code pls?

    • @treadsideways
      @treadsideways 4 роки тому

      here's the updated code. My action animation doesn't return to walk or idle, thus the button is pressed, the action animation triggers, and then you can't interact with the player. Help!
      enum {
      WALK,
      ACTION
      }
      var state = WALK
      var motion = Vector2.ZERO
      var player_orientation_vector = Vector2.ZERO
      onready var animationPlayer = $AnimationPlayer
      onready var animationTree = $AnimationTree
      onready var animationState = animationTree.get("parameters/playback")
      func _ready():
      animationTree.active = true
      func _physics_process(_delta):
      _handle_player_state()
      func _handle_player_state():
      match state:
      WALK:
      move_state()
      if Input.is_action_just_pressed("Action"):
      state = ACTION
      ACTION:
      action_state()
      func move_state():
      var input_vector = Vector2.ZERO
      input_vector.x = Input.get_action_strength("ui_right") - Input.get_action_strength("ui_left")
      input_vector.y = Input.get_action_strength("ui_down") - Input.get_action_strength("ui_up")
      input_vector = input_vector.normalized()
      if input_vector != Vector2.ZERO:
      player_orientation_vector = input_vector
      animationTree.set("parameters/Idle/blend_position", input_vector)
      animationTree.set("parameters/Walk/blend_position", input_vector)
      animationState.travel("Walk")
      motion = motion.move_toward(input_vector * MAX_SPEED, ACCELERATION)
      else:
      animationState.travel("Idle")
      motion = motion.move_toward(Vector2.ZERO, FRICTION)
      motion = move_and_slide(motion)
      func action_state():
      animationTree.set("parameters/Action/blend_position", player_orientation_vector)
      animationState.travel("Action")
      func action_animation_finished():
      state = WALK

    • @plankcaller
      @plankcaller 4 роки тому

      actually thanks for this comment, i was checking my code because it crashed and it was literally the delta in attack_state() so yeah great thank you
      edited yet again: i kinda get it but when i try to use
      func _handle_player_state():
      match state:
      MOVE:
      move_state()
      if Input.is_action_just_pressed("attack"):
      state = ATTACK
      godot returns an error "Too few arguments for "move_state()" call and if i try to add (delta) as an argument it says the delta identifier hasn't been declared. so what's going on?

    • @pascalladal8125
      @pascalladal8125 4 роки тому

      @@plankcaller sorry that was my mistake, you need it in the move_state method. You're method move state must declare it in its signature(method declaration).

  • @joaolucassantosviegas3334
    @joaolucassantosviegas3334 Рік тому +1

    Nice tutorial man, your tutorial series are awesome.
    Note: You could've been used the auto-advance condition to use as check if the state/animation was done. You only needed to set on _ready() call to set the initial condition value and only a if would be necessary to state back to idle for example.

  • @kurdtcoben
    @kurdtcoben 4 роки тому +1

    Not sure if it is mentioned in a later video but I wanted to share some advice for y'all regardless:
    Please, if possible, do yourself a favour and use enums instead of if statements. Not only is it easier to type out, more importantly, it's more efficient.
    Try to think of it this way: With if statements, you go down a list of options and check each step if the statement is true (is he called Carl? no? is he called Daniel then? no? is he called Edward then? yes. ok!). With an enumerator, your basically jumping to the correct location in the list instead of looking up all previous ones (I'm looking for Edward, so I'm going to skip the names starting with C and D). It might not seem like much at first thought but it adds up over time and it's a good habit to avoid this from the get-go.

  • @CrisMW98
    @CrisMW98 3 роки тому

    Should have watcher this series WAYYY sooner. Great stuff!

  • @dard1515
    @dard1515 Рік тому +2

    For Godot 4, I couldn't figure out how to make the attack animation finished function to work properly. So I spent three days working on a bunch of stuff, but I landed on how to make it work with Signals. You learn the basics of Signals in the next video, but here's what I did.
    First, you should know that the next video explains how to connect a signal to a node, that will then generate the function for you. For this code, I used the animation_finished signal, so it generated a function with an appropriate name for me, and has pass in it by default for me to replace with my code. Now the actual code.
    func _on_animation_tree_animation_finished(anim_name):
    if anim_name in ["AttackRight", "AttackLeft", "AttackUp", "Attack Down", "Roll Down"]:
    state = MOVESTATE
    The function that Beastheart made in this video, in combination with the Call Method track, recreates the functionality of connecting signals. But if it's not working then I hope this helps you.

    • @nelsonguedespaulojunior977
      @nelsonguedespaulojunior977 10 місяців тому

      Hi, I just discovered how to make it work in Godot 4. The problem is that on the method line, on the editor, it has a small green ball in front of it. When you click there, it will turn off and then you can move it on the timeline. You need to position this ball on the last time of the track (when you create it, it appears to create after the time the animation is finished, so it never gets called).

  • @nahomaraya2377
    @nahomaraya2377 4 роки тому +20

    16:27 the fox became a jojo character

  • @donovangreene2348
    @donovangreene2348 4 роки тому +2

    I don't know if it will break anything later, but I really didn't like adding the function call to the animation, so I developed a different approach. I changed the Attack animation to auto transition in to the Idle animation, added a change_state function which handles everything that needs to move to a new state, and changed the attack_state to detect when the animation is "Idle". Instead of directly setting the state, you call the change_state function with the new state. Here's the code and it works exactly as expected:
    if Input.is_action_just_pressed("attack"):
    change_state(ATTACK)
    func change_state(new_state):
    match new_state:
    ATTACK:
    animationState.travel("Attack")
    state = new_state
    func attack_state(delta: float):
    if (animationState.get_current_node() == "Idle"):
    change_state(MOVE)

    • @nbk4191
      @nbk4191 4 роки тому

      iam finish the code and repet the video many time but there is lag when player move can you help me

  • @MIAM_MIAM_CUISINE
    @MIAM_MIAM_CUISINE 4 роки тому +3

    Noticed a weird issue on my end where if I try to go Up+Left and press the Space key to play the attack it doesn't play, yet if I use another key (such as the 'Z' key) instead the animation plays correctly, and the Space key seems to work just fine for any other angle.

  • @aarin.dreams
    @aarin.dreams Рік тому

    Hi, I just wanted to say that I REALLY REALLY love your Godot tutorial and the way you explain things are just useful since you point out errors as well. ^^
    I also have a request: could you please make a tutorial on how to make a customizable player and apply the customized player to animation and various movements?

  • @gentlemanduck2167
    @gentlemanduck2167 2 роки тому

    DUDE THANK YOU SO MUCH YOUR VIDEO IS THE ONLY ONE THAT HELPED ME DO THE FULL ANIMATION

  • @darrylwainwright5865
    @darrylwainwright5865 4 роки тому

    Best tutorial if seen so far, exactly what I need for my next project, thanks so much.

  • @troyootipep5
    @troyootipep5 4 роки тому

    Love following this series... Keep it coming HeartBeast

  • @vladyerus
    @vladyerus 10 місяців тому

    Would love to see a rpg tutorial for godot 4 using your components approach in the ship game but I’m using both video series bits and pieces and it seems to do the trick! Love your tutorial videos

  • @WoYoSensei
    @WoYoSensei 4 роки тому

    As always, great video, Mr. Benjamin! Looking forward for more!

  • @JustBobGaming
    @JustBobGaming 2 роки тому

    Just wanted to say thanks, doing a couple videos in this series a day and out of the 3 other game tutorials for this engine I have followed, while they were great in their own right. This is the only one were I feel empowered to go back and comment my code so I ingrain the information more and able to have my own reference game to look back at if I ever get a RPG itch. You can just tell you care about people actually taking something away from these videos and not just trying to finish a cookie cutter game in under X hours.

  • @Dante3085
    @Dante3085 2 роки тому

    Inputs maps in Godot are great. So easy.

  • @averysmith8662
    @averysmith8662 Місяць тому

    For anyone that's getting a bunch of errors after assigning the "Call Method" track at the end of each attack animation, the fix is simple.
    Animation Tree -> Inspector -> Callback Mode -> Change "Method" from "Deferred" to "Immediate".

  • @romulosendoromulo
    @romulosendoromulo Рік тому +1

    Awesome content, thanks!

  • @codywinter4818
    @codywinter4818 3 роки тому

    At 15:10 when you wanted the idle and attack transitions to be perfectly vertical it made me think of this- I looked but didn't see an option for it, maybe theres something like it I didn't see or it could potentially be a nice feature in future versions:
    In my video editor (DaVinci Resolve) when you're doing effects, theres a nodal workspace like the one in the animation tree. Theres an option to have all of the nodes snap to a grid, and theres another option called "orthagonal pipes", which makes all of the connecting lines between your nodes only appear as perfectly horizontal and vertical straight lines with 90 degree elbows where necessary. When these two options are turned on it can totally help keep your project organized looking and easy to follow when you start adding a lot of nodes.

  • @iTobiLP
    @iTobiLP 4 роки тому

    Hey Benjamin, I just want to let u know that I'm really enjoying ur tutorials, keep on rocking. Greetings :)

  • @Gifisha
    @Gifisha 4 роки тому

    As always, great content! Just picked up your 1-bit course too :D

  • @toggles4565
    @toggles4565 3 роки тому +3

    When you add the attack_animation_finished() function to the call stack, make sure the green diamond lines up with the line between 0.3 and 0.4. When I added the function it was adding it just after that line and it was confusing me why it wasn't run.

    • @philippwimmer4603
      @philippwimmer4603 2 роки тому +1

      haha same

    • @thumbtackj
      @thumbtackj 2 роки тому

      God bless you, sir! Could not figure out why my animations were stopping short.

  • @turtlehead447
    @turtlehead447 2 роки тому

    If you want the attack animation to depend on your mouse position instead you can create a variable in the move state function like this[var mouse_position = get_local_mouse_position()] and change the var in animationTree.set to mouse_position instead of input_vector

    • @turtlehead447
      @turtlehead447 2 роки тому

      also take out animation_tree.set("parameters/Attack/blend_position",mouse_position) and paste outside the if statement so it will work even when ur not moving

    • @turtlehead447
      @turtlehead447 2 роки тому

      also for the bug where your character will continues to attack if u change direction u can fix it by changing the dotted line inside the animationtree node to the line

  • @neckkeys5251
    @neckkeys5251 4 роки тому +3

    Awesome teaching skills you have here HeartBeast, keep going with your great tutorials. Do you have some way that we can tip or support you (patreon, etc..)?

  • @compasscrafting1147
    @compasscrafting1147 Рік тому +1

    Remember: when you're using Godot 4, velocity during the attack animation (the sliding bug he describes) is not an issue for you to resolve. Should work out of the box.

  • @FameMonsterD3
    @FameMonsterD3 3 роки тому +2

    for this to increase the sword swing speed you would just have to change the 0.4 to 0.2 or lower the time it takes to complete the animation, right?

    • @bobbytagget5389
      @bobbytagget5389 3 роки тому

      That's what I did, the sword strike in this video was wayyy too slow. put "0.01" in the snap textbox to make it easier and take each frame down by how fast you want the animation. I made mine 2x faster

  • @giannisgeorgiou
    @giannisgeorgiou 4 роки тому

    Excellent vid as always! Thank you!

  • @AussieToadDev
    @AussieToadDev 4 роки тому

    For those who are following along in C#, make sure you build your project (via mono) if your "functions" do not appear in the "Select Method" list.

  • @poketoscoparentesesloparen7648
    @poketoscoparentesesloparen7648 2 роки тому +1

    Ok maybe this is just my version of godot or something but
    when i click in the spacebar and down arrow and left arrow at the same time it just doesn't register the input for some reason
    not only it doesnt change animation but it doesnt even stop the character and i even wrote this check:
    func _physics_process(delta):
    if(Input.is_action_just_pressed("attack")):
    print( "attack")
    ...
    and it prints when i click up + right + space, , up + left + space , down + right + space but just doesn't print anything when i press down+left+space
    EDIT: i added J to the attack inpu and IT works for every direction... maybe its just some weird quirk with my keyboard?
    does anyone have a similar problem or is my godot just weird?
    if anyone knows what is happening please help me

  • @papiangelus
    @papiangelus 4 роки тому +1

    How do you not have more subs. You're the literal Brackey's of Godot. Keep it up!

  • @TobySimone
    @TobySimone 2 роки тому +2

    If anyone has a problem with the AnimationPlayer call method track and not being able to find your function in the popup window just restart Godot. Looks like there's a bit of a bug or something (I'm on version 3.4.2) where the "Insert Key" window isn't picking up changes to scripts. A restart fixed the issue though

  • @silveraddydwimores4085
    @silveraddydwimores4085 2 роки тому

    If you add an idle sprite to the attack animation, you will not need to add the function attack_animation_finished. In all I'm impressed we can add methods to the line of animation to detonate scripts along with said animations. It was worth to see that alternative technique just to open that venue of creative possibilities with the animation track.

  • @deenadayalan3562
    @deenadayalan3562 3 роки тому +1

    Now now I just have several questions.
    1. How do u attack while moving.
    2. How do u make combo. (Let's say we have 3 attack combo and then each attack is in different direction).
    Here the state mechanic won't help. Any idea?

  • @tanghoong513
    @tanghoong513 4 роки тому

    Thanks Sifu. Btw It is better to watch twice before first time pause and follow the setup, which may counter the same error of author itself.. but is good to experience the error for boosting the confident on debug.

  • @ZakRahman
    @ZakRahman 4 роки тому

    Absolutely fantastic. Quality content. Thank you.

  • @theternal
    @theternal 4 роки тому +12

    It's only 2 minutes but still I wish you more viewers :)

  • @mandaputtra
    @mandaputtra 4 роки тому +5

    "thats not what we want, well lest juat do that" 😂 I know your mind you want state machine to play animation based on direction too.

  • @cenourinha3995
    @cenourinha3995 4 роки тому +5

    its sad how heartbeast isn't recgonized on youtube ,he is the best on godot programing so i think that he"s no that recgonized here
    I wish he had at least 1 million that is what he worth
    =)

    • @nbk4191
      @nbk4191 4 роки тому

      iam finish the code and repet the video many time but there is lag whem player move can you help me

  • @JohnLaDot
    @JohnLaDot 3 роки тому

    absolutely incredible. thank you.

  • @rbaleksandar
    @rbaleksandar 4 роки тому

    The only additional issue here is the fact that (probably due to the lack of depth) the attack animation goes through bushes (actually cool) and cliffs (looks as if the sword is being swung above the cliff). But I guess for a beginning we need not be picky. :P

  • @buradley317
    @buradley317 4 роки тому +2

    I ran into a weird issue adding the attack animations. Somehow the left attack "update mode" was set to "continuous" and not "discrete" which resulted in the animation skipping the last frame (I don't recall changing this, and it's a drop down so doesn't seem like a likely mis-click). Oddly, some of the run animations (which I hadn't touched since that part of the tutorial) were changed as well. I haven't been able to replicate the issue once I changed them all back to discrete, but it was a bit of a head-scratcher, just thought I'd share.

    • @nbk4191
      @nbk4191 4 роки тому

      iam finish the code and repet the video many time but there is lag whem player move can you help me

    • @fredericonunes5320
      @fredericonunes5320 2 роки тому

      Helped me :D

  • @spooki-2451
    @spooki-2451 4 роки тому

    i usually use switch statements a ton in C++ and actually wondered why they weren't in godot , it turns out they were always here after all ; in form of that match statement syntax . Thanks for letting me know !

  • @arnomleonam149
    @arnomleonam149 4 роки тому

    Your videos are helping me a lot! Thanks bro!

  • @SchneiderRob
    @SchneiderRob 2 роки тому

    Awesome videos dude.

  • @infomastercode6961
    @infomastercode6961 4 роки тому +2

    Is it possible? if we don't used the Animation Tree.

  • @chickeninabox
    @chickeninabox 4 роки тому +2

    I have printed and the states are not changing.
    (Edited Section.)
    I fixed it by making "Input.action_pressed" to "Input.is_action_just_pressed."

  • @mihai-alexandrubujor9826
    @mihai-alexandrubujor9826 4 роки тому +5

    Hey, will this game have a menu and? And could you make a level-up system? Some bosses maybe?
    Anyways, great video as always!

  • @karim8030
    @karim8030 Рік тому

    first of all THANK YOU, for showing me how to call methods at the end of animations. I'd been searching, for days, for a way to allow single animations to repeat with the animation tree. Do you know of any other ways of doing this? Improvements or alternatives to the workflow of doing repeatable animations.

  • @msbeccafae
    @msbeccafae 2 роки тому +2

    All of my attack animations work except for the down one. When I try to hit the input key to attack while moving down my player just goes idle and I can't move. Does anyone have any idea why this is? I've looked at my AttackDown animation and it looks correct.

    • @Astrellaable
      @Astrellaable Рік тому +1

      I had the same issue, and somehow had ended up coupling IdleDown instead of AttackDown in the AnimationTree.

  • @pvpworld
    @pvpworld Рік тому

    I can't figure out why i'm getting this error
    Invalid call. Nonexistent function 'move_toward' in base 'int'.
    on this line :
    velocity = velocity.move_toward(input_vector * MAX_SPEED, ACCELERATE * delta)
    I've went back to copy the videos again but it keep happening and no luck on google

  • @icefoxzettai
    @icefoxzettai 4 роки тому

    Another way to change the state at the end of the animation would be using Signals (which would be a new topic and maybe that's why you didnt use it in this video), connecting the AnimationPlayer's animation_finished signal to the Player script, then checking if the state is equal to ATTACK, or using a "match" in there too.

  • @mccordinator
    @mccordinator 2 роки тому

    You didn't need to set the attack animations on loop to see them in the AnimationTree vector graph just needed to change the Blend to the dots :)

  • @thunderbear06playsstuff63
    @thunderbear06playsstuff63 3 роки тому +1

    Dude even a bear could understand this, 11/10

  • @sekaamv
    @sekaamv 3 місяці тому

    wow input mapping is cool got my controller mapped too this is starting to look like a real game. Still confused on tile maps since its so different in version 4+

  • @spaghettiman512
    @spaghettiman512 3 роки тому

    6:43 : When you fu. have errors ...
    Love the commitment

  • @sindred3530
    @sindred3530 3 роки тому

    Btw switch-case in c++ can use the enum names ;)
    E.g
    enum class serialKillers { TedBundy, PedroLópez, JohnWayneGacy } and switch(serialKillers) { case serialKillers::TedBundy: break; }

  • @gigapowerpt275
    @gigapowerpt275 3 роки тому +3

    20:56 i need help, it isn't finding attack animation finished
    edit: i closed and reopened godot and now it works

  • @slaps_zrz
    @slaps_zrz 2 роки тому

    What a shame that I have NEVER heard in my 2 year developement in godot of the AnimationTree, or just never used it. I think it makes so much stuff so much easier!

  • @willwurtz
    @willwurtz 4 роки тому

    6:45 You were just about to throw the f-bomb young man 😂

    • @uheartbeast
      @uheartbeast  4 роки тому

      Nah, I've never said the f word in my life.

    • @willwurtz
      @willwurtz 4 роки тому

      @@uheartbeast I believe you :) I just thought you were about to say when you f*** up, then immediately said have errors and stuff.