Slay the Spire Clone Godot 4 Tutorial: Card Dragging & State Machines (02/08)

Поділитися
Вставка
  • Опубліковано 3 чер 2024
  • Welcome to the second installment of the "Slay the Spire Clone in Godot" series using the powerful Godot engine! 🎮
    In this beginner-intermediate tutorial, we'll continue our game development journey by implementing the main card dragging mechanic for our game. Let's dive in!
    🚀 Part 2 - Card Dragging Mechanic & State Machines
    00:00 - Slay the Spire demo
    00:40 - End result
    01:29 - Creating the CardUI Scene
    08:23 - Adding CardDropArea and Hand to the Battle Scene
    13:06 - State Machine explanation
    15:43 - Basic CardUI and CardState base class scripts
    18:47 - Coding the CardStateMachine
    21:06 - Adding Nodes and Scripts for the 4 States
    23:00 - Coding the Base State
    25:09 - Coding the Clicked State
    26:21 - Coding the Dragging State
    30:27 - Coding the first version of the Released State
    30:55 - Hooking up all the systems, fixing bugs
    42:10 - Using the CardDropArea do detect if we should reset the CardUI
    46:27 - Fixing one last bug and wrapping up
    👩‍💻 Source code for Season 1 on GitHub:
    github.com/guladam/deck_build...
    🎓 Learn More About Godot:
    Godot Docs:
    docs.godotengine.org/en/stabl...
    docs.godotengine.org/en/stabl...
    Heartbeast:
    • Godot 4 Tutorial - Hea...
    Card Fanning Tutorial by Bramwell:
    • How I Fan 3D Cards in ...
    ☕ If you want to support me, buy me a coffee at:
    ko-fi.com/godotgamelab
    🔥 Connect with Me:
    Instagram: / adamgulacsi
    Twitter: / adam_gulacsi
    Mastodon: mastodon.gamedev.place/@guladev
    #godot #godotengine #2d #tutorial #godotgamelab

КОМЕНТАРІ • 189

  • @godotgamelab
    @godotgamelab  6 місяців тому +29

    Hey Everyone!
    Thanks for the overwhelming support you showed with this series so far! :)
    I just wanted to let you know that I added timestamps and chapters for my videos so hopefully it's easier for you to navigate if you want to.
    (you can also find them in the video description)
    Keep on cookin' and Cheers!

  • @AbsolutelyMindBlowin
    @AbsolutelyMindBlowin 6 місяців тому +32

    I like how much in depth you are going with the architecture.

    • @godotgamelab
      @godotgamelab  6 місяців тому +3

      Thanks, I appreciate it! I believe breaking it down is a good way to learn these things!

  • @LuizMoratelli
    @LuizMoratelli 6 місяців тому +23

    So good to see a series with good code / architecture!

    • @godotgamelab
      @godotgamelab  6 місяців тому +2

      Glad you like it! :)

    • @nandomax3
      @nandomax3 6 місяців тому +7

      Right? I'm a little bit tired of tutorials with messy code and zero architecture thoughts

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

      @@nandomax3 "Vomit on his IDE already, code spaghetti!"

  • @718Outdoors
    @718Outdoors 3 місяці тому +7

    I love how you show the final result of the episode at the beginning

  • @jmh6559
    @jmh6559 2 місяці тому +3

    I really loved the part that explained the principle and function of the object to be implemented step by step by taking the elevator as an example before working on the code, which most tutorials didn't put in even its the simplest and most central part as a "tutorial". So much appreciate for a great video and series!

  • @Soroosh.S83
    @Soroosh.S83 5 місяців тому +4

    You don't know how much it helps when you add chapters. The tutorial itself is great I love how you maintain to teach us with patience and good quality I'm more excited to see more of this series ❤

    • @godotgamelab
      @godotgamelab  5 місяців тому +1

      Thank you so much for your kind words, glad to have you with us! 🧪🥼

  • @lexsdragon1554
    @lexsdragon1554 5 місяців тому +3

    omg this series is exactly what I needed! Thank you so much!

    • @godotgamelab
      @godotgamelab  5 місяців тому

      Thanks for joining the Lab! 🥼🧪

  • @marcelburdon9795
    @marcelburdon9795 2 місяці тому +4

    I really appreciate how you run the program multiple times, and take little breaks going "this should work, right?" only to show us what we're missing, instead of just dumping all the correct code on the viewer right away. Explaining what is missing, or why it is necessary makes me understand the components a lot better. Also interesting to do input-mapping so late into the tutorial, usually UA-camrs knock that away in the first few minutes, without ever really elaborating on it, whilst you do the code first, and the mapping second, makes me actually understand just a little bit better.
    Despite having previous programming experience, GDscript is still a little tough on me, but I'm slowly learning, and hopefully after a few more videos I'll be comfortable adding my own additions! (like the 3D card fan, switching out the assets and themes, etc. and eventually adding my own non-StS gameplay mechanics) The Godot interface is still rather overwhelming, it's as if PhotoShop and Excel had a baby, with the sheer amount of menus and buttons, but your calm way of guiding the viewer through it is making it a bit more comprehensible.
    I'll try to maybe get a tutorial or two done daily (though I might be lazy in the weekends) and hopefully by the time I'm done I can get a little creative with the code!
    Statemachines are still a little scary, but I think I'm getting a hang of the logic, although the code formatting and syntax itself is somewhat complicated.

    • @marcelburdon9795
      @marcelburdon9795 2 місяці тому +1

      Ah! I've got a bug I can't seem to figure out!
      Moving the cards, changing states, all works seemingly fine. The cards can enter BASE, CLICKED, DRAGGING, and return to BASE... But when I release a card it remains in DRAGGING rather than changing to RELEASED... I've looked through the code multiple times, and everything seems to be in order, I've got no idea where I went wrong...

    • @NanoXzil
      @NanoXzil 15 днів тому

      @@marcelburdon9795If your problem is not yet solved:
      I also had this problem and it was because I forgot the "not" in the first if statement in card_base_state.gd.

  • @ahmadmuazmohaspa5106
    @ahmadmuazmohaspa5106 3 місяці тому +1

    Im not trying to do this, but once i got watching, im pretty convinced that im gonna watch the whole series for the sheer amount of knowledge ur spilling. thank you!

  • @aaronsommers9078
    @aaronsommers9078 5 місяців тому

    Great video! Thanks for creating this content that allows beginners to see some more complex code that is explained well, as well as well-organized! Knowing how to organize code efficiently is something that I have been struggling with, but these videos are a great example!

    • @godotgamelab
      @godotgamelab  5 місяців тому

      Glad to have you with us! ☺️👌

  • @Ocdib
    @Ocdib 6 місяців тому +3

    Very clear. Found you through your reddit post. I love your pace!

    • @godotgamelab
      @godotgamelab  6 місяців тому

      Thanks, I appreciate it 😊

  • @Ocdib
    @Ocdib 6 місяців тому +11

    One comment: when pasting code (esp. for signals, e.g.: signal transition_requested(from: CardState, to: State), it would help if you explain the thought process behind each function or signal a bit slower.
    EDIT: e.g.:18:10 onwards
    Thank you!

    • @Ocdib
      @Ocdib 6 місяців тому +3

      Having a really hard time understanding 18:47 - Coding the CardStateMachine, even though I generally understand signals and nodes :-( what do you suggest I do?

    • @godotgamelab
      @godotgamelab  6 місяців тому +7

      Hey I can try to clear it up for you a bit:
      The State machine does two things really:
      1. Keeps track of which state we are currently in
      2. Manages transitioning from one state to another.
      To help code the states themselves (base state, clicked state etc.) we also delegate callbacks like input_event() and mouse_entered() so the state can handle those events individually.
      The transition_requested() signal is used to provide a way for the CardStates to send a message to the State machine saying hey bro: I'm a base state but I want you to go into the clicked state when the user clicked on the card.
      When transition from one state to another two things happen:
      We call the exit() function of the old state,
      Then we call the enter() function of the new state.
      Does that help? I hope so, let me know if there's anything I can do to clear it up!

    • @nandomax3
      @nandomax3 6 місяців тому

      @@godotgamelab good explantion. I understand why you implemented the _on_transition_requested(from, to) signal now. At the moment only the CardStateMachine is listening to this event, but in the future we could attach other script to it to play sound, trigger other actions, and so on. I think I'm going to start a new study project here based on the space invaders theme and i'll use the knowledge you shared with us in this tutorial. I want a simpler base project to consolidate my learning, I'll create a simple FSM with three states move, fire states for the ship and a FSM for the enemy with just move and death states. I'll try to sketch it first and return to the tutorial just to clarify doubts about how you implemented yours

  • @reIMAGEN
    @reIMAGEN 21 день тому

    This is a great series. Wonderful work mate.

    • @godotgamelab
      @godotgamelab  21 день тому

      Thanks mate! Glad you like it 😌

  • @yogiwiguna9602
    @yogiwiguna9602 6 місяців тому

    Thanks for the tutorial keep it going. It's help me to learn about the State Machine more , still a little bit confused but i try to watch it over and over again.

    • @godotgamelab
      @godotgamelab  6 місяців тому

      Hey, happy to help!
      If you're still confused about state machines I recommend checking out @TheShaggyDev 's channel, he makes some awesome content on the topic! 👌

    • @yogiwiguna9602
      @yogiwiguna9602 6 місяців тому +1

      @@godotgamelab
      Thank you so much, i will check it. I try make the card game, this video really helped me with the implementation of the dragging and the others.

    • @nandomax3
      @nandomax3 6 місяців тому +1

      ​@@yogiwiguna9602 I also had some difficulties learning how to implement state machines, but after copying the simples exemple from the ShaggysDev, I could bootstrap my learning curve

  • @attilasipos3481
    @attilasipos3481 4 місяці тому

    Kúltúrált és megfelelő technológiát használ az úr!
    Emellett értelmes kódot ír!!!

    • @godotgamelab
      @godotgamelab  4 місяці тому

      Hoppá hoppá! Köszönöm uram! 😍

  • @421LIZO
    @421LIZO 6 місяців тому

    thank you. keep it going!

  • @dommychi
    @dommychi 13 днів тому

    Just started with Godot and I'm loving this tutorial!
    Just got a question:
    When releasing the card outside of the card drop area, what input event is activating the on_input function to make it return to the base state?
    Edit: I printed the event as text and it came back as a Mouse motion event. So when I drag the card by holding down the left mouse button then I release the card by releasing the left mouse button, how come a mouse motion event gets triggered after I release the card?

  • @nandomax3
    @nandomax3 6 місяців тому +1

    Amazing content. I was wandering how to expand the concepts tought by the shaggy dev on the Advanced State Machine video to use signals to change states too. Your implementation looks really similar to mine, although I don't like the request_transition(from, to), it's a nice way to organize those piece of code

    • @godotgamelab
      @godotgamelab  6 місяців тому

      Thanks, I'm glad you like it.
      As it's often the case in programming, there are many different ways to implement FSMs but I felt like using signals is a very "Godot way" to do it.
      In the end, I believe that for your own project, you should use a method that makes the most sense to you. But it's always a good thing to keep an open eye and open mind! 👀

  • @RafaMartinelli
    @RafaMartinelli 6 місяців тому +4

    Loving this, I've always wanted to create my own card game!
    Quick question: What's the difference between func name(): and func name(): -> void?
    Is the -> void part absolutely necessary after each func or is it redundant?

    • @godotgamelab
      @godotgamelab  6 місяців тому +6

      Hey, thanks for the feedback, glad to have you with us! 😌
      As for the void return value I'll give you a pros and cons how about that?
      Pros:
      - easier to read to code at a glance (you see that it won't return a value right away)
      - using static typing makes GDscript a tiny bit faster (though might be insignificant in this case)
      - keeps the code consistent (I try to use static typing everywhere)
      Cons:
      - more verbose
      - takes more to time to write for *seemingly* no reason
      - you might consider it to be redundant
      In this case, I think the pros outweigh the cons but it's really up to you and your personal preference. Hope I answered your question! 😌

  • @XenoFect
    @XenoFect 10 днів тому

    Awesome indepth series! Thanks for sharing!
    When you connect the signals how did you have the -> void: show up automatically? was that the magic of editing?

    • @godotgamelab
      @godotgamelab  10 днів тому +1

      Not magic actually! You can turn on static typing as an editor setting:
      Quoted from the docs:
      "If you prefer static typing, we recommend enabling the Text Editor > Completion > Add Type Hints editor setting. Also consider enabling some warnings that are disabled by default."
      docs.godotengine.org/en/stable/tutorials/scripting/gdscript/static_typing.html
      Super useful! Also, thanks for the kind words 😌

    • @XenoFect
      @XenoFect 10 днів тому

      @@godotgamelab Awesome! Thanks for the info and the super quick response!

  • @seanwade7824
    @seanwade7824 5 місяців тому

    Really getting a lot out of this - thank you for taking the time to put this together!
    Hoping you can help give some direction - the drop point detector for releasing cards seems to be triggered based on the bounds of the CardUI itself, not the mouse pointer. Is there any way to base that drop point snapping back to hand functionality on where the mouse is at when releasing, rather than where the bounds of the cards are? Because the way it's currently implemented, a card enters 'RELEASED' state on confirm even if just the very top of the card border has entered the card drop zone.

    • @godotgamelab
      @godotgamelab  5 місяців тому

      Hey, sure.
      That shouldn't be too hard to change. Here's a soluition from the top of my head:
      1, in the CardUI change the DropPointDetector's collision shape to a smaller rectangle, like 10x10.
      2, update the CardDraggingState code, and change the card_ui.drop_point_detector.global_position to the mouse position when you start dragging the card
      3, in the CardBaseState reset the card_ui.drop_point_detector.global_position to it's original position
      and you should be good to go! :)

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

    amazing tutorial. here's some engagement to bump it up in the algo

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

    Hi Adam, thanks for this video, I love your content. Please continue!
    I would also like to leave my comment to suggest an improvement for this episode since I found it hard to follow and I perceived it as rushed.
    I would have preferred to have an intro to the Input system of Godot either here or a link to another video, because it was hard to follow the part about propagation.
    I Would have change the way you present the state transition by first creating Base -> Drag and then presenting the full architecture and in the end write the rest of the code. I am a programmer and the code and the state machine principle were not the problem. What I found hard was that I had to follow you switching between signals, direct reference in the code, some other mechanism of reference by group. I was also not expecting to find the state machine implemented as sub nodes instead of just class instances.
    I will re-watch the video a second time.
    Love your content !

    • @godotgamelab
      @godotgamelab  Місяць тому +1

      Hi, thanks for the kind words and the suggestions.
      I agree with most of what you've said. At the same time, this course was created for people who are already somewhat familiar with Godot. I tried to strike a balance of not over explaining because the videos are quite long already.
      But you are a 100% right, this comes at a cost of sometimes having less structured explanations. Hopefully you'll find the other episodes clearer!

  • @kevintrueblood1057
    @kevintrueblood1057 5 місяців тому +3

    This is an amazing series so far and I look forward to watching the rest of it.
    I think you're doing a great job of keeping concepts at the beginner / intermediate level. I am someone who knows more or less what the nodes are meant to do and has cobbled together a few small projects. Especially without a computer science background, knowing design patterns or game architecture is invaluable, and is teaching me stuff I didn't even know I needed to learn. You're doing a great job of explaining the "why" as well as the "what".

    • @godotgamelab
      @godotgamelab  5 місяців тому +3

      Glad you are enjoying it, nice to have you here with us! 😊
      Thank you for the feedback, I'm happy to see you're learning new stuff!

  • @derekc.7689
    @derekc.7689 20 днів тому +2

    I'm around episode 5 now, but I went back to this state machine and I have a few questions:
    - I can't help but think the "clicked" state is redundant. Even looking at the season 2 code, it doesn't seem to do anything other than go straight to dragging. Why not simplify so that base goes straight to dragging?
    - What's the difference between on_input and on_gui_input? Around 20:00 we add both of them, and it seems like we sometimes use one and sometimes the other. From what I can tell they're not built-ins, so I don't really see why both are needed.
    Thanks for making this series! I have some background in programming but game dev is new to me - it's been a great help!

    • @lukelearley
      @lukelearley 14 днів тому

      i am also curious why there is a need for a "clicked" state. i was able to remove it in my game and go straight to the dragged state, but needed to increase the "DRAG_MINIMUM_THRESHOLD" variable to avoid transitioning directly to released. maybe it has something to do with that?

    • @vexave
      @vexave 12 днів тому +1

      I'm only at episode 2, but I think I can answer your second point.
      You're correct with the fact that the "on_input" and "on_gui_input" method in "card_state_machine.gd" and "card_state.gd" aren't built-in.
      But they get called from "card_ui.gd" through "_input" and "_on_gui_input", and those are built-in signals.
      In terms of difference, I think "_input" always accepts the input while "_on_gui_input" only accepts the input if the cursor is on the CardUI.
      For example, if you change the "on_gui_input" in the "card_base_state.gd" to "on_input", you end up dragging all cards at once wherever you click.

    • @godotgamelab
      @godotgamelab  12 днів тому +2

      Hey everyone,
      Thanks @vexave for explaining, you summed it up nicely!
      If you want to read more on Input, here's the relevant Docs page:
      docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html
      On the gui_input signal itself: docs.godotengine.org/en/stable/classes/class_control.html#class-control-private-method-gui-input
      In terms of the ClickedState, here's my two cents:
      - it's an easy concept to understand when you list all the States you can have: Base, Clicked, Dragged, Released. Pretty intuitive if you ask me.
      - It can happen, that you click on the card but don't move your mouse. In my mind that is clicking and not dragging if I don't move the mouse. There's no way to handle this seperately if you instantly transition into dragging.
      - UI is always the part of a game that changes the most during development. IF you want to do anything in the future ONLY when you are in a clicked state it's much easier to implement then blending those 2 states together.
      I would argue that it's so simple to implement that you don't lose a lot of time, it's more flexible and it even makes more sense to me as it's easier to draw the StateMachine's possible transitions. That said, if you feel like it's superfluous you can always go directly into the dragging state instead! Do whatever makes sense to you! :)
      Hope that helps!

  • @alexdoessudokus
    @alexdoessudokus 4 місяці тому +2

    First of all thank you for this series, I'm just watching it through the first time to get to grips with the concept before coding along side on my second watch to make sure I understand what's going on.
    However I noticed something in this episode (sorry if you address it later): You take the CardUI out of the hand immediately on drag state, and then reparent it on release if it needs to go back - doesn't that change the order of the cards instead of restoring them to the original order?
    I know in Slay and Monster train at least - cards always snap back to their original position in the hand, which will be important for mechanics like random discard and exhaust. Just wanted to check and make sure I'm getting this right!
    I'm thinking when I approach this part I'll only take CardUI out of the Hand on release - but I don't know if that would cause other issues?

    • @godotgamelab
      @godotgamelab  4 місяці тому +3

      Glad you started doing the series! Don't worry, we'll fix this down the road. Nice catch!

    • @alexdoessudokus
      @alexdoessudokus 4 місяці тому

      @@godotgamelab Awesome thanks! I’m not surprised that you’re covering it later, considering how well you pick up the quirky bugs at the end of the episodes, and then providing great explanations and solutions to them. Really great way of teaching - since bugs are generally more memorable and it’s a good way of really getting students to remember it in the future. Thank you for doing this series and I’m looking forward to more :)

  • @Lander_Calcoen
    @Lander_Calcoen 2 місяці тому +1

    Hi, @godotgamelab. I have a error:
    Error at (18, 9): Cannot call non-static function "enter()" on the class "CardState" directly. Make an instance instead.
    What do i do?

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

    Curious, my cards are not showing as base but I cannot find any errors that could guide me to the issue.
    Can you tell me what lines or functions I need to check to find the issue.

  • @itadaimasu
    @itadaimasu Місяць тому +1

    Hi, great tutorial. I have an issue, I « cannot call « non static function « is_node-ready » on the class « CardUI » directly. Make an instance instead. » does anyone know why and how to fix it? Thanks

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

    Wonderfully done, and exactly the series I need as a jumping-off point!
    minor note: the naming format you're using is called snake case, not pascal case
    snake = my_variable_name
    pascal = MyVariableName

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

      Yeah I keep messing that up, even in season 2 😂 I swear I know the difference but bruh. For some reason, speaking English messes up my brain sometimes I guess 🐍

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

      @@godotgamelab The fact that you're putting out such quality content in a second language is hella impressive

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

      @@TylerAlbers01 thanks, that means a lot me! Glad you like it 😊

  • @MuseDoes
    @MuseDoes 2 місяці тому

    Hey, love the videos so far, but I am having an issue with the CardStateMachine node. The class CardStateMachine doesn't appear in the Inspector window for me. I'm unable to change its default state to Base. All of the children within the CardStateMachine have the CardState class and I can select their States. Just not their parent node. Is there a way to fix that?

    • @godotgamelab
      @godotgamelab  2 місяці тому

      Have you created the script for it? Make sure you attach the CardStateMachine script to that parent node. If you have the proper code for that class, the export variable will appear in the inspector!

  • @LiinksGaming
    @LiinksGaming 16 днів тому

    Hi i followed the guide and i dont ran into an error where the cards state dont change into BASE automatically and i cant hold them would you perhaps know the reason?

  • @Mechman2001
    @Mechman2001 4 місяці тому

    Great series! I have a bit of a question in the adding nodes and scripts for the 4 states section. I am unable to assign any states to the 4 nodes some reason. When I click assign state in the inspector tab, every node or choice is greyed out. I was only able to set a default state for the CardStateMachine node. How can I fix this? Godot 4.2.

    • @godotgamelab
      @godotgamelab  4 місяці тому

      Hey, it seems like the Editor doesn't recognize your state nodes as state type nodes. Make sure to:
      - assign scripts to those nodes
      - in their assigned script, don't forget the "extends CardState" line so they inherit all their properties from the base CardState class.
      If both of those are are done you should be able to pick them in the inspector. If still not, try Project --> Reload Current Project from the menu after checking both of them.
      Let me know how it goes!

    • @EvanGSinclair
      @EvanGSinclair 4 місяці тому

      @@godotgamelab I'm having a similar issue. Followed all your steps above but I don't even see the CardState option in the window, I can only see Node

    • @godotgamelab
      @godotgamelab  4 місяці тому

      @@EvanGSinclair If you didn't forget to attach the script to the nodes and followed all the steps, you might want to reload the editor.
      Go to Project --> Reload Current Project. Sometimes it solved issues like this to me. I guess these inconveniances are still expected with Godot 4. Lemme know if that helps!

    • @EvanGSinclair
      @EvanGSinclair 4 місяці тому

      @@godotgamelabworks now, I think the issue was something to do with the "Template" selected when making the initial scripts. Yours were "Object: Empty" mine were "Node: Default" . That's the only difference I could find.

  • @rafaeljm3204
    @rafaeljm3204 3 дні тому

    Thanks for the very cool tutorial.
    I have noticed that, towards the end when you code the snapping back to hand when releasing on the lower part of the screen, the released state reacts to the on_input callback. Following your video up until this point was smooth but I see after this a behaviour that is not intended. Basically, if I release the card but do absolutely no movement with my mouse after, since it receives no input, the card stays released even where it shouldn't, and it only snaps back to hand once I touch my mouse so that it moves. Any suggestions on how to tackle this?

    • @godotgamelab
      @godotgamelab  3 дні тому +1

      Hey, glad you like it!
      If you think this counts as a bug, you can submit an issue on the GitHub page:
      github.com/guladam/deck_builder_tutorial/issues
      I would appreciate if you could describe the bug, and provide some steps to reproduce it.
      Then, I will dedicate a whole video to fixing bugs at the end of season 2! :)

    • @rafaeljm3204
      @rafaeljm3204 День тому

      @@godotgamelab Okay! Submitted!

  • @TheCamulous
    @TheCamulous Місяць тому +2

    Hey, first I want to say this is an absolutely amazing series!
    I just have one problem I can't solve for the life of me. Everything is working with the exception of snapping the cards back to hand if you right click or play outside the play area. I've set up debug checks to see where it is going wrong. According to those everything is running and it seems that the child.reparent(self) call in hand.gd is running but simply not reseting the position of the card. I would love any direction on where to keep looking for issues!

    • @TheCamulous
      @TheCamulous Місяць тому +1

      Turns out the child.reparent(self) call was retaining the position of the child. To work around this I just replaced the reparent call with child.get_parent().remove_child(child) and self.add_child(child). It's not pretty but it works.

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

      @@TheCamulous I had a similar issue, so tried this workaround. However it appears that should you release the first card, then exit a move with your second card, it snaps back all cards, including the previously released card. Any ideas? Did you get similar behaviour?

  • @lukelearley
    @lukelearley 14 днів тому

    not sure if this is a bug or working as intended, but due to the way the "dragging" state only updates 'on_input', if you click and hold the left mouse button on a card, release it outside of the 'card_drop_detector_area' (in the hand or lower part of the screen), but do not move the mouse or click anything else, the card will float as though it is still in the "dragging" state until you do either move the mouse or click something.
    i was able to fix it by changing the 'on_input' function to a '_process' function, but i'm not sure how that will effect performance or interact with other systems down the line.
    oh, and thanks a ton for this series! i've been binging it over the past few days and really appreciating so many aspect of your presentation style.

    • @godotgamelab
      @godotgamelab  14 днів тому +1

      Hey,
      Thanks for pointing this out. Someone reported a very similar issue to this. We fix it later down the line!

  • @muxecoid
    @muxecoid 5 місяців тому

    Thanks for the training.
    Just a small note, the part with if from!=current state, should be with an assert, not just if.

    • @godotgamelab
      @godotgamelab  5 місяців тому

      Absolutely, you can use asserts if you want to generate error messages. Thanks for the tip!

  • @longuemire748
    @longuemire748 5 місяців тому

    Thank you for this tutorial, it's very interesting.
    but what is the purpose of the "on_gui_input" function in the script CardState (17:57)?

    • @godotgamelab
      @godotgamelab  5 місяців тому +2

      Thanks, glad to have you here. Great question!
      We provide 4 callback functions for the different States in our StateMachine which they can override.
      gui_input() is for GUI nodes specifically. We'll override this in the BaseState latern where we prevent any kind of interaction for that card when its disabled and shouldn't be interacted with. Hope it makes sense!

    • @longuemire748
      @longuemire748 5 місяців тому

      @@godotgamelab Sorry, I just saw the message, thanks for the explanation.

  • @dmsys6516
    @dmsys6516 6 місяців тому +1

    func on_input(event: InputEvent):
    I assume that this function will be triggered when any input is given?
    since there are no process function i assume that's how these system works
    But wait this is a ui node and i dont know much about them right now, so am i correct?
    If i am then are they triggered on every input set up in project's input map?

    • @godotgamelab
      @godotgamelab  6 місяців тому +3

      If you don't know much about how Godot handles input I recommend reading the docs:
      docs.godotengine.org/en/stable/tutorials/inputs/inputevent.html
      In short: _input(event: InputEvent) is called whenever an input event occurs. We can filter it out for our own desired inputevents we want to handle. In this game there are three:
      - left click (defined in the InputMap project settings)
      - right click (same)
      - moving the mouse while in the clicked state (it is called InputEventMouseMotion)

  • @Soroosh.S83
    @Soroosh.S83 5 місяців тому +1

    I love slay the spire I actually finished 1 playtrough with each character except watcher.
    I didn't defeat heart but even tho the experience was fun 😊

    • @godotgamelab
      @godotgamelab  5 місяців тому +3

      Come on, you can beat the heart, you got this! Just need a sprinkle of luck and a great deck! 🍀💪

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

    There is an issue here. If you move the mouse and then click on the card, the card immediately transitions from the 'Clicked' state to the 'Dragging' state. This is likely because the previous mouse movement event was also captured. How can one implement the action of moving the mouse, clicking, and then staying in the 'Clicked' state, only transitioning to the 'Dragging' state upon subsequent mouse movement?

  • @tinypixel343
    @tinypixel343 5 місяців тому

    I am really enjoying this series, I just did not really like the last part with the lambda function, your code is so well structured and the lambda parte made it look like it was rushed. I am changing that last part for a timer nested inside CardDraggingState node, when CardDraggingState enters, the timer starts and then connects to a function without a lambda function, it felt cleaner to do it this way.
    But then I caught myself asking, ok so he is very organized, is there any advantage to use that lambda? Maybe something I haven't learned yet...

    • @godotgamelab
      @godotgamelab  5 місяців тому +1

      Hey, I'm glad you like it so far. I think it's up to personal preference.
      If the timer + timeout feels cleaner to you do it that way by any means. Don't really see any advantage picking one over the other 🤔

  • @muxecoid
    @muxecoid 5 місяців тому

    In this example what guarantees on_input of released state to be called? In my tests it is mouse motion, but it feels a bit ugly to wait for input to return to base state. Checking the list of targets when getting out of dragging state feels so much cleaner.

    • @godotgamelab
      @godotgamelab  5 місяців тому

      I'm not sure what you mean by that. on_input() is called when whatever input event is registered for the card: this can be mouse motion, mouse clicks, actions pressed, anything really...
      Input-based cancels can only happen when we right click to cancel out the dragging, I don't see the problem of using the input callback for this. But use whatever you think is clean :)

  • @TheDonValerianos
    @TheDonValerianos 6 місяців тому

    Thanks for great tutorial. Thing became much cleaner for me. Especially when you point on issues and show how to address them.
    One thing I didn't catch up - why do we need and exit_state function? Looks like it does nothing for a current step of tutorial. So whats the purpose of it?

    • @godotgamelab
      @godotgamelab  6 місяців тому +1

      Glad to hear that!
      At this point, we don't really use it but sometimes we might. Later we use that logic, let me give you an example:
      When we start aiming with a single targeted card (i.e. go to the aiming state) we will notify another node (the CardTargetSelector) that we started aiming so we can display an arc and select an enemy.
      But when we finish aiming, we want to notify that same node that we finished the aiming process so it can hide the arc and turn off the target selector mechanic.
      However, we can finish aiming for 2 reasons:
      - we canceled it or selected an invalid target (we go back to the base state)
      - we selected a valid single enemy (we play the card)
      If you think about it, it doesn't really matter which happens because we want to turn off the target selector in both cases. For that reason, we can use the exit() function so whenever we leave aiming (for whatever reason) we can notify the CardTargetSelector that the aiming process has ended.
      Hope that makes sense and helps! :)

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

    I would've liked if you went back to the state machine graphic at the end and overlayed the script names we created to relate them all back to the concept.
    Also, I couldn't reproduce the click error at the very end (Godot Version 4.2.1). Followed those steps of course anyway!
    Likely gonna go through again and comment my code so I get what it does. It very much feels like to me like this is real properly written code with very good practices and things. Thanks!

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

      Good idea, thanks for the feedback! :)

  • @Ichthyoid
    @Ichthyoid 5 місяців тому +1

    Just started this series, thanks for putting it up!
    I noticed a small bug towards the end of the video (don't know if it'll get fixed later):
    If you click on a card without releasing the left mouse button, drag it over to the side (not inside the play area target), and then release WITHOUT moving the mouse, it'll go into the release state, but still stay stuck in its position. Then, only if you then provide any input, it'll snap back to the hand/base state. I think this may be a consequence of the input function being the only thing that transitions the release state back to base state?

    • @Ichthyoid
      @Ichthyoid 5 місяців тому +1

      I eventually fixed this through the dragging confirm code, checking for the target area there (if target area isn't empty, it goes to released, if not, it goes back to base). Hope this doesn't break any code down the road 😅

    • @godotgamelab
      @godotgamelab  5 місяців тому +1

      That's a good point, thanks for pointing it out. I'll look into it ☺️

    • @Ichthyoid
      @Ichthyoid 5 місяців тому

      @@godotgamelab the series is really great so far! I especially love how it’s not for beginners, since there are a lot of those kinds of tutorials. Going through and reading and thinking about the code you’re using is really helping me expand my knowledge of gdscript and coding in general! Thanks!

    • @godotgamelab
      @godotgamelab  5 місяців тому

      glad you like it and thanks for your kind words! :) @@Ichthyoid

  • @UnstoppableTigra
    @UnstoppableTigra 5 місяців тому +1

    hi. what is the purpose of line "var card_ui := child as CardUI" (in hand.gd). Is it for code readability ?

    • @godotgamelab
      @godotgamelab  5 місяців тому +6

      Sure,
      In your example we are referencing the CardUI node which is a Control Node in the SceneTree. The truth is that the code works perfectly fine without using the "as CardUI" bit.
      Let's see what is does. When we type "as CardUI" we cast it from a Control Node to a CardUI type. This way, when we use the variable's name in the script, we'll get auto-complete (intellisense) based on the CardUI class. The result is that you don't need to remember property names and functions precisely and it's easier to code while also it's less error-prone because you make less typos.
      Also, this is we use "class_name CardUI" at the top of our scripts! So we can use CardUI as our own custom type (class)
      You can try this if you start typing card_ui. in your code and press ctrl+space. You'll see all the suggestions correctly but if you delete the "as CardUI" bit, you'll only get suggestions based on the built-in Control Node class.
      I hope that clears it up a bit!
      If you want to refer to the docs, you should look up the reference page for GDScript itself:
      docs.godotengine.org/en/stable/tutorials/scripting/gdscript/gdscript_basics.html#casting

    • @UnstoppableTigra
      @UnstoppableTigra 5 місяців тому

      @@godotgamelabthanks for the detailed answer. Your tutorial rocks.

  • @lassepoulsen7591
    @lassepoulsen7591 12 днів тому

    Hello! i'm currently experiencing issues with the snapping back to the original position on right click, i can see from the text on the card that it does go back to base state, but it doesn't get the base state position

    • @godotgamelab
      @godotgamelab  11 днів тому

      Hey, you need to reparent it to the Hand so it goes back. When the game is running, you can use the remote SceneTree to check if the raparenting actually happens!

  • @sprooc
    @sprooc 2 місяці тому

    Hello, on the "card_dragging_state" and "card_clicked_state" I am getting an error saying that the identifier "transition_requested" is not declared in the current scope.
    From this error I have actually found a lot of stuff I missed trying to figure out what I did wrong but now everything looks like yours and it still says it is not declared in the current scope.

    • @godotgamelab
      @godotgamelab  2 місяці тому +1

      Hey, does your base CardState class exist? If so make sure that the CardDraggingState and CardClickedState actually extend that class where we defined that signal. Then, it should work!

  • @K0ll7n
    @K0ll7n 27 днів тому

    After adding CardStateMachine node and code for card states, i started getting next error: Invalid get index 'state' (on base: 'Control (CardUI)'), after tring to run the game, wich references line card_ui.state.text = "BASE" in card_base_state.gd script. Does abybodyhave some suggestions maybe?
    EDIT: I had a typo as always, namely wrote label incorrectly in card_ui script.

  • @davidReyGD
    @davidReyGD 6 місяців тому +2

    You have to grouw up with more subscriptors, I'm very boring to see always the same platformer series :) thnx! that's really hepful.

    • @godotgamelab
      @godotgamelab  6 місяців тому +2

      Thank you so much! Glad to have you with us! ☺️

  • @deftmute
    @deftmute 4 місяці тому

    When i enter the lines that are highlighted at 33:08, it tells me that an argument is expected for lines 24 and 28. I've triple checked my syntax and can't see any differences. Any idea what's up?

    • @godotgamelab
      @godotgamelab  4 місяці тому

      which lines you have problems with? there is no line 28 at 33:08

    • @deftmute
      @deftmute 4 місяці тому

      ​@godotgamelab it's the card_state_machine.on_mouse_entered and exited. They both say that they expect an argument. Sorry, I think my timestamp may have been the last frame it was on screen, but it was where I had it paused while rereading.
      Edit: I finally got some time and just started over. Pretty sure I figured out where I messed up. Everything is working and I am progressing now. Thank you for your time.

  • @Sal333k
    @Sal333k 4 місяці тому

    Hiya!
    I'm getting Parse Error: The function signature doesn't match the parent. Parent signature is "enter() -> void". This happens with the "initial_state.enter()" in the card_state_machine script. Not sure how to deal with it since i've been pretty much copying everything. Any advices or explanation would be awesome :)

    • @godotgamelab
      @godotgamelab  4 місяці тому

      Can you send me a pastebin link of your card_state_machine.gd and card_state.gd? It's hard to answer without seeing the code

    • @cobysuk-3294
      @cobysuk-3294 4 місяці тому

      @@godotgamelab I seem to have a similar problem, as there is an error stateing "Identifier "initial_state" not declared in current scope" on the "if initial_state:" line. I have been copying everything, so any help would be appreciated.

    • @godotgamelab
      @godotgamelab  4 місяці тому

      ​@@cobysuk-3294 sounds like you don't have the initial_state variable declared at the top.
      Here's the CardStateMachine class's final version from GitHub: github.com/guladam/deck_builder_tutorial/blob/5bad93421de9c0e1978ec842de31342f7f7e4137/scenes/card_ui/card_state_machine.gd
      Hopefully you can find what's wrong by comparing them.
      For the CardState and derived classes you can check this folder to see what's going sideways: github.com/guladam/deck_builder_tutorial/tree/5bad93421de9c0e1978ec842de31342f7f7e4137/scenes/card_ui/card_states
      Cheers,
      Adam

  • @jimdangle7213
    @jimdangle7213 4 місяці тому

    @GodotGameLab I am getting an Error within the card_base_state script: "card_ui" not declared in the current scope.
    where in the tutorial did you declare this? is it still uptodate or am I doing something wrong? hope you still read these comments!

    • @jimdangle7213
      @jimdangle7213 4 місяці тому

      Wow i am dumb, i typed in a previous script: vi instead of ui, that v really looked like an u :D

    • @godotgamelab
      @godotgamelab  4 місяці тому

      Happens to the best of us 😅 glad you fixed it!

  • @PeteReborn
    @PeteReborn 25 днів тому

    I've got a Mac with a trackpad. Unfortunately, I can't test a right click action.

  • @thetiphon
    @thetiphon 4 місяці тому

    What kind of input event we're handling in on_input function in release state 44:20? I assume that we are already handled release event in dragging state. We are just waiting for random event to happen? This code is weird for me

    • @godotgamelab
      @godotgamelab  4 місяці тому

      I think you're a bit confused about what get_viewport().set_input_as_handled() does. From the docs:
      "Stops the input from propagating further down the SceneTree."
      That means if we click with the LMB to confirm releasing the card, no other Node can pick up that left click. Omitting this can lead to some unexpected behaviour. For example, you start dragging a Card and you move it above another Card in your Hand. If you click with the LMB again, that SAME InputEvent (left click) can be picked up by the other Card.
      That's not what you want because in general you want one click to do one thing right? So if you click to release the first card it gets released. If you decide to pick up and drag another you want to click AGAIN for that which should be a new InputEvent.
      Does that make sense?

    • @thetiphon
      @thetiphon 4 місяці тому

      ​@@godotgamelab Actually not, this is not what makes me confused. My question is in what event case we are entering "on_input" function inside card release state? What event makes transition from release state to base state?

    • @godotgamelab
      @godotgamelab  4 місяці тому +1

      @@thetiphonOh, I see sorry. That was a misunderstanding from my part.
      Here, really ANY kind of InputEvent makes the card to go back to the base state because the enter() function gets called first when we enter the state.
      The on_input() callback function can only trigger AFTER the enter() function has already finished its execution.
      We have a flag called played which can be either true or false depending on whether we successfully played the card or not.
      In our on_input() callback we check this flag. If it's false AND we received ANY KIND OF InputEvent this card can get (left click, right click, releasing the card or just moving the mouse over the card for example) we can transition back to the base state because it means we couldn't play the card as we had no valid target.
      Does this help?
      If you're curious what event triggers this, put a print(_event) before the transition_requested signal and when you play the game you can see which event triggered this but it doesn't really matter.

    • @thetiphon
      @thetiphon 4 місяці тому

      @@godotgamelab yes, thanks. Your code architecture is great. Pleasure to see

    • @godotgamelab
      @godotgamelab  4 місяці тому

      thanks, happy to help! @@thetiphon

  • @gurkengerd9981
    @gurkengerd9981 5 днів тому

    The vocal fry is strong with you.... Good lord.

    • @godotgamelab
      @godotgamelab  4 дні тому +1

      I'm sorry you don't like my voice. Have a beautiful day regardless! 😊

  • @tars9063
    @tars9063 Місяць тому +1

    I hope to find an answer by myself in a few hours, but I have this problem, where only thing that's being processed by the game is first click. All the cards together go orange and @clicked", but no dragging or anything. Any ideas?

    • @XxKagarwaxX
      @XxKagarwaxX 22 дні тому

      I do have the same problem. Have you found a solution already by any chance or does anyone else have an idea?
      no matter where you click, it will permanently change the state of all cards to "CLICKED"

    • @tars9063
      @tars9063 22 дні тому

      @@XxKagarwaxX I believe I did. Will Get to the PC and check for you

    • @XxKagarwaxX
      @XxKagarwaxX 22 дні тому

      @@tars9063 you are my hero

    • @tars9063
      @tars9063 21 день тому

      @@XxKagarwaxX didn't find it then, found now. Check card_state_machine script, func on_input, if you have "current_state.on_input(event)" or on __gui__input

    • @XxKagarwaxX
      @XxKagarwaxX 21 день тому

      @@tars9063 thank you for checking back!
      Sadly I already have the current_state.on_input(event), so there is likely another mistake I have made.
      from the card_state_machine-script
      func on_input(event: InputEvent) -> void:
      if current_state:
      current_state.on_input(event)

      func on_gui_input(event: InputEvent) -> void:
      if current_state:
      current_state.on_gui_input(event)

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

    🤩

  • @fvhaudsilhvdfs
    @fvhaudsilhvdfs 4 місяці тому

    38:32 Could someone explain this part to me? Why does adding this variable fix anything? It doesn't seem like the variable name is being referenced anywhere so why would this prevent the crash that was just happening...?

    • @godotgamelab
      @godotgamelab  4 місяці тому +1

      Hey, I'll try my best:
      - this is a dependency for the CardStates because they might want to do stuff like animating the CardUI, calling methods on the CardUI and so on.
      - we declare this variable here to make sure that each and every CardState will have a card_ui available.
      - you're right: in itself it does nothing. However, in the CardStateMachine class, we will actually assign the parent (the CardUI node itself).
      - later in the video, when we code the CardStateMachine class we'll have az init() function where we set this variable.
      Hope this makes sense, cheers!

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

      @@godotgamelab oh shit. i think i missed that the individual card state scripts *are* already referencing the drop_point_detector var. so that makes sense why the crash was happening then. thanks for the explanation and the video(s)

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

    My cards will transition to the base state, but no matter what I do, I cannot get them to transition to “clicked”. I’ve double and triple checked and everything should be working. It seems to either be something in my settings or something where the base state does not emit its signal correctly I can’t seem to fix it.

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

      Hmm, there are a lot of ways this can go wrong... Did you connect the signals in the editor too? You need to connect the CardUI nodes signals to their corresponding functions.

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

      ​@@godotgamelab I got it all the way to the Dragging State. It will return to the base state on a right click. It will set to input_as_handled on a right click. However it will not register a mouse release nor will it transition to the Released state. The only difference in code is that I used on_gui_input instead of on_input.

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

      ​@@godotgamelabOkay, I went back and redid the video. There was a tiny error in my card_state_machine

    • @marcelburdon9795
      @marcelburdon9795 2 місяці тому +2

      @@nicholasmoreno6358 Hi! I've got the same problem where the card will enter CLICKED and DRAGGED, and return to BASE, but won't enter RELEASED, just staying in DRAGGED.
      I've looked through the code many times and can't seem to see any issue, what was your problem, maybe I'm experiencing the same?

  • @Lander_Calcoen
    @Lander_Calcoen 2 місяці тому

    Does this part of the tutorial work in godot 4.2.1 to?

  • @dimtool4183
    @dimtool4183 6 місяців тому

    so at 38:50 when starting to click and drag, when clicking anywhere at all, all three cards display "CLICKED", and nothing else happens at all. No errors either. Godot 4.2, Compatibility. But before this, when testing and hooking up, I didn't get exactly the same no-error or errors at same time as in tutorial.

    • @godotgamelab
      @godotgamelab  6 місяців тому

      Hey, haven't tried it with 4.2 but everything should be working I think. Make sure to double check these:
      - code for the State machine itself
      - code for the individual states
      - in the card UI scene, the state nodes should have their correct enum value type set as their export variable,
      - double check if you set the mouse filter options correctly for the Control nodes in the card UI script.
      Hopefully you can find what's causing this behaviour.

    • @dimtool4183
      @dimtool4183 6 місяців тому

      @@godotgamelab tested with 4.1, and also Mobile mode, same issue, also looked at most code and stuff (not all maybe, and probably missed something), can't find any mistakes yet, will report if I fix it.

    • @godotgamelab
      @godotgamelab  6 місяців тому

      @@dimtool4183 yeah it's probably in the code. If you can't find the mistake, you can zip the project and send it to me, so I can try to help. You can find my email in the channel page

    • @dmsys6516
      @dmsys6516 6 місяців тому

      I am also on godot 4.2 and this works like a charm

    • @Youngdeff1
      @Youngdeff1 5 місяців тому

      in the card_ui script make sure that the input function is "_input" and not "on_input" had the same issue and this fixed my problem also make sure to check the scripts that @godotgamelab mentioned

  • @RedCocoon
    @RedCocoon 29 днів тому

    Megacrit saw this and thought We could make this better

    • @godotgamelab
      @godotgamelab  28 днів тому

      oh mate, I wish I had that kind of influence 😅
      can't wait for the StS 2 though!

  • @Xipheos_
    @Xipheos_ 2 місяці тому

    Idk what I did wrong but I get "Cannot call method 'is_node_ready' on a null value. Im not able to fix it :c

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

      Fixed it

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

      Hi, how did you fix it?

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

      The hierachy was wrong in the CardStates, basically I make the Drag, Click and so on inherit from the Battle node instead of the CardStateMachine or however you called it like

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

      ​@@itadaimasuIf I have not explained myself good enough lemme know

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

    I should have missed something, but let me leave here my experience: moving position of cards in _gui_input might not work when your card is too small. _gui_input only sees what happens on the control, so it may lose the cursor if it moves quickly.

    • @godotgamelab
      @godotgamelab  3 місяці тому +1

      I don't really get it. I use pretty small cards too (20*30 pixels).
      Can you move them faster than the input event registers? That seems a bit weird but I need to test this.

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

      ​@@godotgamelab Thanks, you indeed got a point, this may not be a general bug but system-specific. I noticed my get_global_mouse_position() returns different coordinates every call.

  • @is_game_maker
    @is_game_maker 2 місяці тому

    Invalid call. Nonexistent function 'on_input' in base 'Nil'.。。。。。thats why?

    • @is_game_maker
      @is_game_maker 2 місяці тому

      If I press CTRL+INIT() and so on, I can jump to the function I wrote before in card_state_machine.gd, but I still get an error

  • @BarcelonaMove
    @BarcelonaMove 2 місяці тому

    I tried to follow this tutorial with C#, but the reparenting and signals part is getting out of hand. I think I will stick to gdscript even if i dont like it much...

    • @godotgamelab
      @godotgamelab  2 місяці тому

      There is someone in the comments who did the whole thing in C# under one of the videos...
      Maybe you can try to contact them?

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

    hi, I'm new to this series; great content so far! i'm making a deckbuilder myself and I approached the drag and drop using the built-in functions instead: _get_drag_data, _can_drop_data, _drop_data. do you have any thoughts/opinions on using them instead of your apprach? i feel like it can avoid the need for state machines
    here's what I followed: ua-cam.com/video/IaAqhIC5DaI/v-deo.html
    my cards call the _get_drag_data function
    my card drop areas call the _can_drop_data and _drop_data functions

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

      Hey!
      That works fine too, but I find it a bit too limiting for this game so I opted for a different solution. The Godot built-in version only works on Control nodes, and you have to set a preview which shows below the cursor. I feel like having more control over the dragging for a Card game is a worth trade-off if you have to / want to change things up later.
      If the built-in solution works for you however, I recommend sticking to it because it's actually much much easier then implementing it on your own like we do :)
      Cheers!

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

      @@godotgamelab well said! i'm going to try the built-in route as i follow along your course. props to your solution though, it really gives much more freedom to do what's needed. thanks for your perspective

  • @kardrasa
    @kardrasa 5 місяців тому

    Your channel icon kinda looks like Godot givin me the middle finger..

    • @godotgamelab
      @godotgamelab  5 місяців тому

      It's supposed to be a lab bottle. Nothing personal, promise 😅

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

    Great series so far! I'm a bit stuck unfortunately, I'm getting type errors in _on_transition_requested when I click my cards.
    E 0:00:01:0988 card_base_state.gd:14 @ on_gui_input(): Error calling from signal 'transition_requested' to callable: 'Node(Card_State_Machine.gd)::_on_transition_requested': Cannot convert argument 1 from Object to int.
    core/object/object.cpp:1140 @ emit_signalp()
    card_base_state.gd:14 @ on_gui_input()
    Card_State_Machine.gd:26 @ on_gui_input()
    card_ui.gd:18 @ _on_gui_input()
    However my card_state.gd seems fine:
    What could cause my transition requested to consider my from variable as an int?
    ------------------------------------
    class_name CardState
    extends Node
    enum State {BASE, CLICKED, DRAGGING, AIMING, RELEASED}
    signal transition_requested (from: CardState, to: State)
    @export var state: State
    var card_ui: CardUI
    func enter() -> void:
    pass

    func exit() -> void:
    pass

    func on_input(_event: InputEvent) -> void:
    pass

    func on_mouse_entered() -> void:
    pass

    func on_mouse_exited() -> void:
    pass
    ------------------
    class_name CardStateMachine
    extends Node
    @export var initial_state: CardState
    var current_state: CardState
    var states := {}
    func init(card:CardUI) -> void:
    for child in get_children():
    if child is CardState:
    states[child.state] = child
    child.transition_requested.connect(_on_transition_requested)
    child.card_ui = card

    if initial_state:
    initial_state.enter()
    current_state = initial_state
    func on_input(event: InputEvent) -> void:
    if current_state:
    current_state.on_input(event)

    func on_gui_input(event: InputEvent) -> void:
    if current_state:
    current_state.on_gui_input(event)

    func on_mouse_entered() -> void:
    if current_state:
    current_state.on_mouse_entered()
    func on_mouse_exited() -> void:
    if current_state:
    current_state.on_mouse_exited()

    func _on_transition_requested(from: CardState.State , to: CardState.State) -> void:
    if from != current_state.State:
    return

    var new_state: CardState = states[to]
    if not new_state:
    return
    if current_state:
    current_state.exit()

    new_state.enter()
    current_state = new_state

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

      Hey,
      Check for the signature of your _on_transition_requested function:
      The first parameter should be CardState (you have CardState.State instead), and the second one is CardState.State (the enum)! That should do it

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

      @@godotgamelab Thank you so much!!

  • @718Outdoors
    @718Outdoors 3 місяці тому

    at 32:52, I've typed:
    ------------------------------------------------------
    func _ready() -> void:
    card_state_machine.init(self)
    -------------------------------------------------------
    I get an error.......Invalid Call. Nonexistent function 'init' in base "Nil'
    The init function seems to be set up in Card Machine script correctly.
    ----------------------------------------------------
    func _init(card: CardUI) -> void:
    for child in get_children():
    if child is CardState:
    states[child.state] = child
    child.transition_requested.connect(_on_transition_requested)
    child.card_ui = card

    if initial_state:
    initial_state.enter()
    current_state = initial_state
    ------------------------------------------------
    I have very little experience with coding. so issues are harder to logically figure out in many cases.

    • @godotgamelab
      @godotgamelab  3 місяці тому +1

      this means that the card_state_machine node is not found.
      You need to make sure ifthe CardStateMachine node with the script actually exists in the CardUI scene AND in the cody your @onready var reference to the CardStateMachine node is correct.

    • @718Outdoors
      @718Outdoors 3 місяці тому

      Thank you for you reply....again, a little lost!. The CardStateMachine node, with script, is in the CardUI scene....not sure what you meant by "AND in the cody". I assume cody is code, but if so not sure what that means.

    • @godotgamelab
      @godotgamelab  3 місяці тому +1

      @@718Outdoors I meant that you need to reference the state machine as an onready variable like so:
      @onready var card_state_machine: CardStateMachine = $CardStateMachine
      Please note that this course isn't really meant for beginners. What I'm saying is you can expect a lot of struggle and bumps because this is aimed at intermediate users.
      Hope that helps nevertheless!

    • @is_game_maker
      @is_game_maker 2 місяці тому

      @onready var card_state_machine: CardStateMachine = $CardStateMachine as CardStateMachine
      func _ready() ->void:
      card_state_machine.init(self)
      ,,,,,,
      but still had Invalid call. Nonexistent function 'on_input' in base 'Nil'.
      @@godotgamelab

    • @is_game_maker
      @is_game_maker 2 місяці тому

      That's what I wrote, but it's still the same mistake as him.​@@godotgamelab