One thing to keep in mind for anyone using composition and overall just trying their best to make good code: PROTOTYPING IS GOOD, DO IT! You do NOT want to be the person that spends a year (learning how to and then) creating a versatile system full of state machines and scripts for every little thing you could ever need only to then find out that Godot's 3D hinges are the most confusing thing ever and therefore you either need to spend god knows how long learning the intricacies of Godot's physics engine to make a version of them that does what you want or just give up the project entirely. BEING ABLE TO JUST MAKE SOME *REALLY* **REALLY** BAD CODE SO YOU CAN FIGURE OUT WHAT TO DO IS REALLY GOOD! also this is a really good video and i will use similar things in my projects now thank you
@luluskuy4 күн бұрын
huh?
@djSeakDigital6 күн бұрын
I'm going to show my students this video. The way I hate OOP
@o0Haruo0o13 күн бұрын
What's the music starting at 3:35 ?
@SuPeRg4meCrAfT14 күн бұрын
this vid is so good omg
@Fybuh16 күн бұрын
wait... did i just discovered home??? as in, NIGERIAN GAME DEVS!!!! Abeg, make i join una community na. i've felt alone for so long :(
@Yakend17 күн бұрын
Hey! I'm a new-dev and this is cool. So I use luau (roblox) and I've been making an ability system and this is exactly what I've been doing but described in a word. I use an OOP approach but basically "abilities" have a bunch of different things that could make them up, maybe it's a projectile, maybe it heals, maybe it follows the cursor etc. etc. and I just specify these different things and build an object with blocks I've pre-made rather than having new things inherit from wtvr. Composition. I didn't know the word to describe what I was trying to do, but it's this exactly.
@HD-t3i25 күн бұрын
I will try it in godot 4.4. I have to read the subtitles because i wonder any can understand your bad voice. Open you mouth please ;)
@williammonden87129 күн бұрын
I've been trying to understand the different methods of this kind of implementation because all of my code is horrible and awful and terrible. But I've never been very good at understanding the videos, but this has been probably the best example I've seen. Thanks!!
@muhammad-dq6jgАй бұрын
The biggest bug with my code was... Myself.
@dogamer238Ай бұрын
I have a question what do you use to create the programming sheme it would be usefull for me to share with my friends when i explain programming archiectuer and stuff like that thanks in advance .
@MisterD777Ай бұрын
I truly agree, it's gorgeous...
@jamesloymartinАй бұрын
I mostly send signals, but also if I have a bunch of stuff referencing something, I use custom resources. Like a resource that's PlaneData that the plane updates and has things like it's state, but the resource can be attached to anything that needs to references it, like the player. If you accidently change the variable that stores the plane state in the resource from the player, it doesn't affect the plane itself, just some variable in a resource that only references the plane.
@heavensfield494Ай бұрын
So when actually you want to use them? I do tries compositions sometimes but I find it is harder to work with 15+ script going into it. So I just resort to making new scripts as a “presets”.
@mrserlysirАй бұрын
Well, I've been using the subscriber pattern found in a lot of AWS services, as well as, web frameworks like RXJS. C# let's you do this with delegates and events. This is so that any time I need to make a change where it's appropriate i.e. FixedUpdate, Update or LateUpdate the classes who care about some physics object subscribe to changes in say the RigidBody. The only coupling that happens is when I need to inject a reference to physics changes. Everything that cares about a change gets invoked in a deterministic way. This pattern is what the new Input Module does. I'm not a long term game dev just been programming other things professionally for years now.
@torrescleАй бұрын
Hard to watch with this shitty background music.
@DeepFriedOreoOfflineАй бұрын
This is an amazing video! Composition, or ECSs are extremely useful and something that people tend to either misunderstand, or ignore. However, I do wish you had a better example than Titans because Titans are actually an amazing example of where Inheritance would shine bright. For the main reason that there are thousands of them. The way you describe composition is such that you can apply components to your entity to make exactly what you need, but no one is going to manually create 1000s of Titans, that is ridiculous. You would manually create the, maybe 10, special Titans, and then have some systems that create Titans with a random set of a group of components based on the genetic needs of each class of Titan. Which would be very easy and efficient to do with composition, but in terms of actually managing the Titans themselves, you would want an inheritance layer that controls how the composition happens. In other words, sometimes it's best to use the 2 patterns together.
@Manu-c5qАй бұрын
i use godot with 2GB ram
@AgodzillaFace98-yj5nqАй бұрын
Good exercise is to write some game logic in c. And when you try to create Oop in c, slap your wrist. This exercise will help you understand that game is not real life. And that In turn, will give you more freedom to create solutions that make sense for you and for the machine.
@az-kalaak6215Ай бұрын
most people do not understand that, inheritance is there to inform what an object is (a titan IS a creature, it IS living, it IS tall, it IS a monster). Composition is there to inform what an object has (a titan HAS a shape, it HAS high hp, it HAS high damage). Interfaces (and also member functions) are there to inform what an object can do (a titan CAN crush you, it CAN move, it CAN eat humans). For your example at the very beginning, the randomize has imho no place inside the titan class, as it does not define a titan. it defines how to generate one, which is not the role of a titan (a titan cannot generate a titan can it?). if I complete the example: The Titan Generator can create any kind of titans! it can create basic titans which can run, kill, and eat! it can also generate weird titans, which for some reasons cannot move, but can do everything a basic titan can do. it also generates special titans, which have shielded plates, have higher speed or attack. Those titans can even use a special attack! when basic titans try to use it, they fail miserably... in this example, BasicTitan have four functions (run, kill, eat, attack). they also have a shape, that is passed to the constructor. The WeirdTitans inherits the basicTitan, and overrides the run function to do nothing (as they cannot move) The SpecialTitan inherits the basicTitan, and modifies its base characteristics (hp, strength, speed...). its attack function is overrode to implement a special attack. The TitanGenerator is a factory whose sole job is to create titans, based on what is asked to it. if it creates a basic titan, it is randomly generated. if it is a special titan, it has presets.
@JoeyG-o8rАй бұрын
"This old code I wouldn't touch with a 10 foot pole. The code smelled like vomit; spaghetti" "So I had this player class, which inherited from a class called Entity, which had code for movement..." Uh oh.
@sasdasu00dfsdfardo2 ай бұрын
>memedot
@GoblinArmyInYourWallsАй бұрын
Rent free
@legocloneguy12 ай бұрын
My approach would be to not allow the player to access the plane's state machine or manipulate the plane directly. The player shouldn't fly the plane; instead, the plane itself should handle the inputs. This way, when the plane explodes, all the player needs to know is that the plane no longer exists and can exit out of the pilot state. As for ejection, the player is in the plane and has its own sub state machine component to keep track of whether it is Landed or Flying. The player can switch to the Ejection State or any other to state. Ideally, if you've implemented this correctly, you can reuse the code from the plane's state management for the player's sub state while InPilot. This way both keep track of their own internal state and are loosely coupled. I don't know your code, hopefully this helps. Edit: I thought on this a bit more, if you want npcs to use the same code, given this approach, you probably have to tack on separate component that just interfaces with the npcs.
@NesiAwesomeness2 ай бұрын
@@legocloneguy1 that's actually really neat, like super idea. That's mostly how my code functions, the player's script controls the plane and handles inputs just doesn't keep the plane's state in its own "Flight" substate.
@artoriapd2 ай бұрын
And that's why you should be a hardcore coder like me, which prefer inheritance 😂😂 Btw, this is just personal thought: I think inheritance is just composition, but not a full composition If I'm not mistaken, C++ internally compile inheritance into a composition too
@az-kalaak6215Ай бұрын
internally, c++ gets entirely rid of classes and every single oop stuff to generate machine code :p
@artoriapdАй бұрын
@@az-kalaak6215 ya, I know?
@flashboylee2 ай бұрын
Bro 🤣🤣🤣
@CopperCrownDummyWhoMakesGames2 ай бұрын
Kinda crazy that the algrithim hasbt bosted this video more
@NesiAwesomeness2 ай бұрын
@@CopperCrownDummyWhoMakesGames it should I need more people's takes
@Xanhast2 ай бұрын
in an OO language you could only have a public get_state method and protected set_state, perhaps this is possible in c#? i've never gone that route or if that is one of the benefits to it. secondly, im not sure having circular signals is an issue. its a pub/sub system so there isn't really a broken reference or maybe i'm missing something. thirdly, if what you got works, goodjob :) i wouldn't worry too much about re-factoring now unless it becomes a problem, and explore other options on the next game
@NesiAwesomeness2 ай бұрын
@@Xanhast thanks so much, I'm probably just not educated enough to understand how variables can be protected. Someone mentioned using "constants" somehow
@Xanhast2 ай бұрын
@@NesiAwesomeness yeah im not sure in gdscript either, and why i suggested c# might be a better choice for these relatively abstract components that are implementing more OO ideas, where as gdscript is designed to be great for gameplay elements that you can iterate on quickly without worrying about strict typing and protected members etc
@Xanhast2 ай бұрын
hopefully someone with more godot experience can confirm tho, i've not tried c# in godot but have wider programming experience
@HappyGhetto2 ай бұрын
Without knowing your code it's impossible to say what the best solution is, but using meta data seems like a cheap way to avoid designing the system with the correct interfaces and dependencies. You say "circular reference" when referring to the player and plane having a reference to each other, but in reality this is just a coupling. Yes we like to decouple, but in this situation does it not make sense for the plane to have a reference to its pilot, and vice versa? You can abstract the player to an even more minimal pilot interface that other classes like NPCs could use if that's a concern. The pilot interface requires an Eject function be implemented, and then you implement the pilot interface on the player.
@NesiAwesomeness2 ай бұрын
@@HappyGhetto I do have a piloting interface, I just didn't include that into the video because I felt it was beyond the scope of what I was trying to get across but the "Piloting" script is seperate from the player and can be use just like the state machine. If it's best practice to decouple why not just do that. I figured it might be easier but I just prefer to be on the safe side and find another way.
@HappyGhetto2 ай бұрын
@@NesiAwesomeness If you want to avoid coupling you could create an interface like IStateMachineOwner that has a GetCurrentState method. Yes this is boilerplate, and I understand you wanted to avoid adding code to every object that has the state machine, but it's more robust than using meta data imo. You can add other things you might need to the interface too. Anyway, I think it's great you're making these kind of videos and are trying to strive for good design, keep it up!
@feivmoon2 ай бұрын
@@HappyGhetto omg oop coders are the worst
@HappyGhetto2 ай бұрын
@@feivmoon How would you solve his problem? I'm not familar with GDScript, I come from unreal so yes I'm more familiar with OOP.
@Deathkyun2 ай бұрын
I haven't gone though this problem yet, so I'm not even sure if my propositions work, but I'll throw my hat in as a comment for the sake of the algorithm. I think I would have gone with option 2 with some modifications: Either define my signals in my event bus, or make a new event bus just for my state machine to decouple the signal from the emitter. So (I'm guessing) even if the code that emits the signal is destroyed, you won't have the null problem in your player script. If I wanted to avoid an event bus, I might play around with a clean up function before calling queue_free() on the plane that calls get_connections() on all my signal, and manually disconnecting them before freeing the node. (but again I haven't tried this and I'm not even sure if this works the way I think it does lol). Thanks for the videos, man. This is the first time I learned about set_meta. Hope to see and learn more!
@NesiAwesomeness2 ай бұрын
Thanks for the tip, I actually did that first as well. But I didn't want to have just one plane connected to the Message Bus as they were going to be multiple plane in the game and multiple NPCs also entering planes and I didn't want a case where the camera would follow a plane an NPC entered because the signal from that plane was connected to the message bus even though it isn't the player that entered it. So I decided to just keep all code that references the message bus to the player script.
@faytruefireside2 ай бұрын
I do not envy the added difficulty making games due to stuff needing* everything* to be in a low level language and be based on inheritance.
@faytruefireside2 ай бұрын
I'm not currently making the game I plan to make, instead I'm currently making backend and frontend software. But when I do it's in my plans to try to only use low level code for rendering, scene data manipulation/construction, and handling inputs. though ideally unreal engine would handle that all for me well enough that I barely have to touch it. And then I just use a higher level language on top since everything else that makes up a game doesn't use very many resources. Higher level languages mean you don't have to manage memory, you can utilize dynamic programming for faster development, utilize insane language features super smart people have made like virtual threads, and if it's a lisp you can create you're own DSL as easily as writing normal code(just don't create an abomination, especially if you're sharing the codebase with others). The higher level languages that are in my considerations are janet lang, and clojure(I may want to compile it to native using graalvm rather than using a JVM). There aren't a ton of lisp lanuages that exist, this is for many reasons, but janet lang and clojure should be able to cover everything, espectialy if Java's JNI successor or the jank lang dialect of clojure is done by the time I start, since interop with lower level code will be a lot simpler meaning I have to get annoyed by it even less. If I had to write low-level code for rendering, scene data manipulation/construction, or input handling due to the game engine not having what I need Id probably try to use roc or nim. Nim tries really hard to help you reduce state like clojure does, as well as help you make a DSL as easily as possible considering it isn't a lisp and so it's inherently a lot harder. Roc tries really hard to use smart compilation techniques leveraging modern memory constructions to find ways to retain many abstractions that are typically considered higher level, but without incurring a performance cost. But I haven't looked into how well those languages would interop with the existing game engines, though most stuff interops with C relatively well. A big consideration here is that my game doesn't need some super novel game engine, rendering technique, shader aesthetic, or anything else like that. Though it's worth mentioning that almost all games people make also fulfill this constraint. But lots of game developers seem to really like working on that "game engine" style stuff... at least the game developers I see on KZbin, even though the games are making don't need that.
@NesiAwesomeness2 ай бұрын
@@faytruefireside I use Godot, GDScript is a pretty high level language. Some systems do require a lot of thought just to make sure you're follow like "best practices". I actually knew you'd say unreal maybe I'll try that out too someday but Godot is just super convenient
@faytruefireside2 ай бұрын
@@NesiAwesomeness Yah unreal just has some insane rendering performance capabilities and rendering quality of life stuff. And we all know that our games get low on FPS way too quickly while developing them. Plus unreal costs like nothing to use. You have to make 1 million before you pay anything and even after that its 5%. For the vast majority of games its cheaper then unity.
@NesiAwesomeness2 ай бұрын
@@faytruefireside unreal is such a great choice, I just don't have the hardware for it, Godot is just super light weight
@faytruefireside2 ай бұрын
@@NesiAwesomeness I hope you arnt stuck with poor hardward forever, <3
@dbatdev2 ай бұрын
Great vid. Nice editing. I must look into metadata soon.
@NesiAwesomeness2 ай бұрын
You should
@sinus47842 ай бұрын
Why's the video interlaced?
@NesiAwesomeness2 ай бұрын
I have no idea what that is. I just used the KZbin preset on DaVinci Resolve.
@sinus47842 ай бұрын
@@NesiAwesomeness The pattern is 3 non interlaced frames, then there's 2 interlaced frames. If you go frame by frame in the video (in places with movement) you'll see frames where two other frames have been combined into one with alternating lines.
@NesiAwesomeness2 ай бұрын
@@sinus4784 yh I googled it, thanks so much I hope it didn't take too much away from the video?
@sinus47842 ай бұрын
@@NesiAwesomeness It doesn't :) I just wanted to mention it as it does look a little odd
@danielmiller82232 ай бұрын
1:21 - Knee-jerk reaction is to give a weak pointer to allow for this interaction. I do not know about your codebase at this point so I am assuming a C-like language that should have the ability to do this interaction. This weak pointer can be changed based on the last interacted aircraft of the player rather than hardcoded to the one you have on the screen now. 2:15 - Although I agree that keeping information private is ideal and probably the best solution, you can prevent tampering with information given by sending const data rather than a pointer to the object. Although you may be creating a copy of that variable or class when you request it, the optimizer may remove that and use a reference under the hood; so that may not be a concern. 2:46 - To shortcut this, you could give a weak reference to the player. This would allow you to send information of state change in the Aircraft State Machine (ASM for brevity) to the Player. The player then can have the responsibility to read those events or ignore them as desired. In your example, the last known state change of the ASM will determine the business logic of the Player in changing his State Machine. The difference from this and my knee-jerk reaction would be that the ASM can either post updates or the Player can poll updates. I like this suggestion better. 4:20 - Not sure if this is the best approach. Basically, it just adds the data from the State into the base class. Yes, you will not need to add additional code to each class, but it still requires functions to reach into another class to get the data it needs for evaluation. One way this problem can present itself is if you are referencing the object multiple times in the same function and during evaluation the object becomes null. Now this may not happen as often so may be difficult to reproduce and would be very tricky to even figure out why the program crashed in the first place depending on your language. Final assessment: Although I think you found a clever idea to deal with this issue, you may be able to reduce future complications in your code if you lock the aircraft state before evaluating it. My suggestion would be to move into more of an event driven paradigm where you send (publish) the state of the aircraft when it changes, and anyone can read (subscribe/observe) the changes if they want to know the latest change. This would create a more complicated situation, but would allow multiple NPCs/players to interact with the aircraft in the future (2-seater aircraft, etc.) Also allow and NPC and player to monitor the same aircraft for whatever reason. Note: I do think that your solution was very innovative and want to also say that these are just opinions/suggestions and there may be much better ways than what I presented. I am not writing the code and so cannot and should not have a perspective on what you should do. These are just considerations to make if they seem helpful.
@NesiAwesomeness2 ай бұрын
@@danielmiller8223 thanks so much, I'll see what I can do to try this. I'll have to read up on "weak pointers" and all that jazz. Thanks again.
@felixabbott1262 ай бұрын
I agree with the use of godots signals (observer pattern), but I don't believe godot has any sort of pointers you can use (from my understanding it's more similar to python) although if something like that does exist then let me know cuz that would be useful :O
@Húhú202ehhe2 ай бұрын
thats pretty cool i didnt know that
@NesiAwesomeness2 ай бұрын
@@Húhú202ehhe thank you
@chuckthediviner2 ай бұрын
First comment
@tumacho-d9t2 ай бұрын
I think you have to learn object-oriented design first in order to critique. 😅
@NesiAwesomeness2 ай бұрын
@@tumacho-d9t I'll let you slowly figure it out.
@blackandwhite74022 ай бұрын
Nice, I actually didn't see it coming to use behaviour trees in the plane and the camera ✌️ I learned something new
@GameInOne2 ай бұрын
ANy way to optimize this ? SO if im trying to draw it in full screen how can i make it smoother ?
@VitSoonYoung2 ай бұрын
Thanks for talking in such a peaceful way, not cutting the silence too much nor speed up talking as my brain uses those time to process. One question, what's the behavior of Camera: Freefall?
@NesiAwesomeness2 ай бұрын
It's just a script that controls the camera's movement when the player is free falling it keeps the player and plane in frame during that interaction
@theraven12322 ай бұрын
As a Haskell truther, you're on the right track. Just wait till you get into the insanity category theory offers. Problem is applying it to the main game engines, unless you're building your own engine it's hard to squeeze efficiency out of monadic composition, you're always gonna be beholden to OOP to some degree. The Scala-esque mixed approach will always be the best you can get away with in most cases.
@KenTheJr2 ай бұрын
So why Composition over ECS?
@JanVerny2 ай бұрын
OOP places a high burden on the designer of the system. Any unforeseen situation can lead to costly refactors, and this might repeat several times before one arrives at the correct solution for the problem. Functional programming attempts to solve the issue by allowing the system to evolve more organically. Like a city, you just tack on more streets, more houses, more floors, until your system can't take it no more and people are spending 3h in traffic for 7km trip. I think this debate will never be settled because the functional approach just isn't scalable, while correct OOP is too difficult to be practiced by the masses.
@WorldEnder2 ай бұрын
always love to see a 2 years experienced programmer take a s h iat on OOP
@ManilaSh8-co3fn3 ай бұрын
Why am I here. I just started as a developer. This is too advance lol
@GameDevBry3 ай бұрын
Really cool, are you sharing the sauce code? 🥫🙂
@UltimatePerfection3 ай бұрын
Can't wait to debug why my character is running, jumping, falling and being idle at the same time.