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

Sdílet
Vložit
  • čas přidán 23. 05. 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

Komentáře • 183

  • @godotgamelab
    @godotgamelab  Před 5 měsíci +28

    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 Před 6 měsíci +28

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

    • @godotgamelab
      @godotgamelab  Před 5 měsíci +3

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

  • @LuizMoratelli
    @LuizMoratelli Před 5 měsíci +22

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

    • @godotgamelab
      @godotgamelab  Před 5 měsíci +2

      Glad you like it! :)

    • @nandomax3
      @nandomax3 Před 5 měsíci +7

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

    • @Nerobyrne
      @Nerobyrne Před 3 měsíci

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

  • @718Outdoors
    @718Outdoors Před 3 měsíci +6

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

  • @jmh6559
    @jmh6559 Před měsícem +2

    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!

  • @marcelburdon9795
    @marcelburdon9795 Před 2 měsíci +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 CZcamsrs 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 Před 2 měsíci +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 Před 3 dny

      @@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.

  • @Ocdib
    @Ocdib Před 5 měsíci +10

    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 Před 5 měsíci +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  Před 5 měsíci +6

      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 Před 5 měsíci

      @@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

  • @lexsdragon1554
    @lexsdragon1554 Před 5 měsíci +3

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

  • @Soroosh.S83
    @Soroosh.S83 Před 5 měsíci +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  Před 5 měsíci +1

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

  • @Ocdib
    @Ocdib Před 5 měsíci +3

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

  • @aaronsommers9078
    @aaronsommers9078 Před 4 měsíci

    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!

  • @yogiwiguna9602
    @yogiwiguna9602 Před 5 měsíci

    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  Před 5 měsíci

      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 Před 5 měsíci +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 Před 5 měsíci +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

  • @reIMAGEN
    @reIMAGEN Před 10 dny

    This is a great series. Wonderful work mate.

  • @ahmadmuazmohaspa5106
    @ahmadmuazmohaspa5106 Před 2 měsíci +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!

  • @421LIZO
    @421LIZO Před 5 měsíci

    thank you. keep it going!

  • @attilasipos3481
    @attilasipos3481 Před 4 měsíci

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

    • @godotgamelab
      @godotgamelab  Před 4 měsíci

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

  • @nandomax3
    @nandomax3 Před 5 měsíci +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  Před 5 měsíci

      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! 👀

  • @underscorerx
    @underscorerx Před 3 měsíci

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

  • @TheCamulous
    @TheCamulous Před měsícem +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 Před měsícem +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 Před měsícem

      @@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?

  • @kevintrueblood1057
    @kevintrueblood1057 Před 5 měsíci +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  Před 5 měsíci +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!

  • @RafaMartinelli
    @RafaMartinelli Před 5 měsíci +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  Před 5 měsíci +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! 😌

  • @ciaala
    @ciaala Před 19 dny

    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  Před 18 dny +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!

  • @Soroosh.S83
    @Soroosh.S83 Před 5 měsíci +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  Před 5 měsíci +3

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

  • @seanwade7824
    @seanwade7824 Před 5 měsíci

    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  Před 5 měsíci

      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! :)

  • @TylerAlbers01
    @TylerAlbers01 Před 26 dny

    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  Před 26 dny

      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 Před 26 dny

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

    • @godotgamelab
      @godotgamelab  Před 26 dny

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

  • @alexdoessudokus
    @alexdoessudokus Před 4 měsíci +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  Před 4 měsíci +3

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

    • @alexdoessudokus
      @alexdoessudokus Před 4 měsíci

      @@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 :)

  • @dommychi
    @dommychi Před 2 dny

    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?

  • @davidReyGD
    @davidReyGD Před 5 měsíci +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  Před 5 měsíci +2

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

  • @muxecoid
    @muxecoid Před 5 měsíci

    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  Před 5 měsíci

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

  • @itadaimasu
    @itadaimasu Před měsícem +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

  • @Lander_Calcoen
    @Lander_Calcoen Před 2 měsíci +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?

  • @derekc.7689
    @derekc.7689 Před 9 dny +1

    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!

    • @luke-lh5ye
      @luke-lh5ye Před 3 dny

      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 Před dnem

      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  Před dnem

      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!

  • @MuseDoes
    @MuseDoes Před 2 měsíci

    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  Před 2 měsíci

      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!

  • @luke-lh5ye
    @luke-lh5ye Před 3 dny

    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  Před 3 dny +1

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

  • @dmsys6516
    @dmsys6516 Před 5 měsíci +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  Před 5 měsíci +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)

  • @longuemire748
    @longuemire748 Před 5 měsíci

    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  Před 5 měsíci +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 Před 5 měsíci

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

  • @tinypixel343
    @tinypixel343 Před 5 měsíci

    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  Před 5 měsíci +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 Před 5 měsíci

    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  Před 5 měsíci

      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 :)

  • @Mech_rat
    @Mech_rat Před 4 měsíci

    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  Před 4 měsíci

      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 Před 4 měsíci

      @@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  Před 4 měsíci

      @@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 Před 4 měsíci

      @@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.

  • @FaceofFrequency
    @FaceofFrequency Před 2 měsíci

    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  Před 2 měsíci

      Good idea, thanks for the feedback! :)

  • @TheDonValerianos
    @TheDonValerianos Před 5 měsíci

    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  Před 5 měsíci +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! :)

  • @txeemo6946
    @txeemo6946 Před 23 dny

    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.

  • @GameUISchool
    @GameUISchool Před měsícem

    🤩

  • @Ichthyoid
    @Ichthyoid Před 4 měsíci +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 Před 4 měsíci +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  Před 4 měsíci +1

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

    • @Ichthyoid
      @Ichthyoid Před 4 měsíci

      @@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  Před 4 měsíci

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

  • @RedCocoon
    @RedCocoon Před 17 dny

    Megacrit saw this and thought We could make this better

    • @godotgamelab
      @godotgamelab  Před 17 dny

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

  • @UnstoppableTigra
    @UnstoppableTigra Před 5 měsíci +1

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

    • @godotgamelab
      @godotgamelab  Před 5 měsíci +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 Před 5 měsíci

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

  • @nicecatch8646
    @nicecatch8646 Před měsícem

    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?

  • @LiinksGaming
    @LiinksGaming Před 5 dny

    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?

  • @K0ll7n
    @K0ll7n Před 16 dny

    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.

  • @deftmute
    @deftmute Před 4 měsíci

    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  Před 3 měsíci

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

    • @deftmute
      @deftmute Před 3 měsíci

      ​@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 Před 4 měsíci

    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  Před 3 měsíci

      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 Před 3 měsíci

      @@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  Před 3 měsíci

      ​@@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 Před 4 měsíci

    @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 Před 4 měsíci

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

    • @godotgamelab
      @godotgamelab  Před 3 měsíci

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

  • @sprooc
    @sprooc Před 2 měsíci

    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  Před 2 měsíci +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!

  • @PeteReborn
    @PeteReborn Před 13 dny

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

  • @fvhaudsilhvdfs
    @fvhaudsilhvdfs Před 4 měsíci

    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  Před 4 měsíci +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 Před měsícem

      @@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)

  • @thetiphon
    @thetiphon Před 3 měsíci

    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  Před 3 měsíci

      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 Před 3 měsíci

      ​@@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  Před 3 měsíci +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 Před 3 měsíci

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

    • @godotgamelab
      @godotgamelab  Před 3 měsíci

      thanks, happy to help! @@thetiphon

  • @lassepoulsen7591
    @lassepoulsen7591 Před 20 hodinami

    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  Před 14 hodinami

      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!

    • @lassepoulsen7591
      @lassepoulsen7591 Před 12 hodinami

      @@godotgamelab what should i be looking for within the remote SceneTree? also it changes the text back to "base" but the position remains where i placed it

    • @lassepoulsen7591
      @lassepoulsen7591 Před 12 hodinami

      @@godotgamelab i don't know where it goes wrong, because when i check the label it has the state"BASE" but the position is just where i left it

  • @dimtool4183
    @dimtool4183 Před 5 měsíci

    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  Před 5 měsíci

      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 Před 5 měsíci

      @@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  Před 5 měsíci

      @@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 Před 5 měsíci

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

    • @Youngdeff1
      @Youngdeff1 Před 5 měsíci

      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

  • @nicholasmoreno6358
    @nicholasmoreno6358 Před 3 měsíci

    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  Před 3 měsíci

      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 Před 3 měsíci

      ​@@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 Před 3 měsíci

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

    • @marcelburdon9795
      @marcelburdon9795 Před 2 měsíci +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?

  • @onreadyvar
    @onreadyvar Před 2 měsíci

    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  Před 2 měsíci +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 Před 2 měsíci

      ​@@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.

  • @tars9063
    @tars9063 Před měsícem +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 Před 11 dny

      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 Před 11 dny

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

    • @XxKagarwaxX
      @XxKagarwaxX Před 11 dny

      @@tars9063 you are my hero

    • @tars9063
      @tars9063 Před 10 dny

      @@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 Před 10 dny

      @@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)

  • @Lander_Calcoen
    @Lander_Calcoen Před 2 měsíci

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

  • @Xipheos_
    @Xipheos_ Před měsícem

    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_ Před měsícem

      Fixed it

    • @itadaimasu
      @itadaimasu Před měsícem

      Hi, how did you fix it?

    • @Xipheos_
      @Xipheos_ Před měsícem

      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_ Před měsícem

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

  • @is_game_maker
    @is_game_maker Před měsícem

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

    • @is_game_maker
      @is_game_maker Před měsícem

      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 Před měsícem

    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  Před měsícem

      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 Před 3 měsíci

    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: czcams.com/video/IaAqhIC5DaI/video.html
    my cards call the _get_drag_data function
    my card drop areas call the _can_drop_data and _drop_data functions

    • @godotgamelab
      @godotgamelab  Před 3 měsíci

      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 Před 3 měsíci

      @@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 Před 4 měsíci

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

    • @godotgamelab
      @godotgamelab  Před 4 měsíci

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

  • @monamibob
    @monamibob Před 26 dny

    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  Před 26 dny

      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 Před 25 dny

      @@godotgamelab Thank you so much!!

  • @718Outdoors
    @718Outdoors Před 3 měsíci

    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  Před 3 měsíci +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 Před 3 měsíci

      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  Před 3 měsíci +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 Před měsícem

      @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 Před měsícem

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