We're running a Christmas sale right now; all our courses are 50% off with the coupon code DISCOUNT50: gdquest.mavenseed.com/ Don't forget to watch PlayWithFurcifer's video for 5 more Godot code patterns: kzbin.info/www/bejne/i6aoooiEbp2okNE
@ecclesoul2 жыл бұрын
Will you add a complete 3d game development course at some point?
@dairyfreelemonstreams9493 Жыл бұрын
0:50 Subclasses 2:58 DataClasses aka why I'm rewatching this again 4:04 Feature Tags 6:56 Fluent Interface 8:20 State Machine
@willnationsdev Жыл бұрын
I'd like to point out that the notion of a "data class" also goes by another generic name: POD or "Plain Old Data" class. There are also other names used for such classes, but which are more use-case-specific: - a "Context" class is one that is used in the manner described in the video: you specifically want to make method refactoring methods easier as well as simplify the process of re-using the same arguments across many different methods without refactoring all of them. - a "Data Transfer Object" or DTO class is one that is used purely to map data between endpoints in the application to the application's internal APIs. For example, when accepting user input, displaying data to the user, fetching data from a database, or sending data to a database, the exact set of fields and properties associated with data will very likely be specific to that targeted "endpoint". You then transfer the data from that object to a format that is more friendly to your application's domain, i.e. perhaps an array of comma-delimited strings gets converted into a Dictionary of integerinteger mappings. This pattern can also be combined with other patterns, for example... - the static factory pattern (as described in the video) where you write a static method that creates a new instance of the class and returns it, similar to a constructor. However, because it isn't an actual constructor, it doesn't run into the problem of GDScript not allowing multiple constructors and often requiring the constructor (if defined) to allow for no arguments to be passed (e.g. scenes can't instantiate Nodes unless they support an empty constructor). Note that static factory methods often have a `from` prefix to indicate that a new instance is being built "from" some other data. - the Fluent API / Fluent Interface: as mentioned, can have method calls that mutate the instance and then return itself, thereby letting you chain together method calls on a single line to steadily transform the object. - the Builder pattern: combines Fluent API with Command to effectively build an object that can be mutated, but which is ultimately responsible for instantiating new instances of a target class based on the configuration/mutation of the Builder's properties. It will have a Fluent API that modifies its own properties, but it is a data-only class. You would then call a `build()` method on the Builder that uses all of the assigned values to instantiate a new instance of the Builder's target type. So, e.g. a NodeBuilder would be an object you pass around (like a Command), and update using chained method calls (like Fluent) and which you can pass through an arbitrary pipeline of methods (lambdas, signal callbacks, whatever) before eventually calling `build()` and actually getting a Node created according to the specifications of all the methods it passed through. You can then also cache and reuse that builder to create identical nodes (or whatever the target type is) as desired. This is kinda similar to how the PackedScene class works under-the-hood to instantiate scene files. Since I touched on the subject, I'll also say this: there are also several conventions that come with name prefixes: - `from` for static factory methods. - `get` for accessing a property's value. - `set` for overwriting a property value. - `with` to return a NEW instance of an object with a specific change (to avoid side-effects and preserve the purity of a given function call in functional programming). - `to` to convert an instance's data into a new data type. `as` to provide a new view of an existing instance's data (most often in the context of custom iterators over a collection). - `try` to attempt an operation and return a bool true/false based on whether the attempt succeeded. - `using` to pass a lambda that accepts a context that provides temporary access (within the lambda) to data that is managed by the class with the `using` method, that way the class does not have to directly expose whatever the protected data is directly in its public API. - `find` to perform a key-based lookup of some kind. - `at` to perform an index/offset-based lookup of some kind. - many, many more, especially if you explore .NET's LINQ API
@longuemire748 Жыл бұрын
thanks
@NihongoWakannai Жыл бұрын
@@willnationsdev is there an article covering those naming conventions? I already know most of them but was still getting a little confused without code examples lol
@pliniojrm3 ай бұрын
Imo it it's called "Builder Pattern"
@dairyfreelemonstreams94933 ай бұрын
@@pliniojrm Which is??? i listed 5 things
@ipdramon21772 жыл бұрын
The most important I learned from programming in professional environments is that performance is in many cases not the hardest part. Writing code that you and others can understand tomorrow, in a week and even after months of not working with it is more important than this one nanosecond you can save. Only think about performance if your program is currently having issues and does not meet criteria like your wanted fps.
@flashfreak62 Жыл бұрын
I learned this lesson very early in my gamedev journey. I would take 1-2 month hiatuses. If my code wasn't readable sometimes it was faster to just transfer all my assets to a new project and start over from scratch. Since then though I've gotten really good at making very readable code. I can pick up projects I started months or over a year ago and almost immediately get a pretty strong understanding of what everything does and how they work together
@peezieforestem5078 Жыл бұрын
That's a false dichotomy right there. If you think in terms of problems and solutions, your solutions should be clear and obvious. If that's the case, your code will automatically be readable and reasonably performant. If your code looks like a mess you cannot decipher in a few months, that means, in all likelihood, it wasn't a good solution to begin with.
@HDL_CinC_Dragon Жыл бұрын
I think your post can be summed up primarily into two well established programming principles: 1) Premature optimization is an enemy, not a friend 2) Never write "clever" code
@rogthepirate4593 Жыл бұрын
@@peezieforestem5078 If you think it's always this simple, you haven't worked on any complex problems yet. From years of experience in big data server backend stuff, I can assure you that more often than not, "clear and obvious" is a near-utopian luxury that has nothing to do with the real world, and code is never "automatically readable and reasonably performant", it takes hard work to get it there and keep it that way.
@fenilli Жыл бұрын
As for the first pattern, I would say it would be better to follow composition over inheritance, instead of having a Mob scene, have a FollowComponent scene, an HealthComponent Scene, a HurtboxComponent, and that would do only a single job, of emiting signals when something specific to it happen, so you can compose those by passing an instace when needed to each of those, so now you can have as many reusable parts as you want, and any enemy that follows the pattern can use, and any that does not can use another one.
@jkf16m96 Жыл бұрын
I've been trying my way on engineering that with my own classes. Inheritance isn't bad either, but one must really think well how concrete the class should be. What I've been doing is making the "components" folder with a type-folder structure "Node, RigidBody2D" etc, and creating small classes specific for them. And now when implementing my own players or enemies, I extract the needed logic units and puts them in a getter private RigidBody2DType.MovementControl MovementControl => new MovementControl(this,...); This is what I've gotten so far, but I would like to be able to export MovementControl properties into the editor... If I don't discover a way, I'll end up just creating base Nodes.
@javgroman2 жыл бұрын
Came from Unity and really enjoyed working in C# but the built-in editor in Godot and GDScript has won me over - it doesn't have all the bells and whistles of say VSC but I don't miss them really. Nice summary vid - always learn a lot from your team coming to Godot. Thanks!
@Draenal Жыл бұрын
Godot supports external editors and there are VS Code plugins for GDScript.
@jeffreystephens2658 Жыл бұрын
The only thing I feel like it's lacking is Replace All.
@jrmillerfilms Жыл бұрын
Only thing I truly miss is being able to highlight a block of code and replace it with a function call, and have it move and create the new function. That or typing a function call before it's been created and a hotkey press away and VS creates the empty function with a Not Implemented Exception.
@BravosChannel2 жыл бұрын
Subclass sandbox is really nice and I like how easy it sounds to just put new stuff, but the way I usually do it is by creating a bunch of nodes that can be children of mob, such as "Damageable" and "Talkable" which makes it easy for me to have certain mobs require more features or less depending on the type of mob I want. If the mob is an NPC, I don't need Damageable, but I do need Talkable. If the mob is a boss, I can add Damageable since the boss will take damage, and Talkable to spice up the drama. I can then connect those signals to the owner class to do specific things like knocking the enemy back after taking damage and stuff like that. When I'm hitting the enemy, I know the player should be hitting "Damageable" so then I can call the function in there with arguments, and let Damageable do the rest of the work in whatever the mob class is meant to do
@Gdquest2 жыл бұрын
Going with composition like this is a good idea. Depending on the game I'll also tend towards that. The sandbox pattern, like most patterns, has its tradeoffs: very easy, you can have super transparent code, but at the same time you're really constrained by the parent class/scene's structure. Now, using a sandbox doesn't prevent you from using components for damage and the ability to talk. You can use it only for the behaviors that you want every e.g. AI agent to have access to.
@BravosChannel2 жыл бұрын
@@Gdquest honestly a combination of the two is best bet. I just wish it were easy to make certain children editable from the inspector so I can modify children by default without having to make all children editable. It'll make the whole component structure a lot more easy to work with. Usually right now I just drag component nodes into the owner which definitely does get repetitive if I want one specific enemy to do more damage than others. Sandbox definitely streamlines this process a lot better and is just good practice in general but I also do wish there was a way to make certain children editable. There's probably a proposal for that
@kawashinimon2 жыл бұрын
This is a really good idea; it really breaks down the complexity of larger scale games like RPGs into something more manageable overall. Really puts a shine on the node system of godot.
@jawny7620 Жыл бұрын
@@BravosChannel you can accomplish this in godot 4 func _on_tree_entered(): get_parent().set_editable_instance(self, true) connect that function to the on_tree_entered signal of an instantiable node, make sure it's a @tool script so it can run from editor, and it will automatically add the node to the scene as editable
@sloppyy10 ай бұрын
realizing how much i was taking for granted about having previously learned a lot of software design patterns years in advance of ever firing up godot
@luke1235XD Жыл бұрын
Another thing to note about inherited scenes is that they are slightly dangerous since you can lose nodes/properties in the child scenes by making changes in the parent scene. Personally I would only use them for simple things like projectiles were your just changing properties and don't add any additional nodes.
@tryoxiss2 ай бұрын
FYI X11 is a specific display manager on Linux, not Linux in general! There is also Wayland which is more modern.
@michaelavrie2 ай бұрын
native Wayland support isn't available in Godot yet but it is coming soon according to the latest 4.4 dev snapshots
@Ash_180372 жыл бұрын
Fluent interface is absolutely not about being able to chain function calls on a single line as you said at 0:19 In fact fluent interface lines almost always need to be broken up into multiple lines to maintain readability (often people break the line after a . character). Fluent interface aims to improve the understandability and readability of code so that even someone not familiar with it could make a decent guess at what it is doing. The chained method calls ideally make sense if read as an everyday sentence (hence fluent). I don't actually like or recommend fluent interfaces greatly, just wanting to ensure you don't mislead people about it. The more detailed explanation later in the video is much more accurate.
@Ash_180372 жыл бұрын
If GDscript doesn't allow breaking lines (as is possible in C#) then using fluent interface is going to create some absolutely awful code. e.g. a 10 method chain restricted to one line.
@Gdquest2 жыл бұрын
Thanks for the correction! To me, it doesn't make things much more readable than setting properties or calling functions in the context of GDScript, so honestly, I never quite understood the pattern. Where I've seen it used, it mostly seemed to shorten code, i.e. turn: object.do_something() object.do_something_else() Which is explicit and accessible code, into: object.do_something().do_something_else() Which is just as explicit and accessible, but shorter. I guess the notion of fluent, in the sense of "making it read like a sentence" makes some sense. To write each call on a different like you need to write a \ at the end of the line by the way.
@makesnosense6304 Жыл бұрын
It's also called build pattern, where you build the object up with additional methods. "The intent of the Builder design pattern is to separate the construction of a complex object from its representation."
@Daseril2 жыл бұрын
I think this is the first time I've really understood what a state machine is, I've heard/read explanations of it, but never really seen an example of what that means. Seeing the nodes and the scripts attached to them here in the scene tree really helped me to understand. Because before this I was just thought that a state machine just referred to how you would code something in a single script when something is in different states. However, seeing that there are multiple nodes and scripts, I now get that its way to break things up, so everything isn't in a single script, and therefore less crowded and difficult to search through.
@RenderingUser2 жыл бұрын
Wait what? I thought state machines were for switching out one set of code for another in a game
@v44n7 Жыл бұрын
@@RenderingUser i am new into godot, but i am understanding state machine like for example. Lets suppose a monsters is moving around minding his own business. That can be called a state. Idle state for example, in which you write all the code for the monster, it moves around, do stuff, etc. But once a player attacks the monster, it changes to aggressive state. In which, starts looking for the player and tries to attack him. I think in the video example it gives stats for the 3D character, When the idle state is active, the character animation and codes all respectively to idling, when jumping for example it switches to the "Air state" in which all new animation and coding runs instead of the ones in idle
@ArcangelZero7 Жыл бұрын
Awesome! For yourself or anybody else here: a great example of State Machine usage is with simpler game Ai. The first Half-Life was a big deal with how they used state machines for Ai logic. Like the other comment here mentioned: "If I don't see the player, I'm in a searching state and behave like this...Oh I see the player! Move to attacking state. Oh no the player threw a grenade close to me! Move to fleeing state." There's some really good videos on KZbin for it if you search around. :)
@danieloliveira-pq4zy7 ай бұрын
Awesome video, really helpful insights! Btw, does someone know how to get those fancy little details in the code where stuff like "->" (7:37) and "
@Chevifier Жыл бұрын
4:07 Isnt creating a new Damage class every time you pass damage causing a memory leak. Id recommend that it extends the Reference class so it clears itself after its used.
@jkf16m96 Жыл бұрын
It's not a memory leak in c# or GDscript It is a really common pattern to use and causes almost no perceptible performance issue. In c++ or c, it is definitely an issue (unless you use a smart pointer in c++)
@user-rx3xl7zn1u7 ай бұрын
Do you have a recent state machine tutorial?
@Gdquest7 ай бұрын
Soon hopefully but try Godotneers. Their channel is linked on ours. They do an excellent job.
@NachoKsp2 жыл бұрын
This video is gold for beginners like me, thanks!
@generrosity2 жыл бұрын
Oh, some gems here! Just thinking of juice with the state machine "on_enter" does the juicey particles or wibbles as you move from state to state. And passing Self as the return just makes me think of RPG characters and scripting more complex activites far easier :o
@pranavbadrinathan6693 Жыл бұрын
While the subclass behaviour is good, can we do something like Interfaces and implementing multiple interfaces? That would be extremely useful to use in games.
@Gdquest Жыл бұрын
No, GDScript doesn't have interfaces like e.g. C#
@jovlem Жыл бұрын
Ok, I'm new to classes and that kind of stuff at 2:58 Does it matter where I put/save these? Must the node wtih this data class in the same node tree as where I want to use them or can I "call" them from anywhere?
@josuereis6367 Жыл бұрын
Maybe I didn't understand, but the enter() and exit() functions seem to serve only to make the code more complex. A change_state() function and delegating processing to the state node is apparently enough.
@thechrom0072 жыл бұрын
What is font on 8:00 ?
@lexi30772 жыл бұрын
Just a question because of my understanding (and I have sometimes trouble seeing stuff): the sandbox pattern. The functions have the code in the Mob-Script and this iconthingie which I really cant see after the "void:" is just indicating that the code is hidden? On the first glance it looks like there is no functionality and I had to pause the video to analyze. So did I understand it right, that we just can't see your code? (thats fine! My brain just got confused and then I cant properly listen anymore until I figure stuff out...)
@Gdquest2 жыл бұрын
Yes, you can fold code blocks in the godot editor, and I folded most functions in the script to highlight one function in particular for the video.
@soran22902 жыл бұрын
7:00 fluent pattern
@whyunwhite7274 Жыл бұрын
Just saw the big "5" in the thumbnail and instantly thought... Godot 5?
@warlockco13 Жыл бұрын
Curvy moments y zeno's anthology fueron juegos que me engancharon por sus tramas. Realmente los difrute, una pena que curvy moments no está completo, me quedé con ganas de saber como terminaban las historias.
@angelrubiov Жыл бұрын
Lol I didn't see the title at 6:56 because my subtitles were obscuring it, I got lost af
@Gdquest Жыл бұрын
That's really useful feedback. I'll keep that in mind for future videos, thanks!
@ДимаК-в7е7 ай бұрын
X11 does NOT stand for Linux. X11 is a window system. Not every Linux system runs X11, some run Wayland. For now it doesn't matter, but when/if Wayland support will be added, this can break your game if you assume that every Linux build supports X11. It says Linux/X11 and not Linux for a reason.
@max.marauder2 жыл бұрын
A bit funny to see inheritance from base classes presented as some cool pattern, rather than one of the core OOP principles that are used by default in any code :) No offense to the author though, the video is cool anyway!
@Gdquest2 жыл бұрын
No offense taken, it's a very simple pattern. There's inheritance in general, where you override things and add whatever code you like, and there's the sandbox pattern, where you define pretty much all utility functions in the base class and almost exclusively call these functions. You use the base class's code in inherited classes, creating a kind of sandbox, hence the pattern's name. It's the constraint you put on calling functions from the parent class to implement concrete behavior that makes the pattern interesting.
@Ash_180372 жыл бұрын
@@Gdquest It's very understandable why max said this though. This is a very "wishy washy" pattern. I'd even say it's barely qualifies as a pattern. So often you will see code where child classes barely even touch the base class and/or access services directly. The problem is there is absolutely no "in your face" restriction that stops the developer bypassing the base class completely. Once you do that you lose all benefits of the pattern.
@Gdquest2 жыл бұрын
@@Ash_18037 In a language like Python, JavaScript, or GDScript, there's not much that prevents you from breaking away from lots of patterns. Most rely on your team following the same style and conventions.
@marcozanella98502 жыл бұрын
Totally agree, code reuse through inheritance is so standard in OOP that it feels strange to call it a pattern. BUT in the context of game making (where you don't generally mess around with inheritance that much) I think it makes sense.
@DzotEKirill2 жыл бұрын
Hi, I'm not on the topic of the video, but can you help how to implement that in an HTML5 game the sound is not played when the game is minimized or we are on another tab via OS.is_window_focused() , OS.window_minimized does not work
@molotov37822 жыл бұрын
i have a question: is it good toggling State's set_process method instead of using other virtual methods? or does set_process method have high performance impact or any other problem? also the PlayerState class can be a subclass in the Player class, so it won't be shown in the add child menu, auto completion works completely in godot 4 but idk if it works in godot 3
@eibriel2 жыл бұрын
Wow, most useful Godot video ever
@OgGhostJelly2 жыл бұрын
crossover episode? 💀
@njnjhjh8918 Жыл бұрын
I fail to see the "twist" to subclasses, that's just what subclasses are usually
@WifeWantsAWizard Жыл бұрын
Nice video. (0:23) What the hell? Why not "Character.new("Juan",100,10);"? (2:11) "...especially in an indie game..." Always code like you're applying for a job at Epic. You never know when someone in an interview is going to say, "Can I see the code on that?". (3:02) Yes, that is how you pronounce "parameter". From the Greek "para-" meaning "next to" and "-metra" meaning "measure". If "x = 5", "x" is the parameter because it is "next to" the measurement of "5". (4:12) Never use a float unless absolutely necessary. The savings he's talking about is 20-30 floats, not 20-30 ints. (4:54) This is why we have game *designers* and game *programmers*. Left to their own devices, programmers will change the names of properties as they realize their mistakes causing havoc in big projects. However, designers create game docs so that every property is established in advance and then hand off the finished product to programmers to get the job done in half the time. (5:33) What is the point of GodotScript if there's no "Application.platform"? You're telling me that three years from now someone isn't going to come up with an amazing Javascript OS that changes the world? People, hear my voice: learn C#. (8:07) I'm sorry, does it filter OUT all the odds or filter FOR odds? Maybe ".filter_remove("odd")" or ".lessThan(10)" instead?
@eyondev Жыл бұрын
"Always code like you're applying for a job at Epic" sound like a decent way to not get anything done. Besides, you use the right tools for the right job. You are doing an Indie game, you solve for the indie game's requirements and limitations, not for what you think would be the requirements for a hypotetical game at Epic. The best code depends on the context it's in.
@pashakurozeev55162 жыл бұрын
Hello! Please make lessons on creating fishing in godot!
@katkazam5246 Жыл бұрын
You know have to breath manually
@AdroSlice2 жыл бұрын
Fluent API is pretty bad. It comes from the dated getter/setter-method pattern of Java-centric OOP and is strictly worse than something like a C# object initializer. Depending on the implementation, it can add unnecessary overhead in the form of function calls, and in my opinion the syntax is neither pretty nor intuitive either, especially when you have to mix it with other parts of the code or a library that does not employ the same pattern.
@AdroSlice2 жыл бұрын
Example (C#): x = new RandomObject().SetA(1).SetB(2); vs. x = new RandomObject() { A = 1, B = 2 };
@Gdquest2 жыл бұрын
I don't use it personally, but quite a few developers actually love it. In any case, GDScript doesn't support the C/C#/JavaScript style object creation/initialization.
@AdroSlice2 жыл бұрын
There is an open proposal to introduce a feature like this to GDScript, I very much hope it sees some more attention.
@Gdquest2 жыл бұрын
@@AdroSlice That'd be nice! I'm not sure what's planned for the future of GDScript though, the devs and language designer are also trying to keep it simple. We'll see.
@kawashinimon2 жыл бұрын
@@AdroSlice I agree with this. I never liked the get/set thing. Part of it may be because I learned coding through c/c#, but just setting the OOP with a = and calling it as such instead of set/get just feels more simple and cleaner. It''s funny since gdscript is based on python which is based around being simple and clean and avoids get/set but for some reason gdscript went back on that.
@IceWolve6710 ай бұрын
yeaaa this is not for beginners
@manuelmakesartz2 жыл бұрын
Hello
@zitronekoma30 Жыл бұрын
Left a very politely worded criticism on play with furcifer's channel in the past and was immediately insulted by the owners of the channel, left me with a bad taste so I won't be watching this video, love your guy's content as always tho, I'm sure this is no exception.
@saulnores34772 жыл бұрын
Playfucifer spoke do fast that I didnt understand anything. I only liked GDQuest parts of the video.
@rekiemr45012 жыл бұрын
bro plsss make game like a growtopia i hope u can😥
@peezieforestem5078 Жыл бұрын
That's a terrible advice. People, don't think in terms of patterns, learn to solve problems.
@skilletborne Жыл бұрын
They're tools to add to the proverbial toolbelt, they were never presented as something that it was imperative to use
@peezieforestem5078 Жыл бұрын
@@skilletborne What do you mean by "never presented"? "Must Have Code Patterns" is literally the title.
@JacobTeach Жыл бұрын
@@peezieforestem5078 I'll play devil's advocate and assume by "must have" they meant "must know" patterns are valuable and there's no need to reinvent the wheel
@peezieforestem5078 Жыл бұрын
@@JacobTeach if that's what they mean, then I have no objections. However, we should be careful with interpreting other people's words. I think it's more productive to discuss what's actually being said as opposed to what we think is the closest match that makes sense.
@iivarimokelainen Жыл бұрын
the accents are super annoying
@Gdquest Жыл бұрын
You don't have to watch the videos, you know. No need to comment that on multiple videos.
@welyn5499 Жыл бұрын
Hey! Great video. #1 place for online marketing 'Promo sm'!!!