I have a question, is there any design pattern for saving specific data? for a while now I've been trying to come up with a system where I can create an object, lets call it an EventTree object, for this example I'll have a dog stuck in a hole or so I want this EventTree to hold a bunch of events like HeardOfDog - SeenDog - InteractedWithDog - (and here could be a split between RescuedDog and Didn'tRescueDog), which could merge into - LeftDog my goal is to easily make these objects and to store the current state of the tree where the player is at in an efficient manner because I want a lot of these. any ideas?
On a side note, for quests in games I usually choose to use something more akin to a behaviour tree to handle quests. It offers a lot of flexibility due to how we can create nodes for both controlling the flow of a quest and evaluating what succeed or fail that quest with a clear logical delimitation. It is also fairly easy to read and understand from juniors upwards. For example, a Sequence node (control of the flow) implies that N condition nodes must be executed in order for the quest to complete. A Fallback node (control of the flow) implies that any of the condition nodes can be completed and the quest will complete. Etc. Condition nodes are simply callbacks where we subscribe to an event that will complete or fail the current node of the quest when it is active and unsubscribe when it becomes inactive. Very powerful and flexible stuff.
This is why I recommend even beginner Devs to your channel. It's better to learn these patterns early on than fall into the pit of logic blocks that turn into actual blocks in your code. Your implementation is such a neat and modular quest system. It gives me ideas for handling game states and behaviours. You mentioned your work, what do you do as your day job, if there's no hush hush?
Thank you so much for recommending the channel-it means a lot! I totally agree; learning these patterns early can save so much time and frustration later. As for my day job, I work in solution architecture and software development, which gives me plenty of opportunities to design and implement systems like these. It’s always fun bringing that experience into game dev!
Zoran Horvat's video on using COR to fluently chain the sorting rule of a list of data is what blew my mind about this particular pattern, but since then I've not found a meaningful use-case. It does overlap quite a bit with the strategy pattern too. The quest system is a nice use-case, but the debug one seems a bit too over-engineered for a debug tool xD Nice video!
That's true. It seems to be that people often forget it's usefulness until it's too late and then decide not to refactor. But maybe this video will help!
More often, I prefer to use a class that defines the chain and how it steps through (using a container of objects with the given interface). Relying on correct implementation of the interface ties the class to the operation of the whole chain. This adds the extra layer of remembering to call the next class the way you expect it to in the chain rather than having the operation of the chain all in one class.
My thought as well, it is easier to extend the logic around it (e.g. adding new chain elements later on in the program) and also the stack traces will not become that deep, since we're stepping out of each processor method before entering the next.
Hey @git-amend! Do you have any suggested patterns for implementing heavy sequential-activity/synchronous-operations for games like Balatro? For example, in Balatro, when we play our hand, there is a sequence of processes that need to take place to evaluate the score for the hand. Essentially the game first evaluates any boss effect to be applied on the cars, then subsequently iterates through each card in the hand to calculate the impacts of the jokers, then final iterates through the jokers to apply any effects they might have on the score. I'd love to know how you would approach this kind of problem!
Chain of Responsibility could work if the steps in your sequence might conditionally handle or skip processing (e.g., certain cards bypass specific effects). However, for guaranteed, ordered, sequential processing like in your example, the Pipeline Pattern is a great choice. Each stage of your sequence (e.g., boss effects, card evaluations, joker effects) becomes a pipeline step, where each step processes data and passes it to the next. Combine it with a State Pattern to track intermediate results or contextual data as the pipeline progresses, ensuring clarity and flexibility for complex operations. You can read about that here: levelup.gitconnected.com/design-patterns-implementing-pipeline-design-pattern-824bd2d42bab
This reminds me of web dev, backend. Where we are chaining processors to handle requests, either passing the payload to the next processor or send response right away. It keeps code organized and modular. I wonder if you can turn this into a generic framework for games
You're absolutely right-this pattern is heavily used in web backends for routing requests! You could definitely adapt it into a generic framework for games, where the processors handle things like events, input, or AI behaviors. The key would be making the chain dynamic and extensible, so you can plug in custom processors for different systems or genres. It’s a great idea!
What do you think about using Exceptions for cutting the chain? for example: try { operation1(); operation2(); operation3(); } catch(CutChainException cce) { }
I think that's reasonable, so long as you don't want any other handlers to run. In a more advanced scenario you could also have the chain branch to handle exceptions and follow a different path.
You really create a video on quest system I asked you a while ago and you delivered , you are the best . So, Is this pattern used to remove a lot of if statements? Like if i create a class that could potentially have 100-1000 of if statement , should i use it then or there are more use cases?
Well, to be frank I would build something a lot more serious than this for a real Quest system. This is just a simple example of the pattern. This is one way to eliminate if statements. Use the Chain of Responsibility pattern when you need to handle different requests in varying sequences, especially when the request types and handler order are dynamic or must change at runtime.
Very interesting pattern! just one question about the implementation why do we implement an interface on top of the abstract class instead of just making a abstract class ? will it break something if we do without the interface ?
Great question! Using an interface provides flexibility, allowing other classes or structures to implement the chain without inheriting from the abstract base class. It won't break functionality if you remove the interface, but you'll lose that flexibility, and your chain will be tied to the specific abstract class hierarchy. In practice, I almost always start from interfaces as it also makes it very easy to create mocks for testing.
Not quite! While the Builder Pattern uses method chaining to configure complex objects, it’s not a form of Chain of Responsibility. COR focuses on passing a request through a chain of handlers where each can choose to process or pass it along. Builder, on the other hand, constructs an object step-by-step in a predetermined flow, with no conditional delegation of tasks. They serve different purposes despite the similar chaining mechanism.
Hi! i'm a really inexperienced dev who has been trying developing games while following good practices, I really really like your videos, I've been scratching my head to find the best pattern to implement a sinergy system similar to the ones you can find in roguelikes like the binding of isaac, where semeanly, the objects combine a series of modifications to output a result, what you could say is the best programming pattern for something like this?
Thanks for the kind words! For a synergy system like that, you might consider the Decorator Pattern-it’s great for dynamically combining modifications while keeping each behavior modular. Pair it with a Composite Pattern if you need to handle nested effects or hierarchies of synergies.
Sir what programming pattern should I use as someone trying to build his first big project till now I only did game jam so I decided I would look some good architecture to actually complete big project
Underrated comment right here... This needs to be bumped. Git, please make a long form tutorial of a complete game... Something akin to Rob Ager's dungeon gunner (but let's make an ice hockey clone :)) We're really down the abstract rabbit hole now, we need some sort of full project to pull it all together.
@@git-amend So this is what I needed for my project and I somewhat already had this pattern in my existing code. However I am confused on trigger the next step in a quest. IE to the location, once at location that step of the quest is completed and we trigger a boss fight. Do we go through the entire stack of messages again or can we save the stack in the quest dictionary?
@@puretrack06 Technically you could save a reference to any link in the chain, and enter the chain from any point. In practice, I doubt it will affect performance much to enter the chain from the beginning. Up to you.
Seems a little unnecessary to add all these new classes and interfaces to the COR namespace. Similar to a builder pattern, I'd prefer a top level class with a bunch of sub interfaces implementing each handler step. I don't want my IDE sifting through dozens of "i" named interfaces for intelesense every time I want to do something. I could see the argument for separated namespaces instead, possibly for part mentalizing compilation. But it might be overkill to make an entire namespace just for quest management. You also get the nice added benefit of less verbose naming conventions for each interface/class object because everything is obviously part of Quest. Either everything in QuestManager, or wrap a Processor object within QuestManager that has all the sub classes/interfaces. I like the second choice because I prefer my monobehavior inheriting code to be as simple as possible. And non-monobehavior inheriting scripts do all the heavy lifting. But I realize that's more of a preference.
Thanks for the thoughtful comment! First, the video is meant to serve as a clear example that most people can understand, rather than being a production-ready system. But you do bring up some good points. For real projects, collapsing processors into inner classes or submodules of QuestManager can avoid clutter while staying modular. Keeping everything scoped within a clear context like QuestManager also reduces verbose naming and improves IDE usability. I’m with you on keeping MonoBehaviours as lightweight as possible and delegating the heavy lifting to non-MonoBehaviour classes.
Happy Sunday! Let’s dive into the Chain of Responsibility pattern and explore how it can transform your code with clean, modular architecture!
I have a question, is there any design pattern for saving specific data?
for a while now I've been trying to come up with a system where I can create an object, lets call it an EventTree object,
for this example I'll have a dog stuck in a hole or so
I want this EventTree to hold a bunch of events like HeardOfDog - SeenDog - InteractedWithDog - (and here could be a split between RescuedDog and Didn'tRescueDog), which could merge into - LeftDog
my goal is to easily make these objects and to store the current state of the tree where the player is at in an efficient manner because I want a lot of these. any ideas?
On a side note, for quests in games I usually choose to use something more akin to a behaviour tree to handle quests.
It offers a lot of flexibility due to how we can create nodes for both controlling the flow of a quest and evaluating what succeed or fail that quest with a clear logical delimitation.
It is also fairly easy to read and understand from juniors upwards.
For example, a Sequence node (control of the flow) implies that N condition nodes must be executed in order for the quest to complete. A Fallback node (control of the flow) implies that any of the condition nodes can be completed and the quest will complete. Etc.
Condition nodes are simply callbacks where we subscribe to an event that will complete or fail the current node of the quest when it is active and unsubscribe when it becomes inactive.
Very powerful and flexible stuff.
This is why I recommend even beginner Devs to your channel. It's better to learn these patterns early on than fall into the pit of logic blocks that turn into actual blocks in your code. Your implementation is such a neat and modular quest system. It gives me ideas for handling game states and behaviours. You mentioned your work, what do you do as your day job, if there's no hush hush?
Thank you so much for recommending the channel-it means a lot! I totally agree; learning these patterns early can save so much time and frustration later. As for my day job, I work in solution architecture and software development, which gives me plenty of opportunities to design and implement systems like these. It’s always fun bringing that experience into game dev!
been waiting on you covering this for months ever since I saw Aarthficial's video on it. Great stuff as always
It's been in the backlog for a while! Finally got around to it!
Gradually came to love Sundays. Thanks as always for the time you take making your videos!
Thank you so much! I’m glad you’re enjoying the videos-and Sundays too! Your support means a lot!
Zoran Horvat's video on using COR to fluently chain the sorting rule of a list of data is what blew my mind about this particular pattern, but since then I've not found a meaningful use-case. It does overlap quite a bit with the strategy pattern too. The quest system is a nice use-case, but the debug one seems a bit too over-engineered for a debug tool xD
Nice video!
I'll have to check that out. I really like Zoran's channel.
I like these intermediate level videos. Thanks!
Glad to hear that, thank you!
Pure gold as always;)
Thanks for watching!
I don't see many people using that pattern these days in our field.
It's a good thing that you took the time to introduce it to the community.
That's true. It seems to be that people often forget it's usefulness until it's too late and then decide not to refactor. But maybe this video will help!
The structure is really beautiful. I want to code like this one day.
Glad to hear it! Keep coding!
@@git-amend I'm always referring to it. Your Git Hub is my inspiration source and source code.
Great details
Thank you! Cheers!
Great video!
Thanks, I'm glad you liked it!
Another fantastic video
Thanks!
always great videos!!
Thank you! I'm glad you're enjoying them.
Great intro !!!
Glad you liked it! I've been using Timeflow lately.
More often, I prefer to use a class that defines the chain and how it steps through (using a container of objects with the given interface). Relying on correct implementation of the interface ties the class to the operation of the whole chain. This adds the extra layer of remembering to call the next class the way you expect it to in the chain rather than having the operation of the chain all in one class.
Nice tip, thanks for posting that.
My thought as well, it is easier to extend the logic around it (e.g. adding new chain elements later on in the program) and also the stack traces will not become that deep, since we're stepping out of each processor method before entering the next.
Hey @git-amend! Do you have any suggested patterns for implementing heavy sequential-activity/synchronous-operations for games like Balatro? For example, in Balatro, when we play our hand, there is a sequence of processes that need to take place to evaluate the score for the hand. Essentially the game first evaluates any boss effect to be applied on the cars, then subsequently iterates through each card in the hand to calculate the impacts of the jokers, then final iterates through the jokers to apply any effects they might have on the score.
I'd love to know how you would approach this kind of problem!
Chain of Responsibility could work if the steps in your sequence might conditionally handle or skip processing (e.g., certain cards bypass specific effects). However, for guaranteed, ordered, sequential processing like in your example, the Pipeline Pattern is a great choice. Each stage of your sequence (e.g., boss effects, card evaluations, joker effects) becomes a pipeline step, where each step processes data and passes it to the next. Combine it with a State Pattern to track intermediate results or contextual data as the pipeline progresses, ensuring clarity and flexibility for complex operations. You can read about that here: levelup.gitconnected.com/design-patterns-implementing-pipeline-design-pattern-824bd2d42bab
@@git-amend This is fantastic. Thank you!
brilliant!
Thanks!
Nice!
Thanks! Cheers!
@@git-amend Congrats on hitting 1 million total views.
Amazing isn't it!
This reminds me of web dev, backend. Where we are chaining processors to handle requests, either passing the payload to the next processor or send response right away. It keeps code organized and modular. I wonder if you can turn this into a generic framework for games
You're absolutely right-this pattern is heavily used in web backends for routing requests! You could definitely adapt it into a generic framework for games, where the processors handle things like events, input, or AI behaviors. The key would be making the chain dynamic and extensible, so you can plug in custom processors for different systems or genres. It’s a great idea!
What do you think about using Exceptions for cutting the chain?
for example:
try
{
operation1();
operation2();
operation3();
}
catch(CutChainException cce)
{
}
I think that's reasonable, so long as you don't want any other handlers to run. In a more advanced scenario you could also have the chain branch to handle exceptions and follow a different path.
@@git-amend btw great content, keep it up!
Thanks for the video.
Can we get a video about new input system set up with gameplay and ui action maps? Would be very helpful
Maybe, I'll put that on the TODO list.
the MVP coding channel strikes again
Appreciate the support! Glad you’re enjoying the content-more to come!
You really create a video on quest system I asked you a while ago and you delivered , you are the best . So, Is this pattern used to remove a lot of if statements? Like if i create a class that could potentially have 100-1000 of if statement , should i use it then or there are more use cases?
Well, to be frank I would build something a lot more serious than this for a real Quest system. This is just a simple example of the pattern. This is one way to eliminate if statements. Use the Chain of Responsibility pattern when you need to handle different requests in varying sequences, especially when the request types and handler order are dynamic or must change at runtime.
Very interesting pattern! just one question about the implementation why do we implement an interface on top of the abstract class instead of just making a abstract class ? will it break something if we do without the interface ?
Great question! Using an interface provides flexibility, allowing other classes or structures to implement the chain without inheriting from the abstract base class. It won't break functionality if you remove the interface, but you'll lose that flexibility, and your chain will be tied to the specific abstract class hierarchy. In practice, I almost always start from interfaces as it also makes it very easy to create mocks for testing.
Would it be fair to say the Builder Pattern is a form of COR since you can effectively chain methods together in creating complex entities?
Not quite! While the Builder Pattern uses method chaining to configure complex objects, it’s not a form of Chain of Responsibility. COR focuses on passing a request through a chain of handlers where each can choose to process or pass it along. Builder, on the other hand, constructs an object step-by-step in a predetermined flow, with no conditional delegation of tasks. They serve different purposes despite the similar chaining mechanism.
Hi! i'm a really inexperienced dev who has been trying developing games while following good practices, I really really like your videos, I've been scratching my head to find the best pattern to implement a sinergy system similar to the ones you can find in roguelikes like the binding of isaac, where semeanly, the objects combine a series of modifications to output a result, what you could say is the best programming pattern for something like this?
Thanks for the kind words! For a synergy system like that, you might consider the Decorator Pattern-it’s great for dynamically combining modifications while keeping each behavior modular. Pair it with a Composite Pattern if you need to handle nested effects or hierarchies of synergies.
@@git-amend thank you so much!
Sir what programming pattern should I use as someone trying to build his first big project till now I only did game jam so I decided I would look some good architecture to actually complete big project
Start with Abstract Factory, Fluent Builder and Strategy. There are videos in the playlist for each of those. These are the ones I use almost daily.
Underrated comment right here... This needs to be bumped. Git, please make a long form tutorial of a complete game... Something akin to Rob Ager's dungeon gunner (but let's make an ice hockey clone :)) We're really down the abstract rabbit hole now, we need some sort of full project to pull it all together.
I am using this pattern to create on boarding or first time user experience
Nice! Great use case!
Looks like I'm refactoring this week cuz I could have used this video like 3 weeks ago
Always time to refactor :)
@@git-amend So this is what I needed for my project and I somewhat already had this pattern in my existing code. However I am confused on trigger the next step in a quest. IE to the location, once at location that step of the quest is completed and we trigger a boss fight. Do we go through the entire stack of messages again or can we save the stack in the quest dictionary?
@@puretrack06 Technically you could save a reference to any link in the chain, and enter the chain from any point. In practice, I doubt it will affect performance much to enter the chain from the beginning. Up to you.
Seems a little unnecessary to add all these new classes and interfaces to the COR namespace.
Similar to a builder pattern, I'd prefer a top level class with a bunch of sub interfaces implementing each handler step. I don't want my IDE sifting through dozens of "i" named interfaces for intelesense every time I want to do something. I could see the argument for separated namespaces instead, possibly for part mentalizing compilation. But it might be overkill to make an entire namespace just for quest management.
You also get the nice added benefit of less verbose naming conventions for each interface/class object because everything is obviously part of Quest.
Either everything in QuestManager, or wrap a Processor object within QuestManager that has all the sub classes/interfaces. I like the second choice because I prefer my monobehavior inheriting code to be as simple as possible. And non-monobehavior inheriting scripts do all the heavy lifting. But I realize that's more of a preference.
Thanks for the thoughtful comment! First, the video is meant to serve as a clear example that most people can understand, rather than being a production-ready system. But you do bring up some good points. For real projects, collapsing processors into inner classes or submodules of QuestManager can avoid clutter while staying modular. Keeping everything scoped within a clear context like QuestManager also reduces verbose naming and improves IDE usability. I’m with you on keeping MonoBehaviours as lightweight as possible and delegating the heavy lifting to non-MonoBehaviour classes.