Clean and Extensible: Chain of Responsibility in Unity Projects

แชร์
ฝัง
  • เผยแพร่เมื่อ 18 ธ.ค. 2024

ความคิดเห็น • 71

  • @git-amend
    @git-amend  10 วันที่ผ่านมา +16

    Happy Sunday! Let’s dive into the Chain of Responsibility pattern and explore how it can transform your code with clean, modular architecture!

    • @AliceEverglade
      @AliceEverglade 9 วันที่ผ่านมา

      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?

  • @Hersatz
    @Hersatz 10 วันที่ผ่านมา +3

    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.

  • @silchasruin4487
    @silchasruin4487 10 วันที่ผ่านมา +6

    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?

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +2

      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!

  • @toastyshrimp1882
    @toastyshrimp1882 10 วันที่ผ่านมา +5

    been waiting on you covering this for months ever since I saw Aarthficial's video on it. Great stuff as always

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      It's been in the backlog for a while! Finally got around to it!

  • @YJPLAPI
    @YJPLAPI 10 วันที่ผ่านมา

    Gradually came to love Sundays. Thanks as always for the time you take making your videos!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Thank you so much! I’m glad you’re enjoying the videos-and Sundays too! Your support means a lot!

  • @Briezar
    @Briezar 10 วันที่ผ่านมา +1

    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!

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      I'll have to check that out. I really like Zoran's channel.

  • @MrOmega-cz9yo
    @MrOmega-cz9yo 10 วันที่ผ่านมา +1

    I like these intermediate level videos. Thanks!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Glad to hear that, thank you!

  • @grzegorzpedrycz2630
    @grzegorzpedrycz2630 7 วันที่ผ่านมา

    Pure gold as always;)

    • @git-amend
      @git-amend  7 วันที่ผ่านมา

      Thanks for watching!

  • @Hersatz
    @Hersatz 10 วันที่ผ่านมา +3

    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.

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      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!

  • @정동우-n2x
    @정동우-n2x 9 วันที่ผ่านมา

    The structure is really beautiful. I want to code like this one day.

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      Glad to hear it! Keep coding!

    • @정동우-n2x
      @정동우-n2x 9 วันที่ผ่านมา

      @@git-amend I'm always referring to it. Your Git Hub is my inspiration source and source code.

  • @FirebreathingGamesOG
    @FirebreathingGamesOG 9 วันที่ผ่านมา

    Great details

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Thank you! Cheers!

  • @vSwaize
    @vSwaize 10 วันที่ผ่านมา +1

    Great video!

    • @git-amend
      @git-amend  10 วันที่ผ่านมา

      Thanks, I'm glad you liked it!

  • @lonbpalmer
    @lonbpalmer 10 วันที่ผ่านมา

    Another fantastic video

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Thanks!

  • @mangakaray
    @mangakaray 9 วันที่ผ่านมา

    always great videos!!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      Thank you! I'm glad you're enjoying them.

  • @gonzaloasencio4503
    @gonzaloasencio4503 10 วันที่ผ่านมา

    Great intro !!!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Glad you liked it! I've been using Timeflow lately.

  • @setroid8235
    @setroid8235 10 วันที่ผ่านมา +1

    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.

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      Nice tip, thanks for posting that.

    • @JohannesDeml
      @JohannesDeml 16 ชั่วโมงที่ผ่านมา +1

      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.

  • @sebastianking7713
    @sebastianking7713 10 วันที่ผ่านมา +1

    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!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      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

    • @sebastianking7713
      @sebastianking7713 9 วันที่ผ่านมา

      @@git-amend This is fantastic. Thank you!

  • @VyvyanTheGreat
    @VyvyanTheGreat 9 วันที่ผ่านมา

    brilliant!

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Thanks!

  • @damonfedorick
    @damonfedorick 10 วันที่ผ่านมา +1

    Nice!

    • @git-amend
      @git-amend  10 วันที่ผ่านมา

      Thanks! Cheers!

    • @damonfedorick
      @damonfedorick 10 วันที่ผ่านมา

      @@git-amend Congrats on hitting 1 million total views.

    • @git-amend
      @git-amend  10 วันที่ผ่านมา

      Amazing isn't it!

  • @shuoyuanchen7800
    @shuoyuanchen7800 10 วันที่ผ่านมา

    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

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      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!

  • @shayshay8295
    @shayshay8295 10 วันที่ผ่านมา +1

    What do you think about using Exceptions for cutting the chain?
    for example:
    try
    {
    operation1();
    operation2();
    operation3();
    }
    catch(CutChainException cce)
    {
    }

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      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.

    • @shayshay8295
      @shayshay8295 10 วันที่ผ่านมา

      @@git-amend btw great content, keep it up!

  • @x2andrew
    @x2andrew 10 วันที่ผ่านมา

    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

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Maybe, I'll put that on the TODO list.

  • @jumpkut
    @jumpkut 9 วันที่ผ่านมา

    the MVP coding channel strikes again

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      Appreciate the support! Glad you’re enjoying the content-more to come!

  • @AryanSingh-cw6ce
    @AryanSingh-cw6ce 10 วันที่ผ่านมา

    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?

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      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.

  • @kaizerwaldproject3594
    @kaizerwaldproject3594 10 วันที่ผ่านมา

    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 ?

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +1

      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.

  • @MarushiaDark316
    @MarushiaDark316 10 วันที่ผ่านมา

    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?

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +2

      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.

  • @urielvilanueva3099
    @urielvilanueva3099 10 วันที่ผ่านมา

    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?

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      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.

    • @urielvilanueva3099
      @urielvilanueva3099 8 วันที่ผ่านมา

      @@git-amend thank you so much!

  • @samidev4122
    @samidev4122 10 วันที่ผ่านมา

    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

    • @git-amend
      @git-amend  10 วันที่ผ่านมา +4

      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.

    • @drewalkemade3715
      @drewalkemade3715 10 วันที่ผ่านมา

      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.

  • @ugurkarabulut8598
    @ugurkarabulut8598 9 วันที่ผ่านมา

    I am using this pattern to create on boarding or first time user experience

    • @git-amend
      @git-amend  9 วันที่ผ่านมา

      Nice! Great use case!

  • @puretrack06
    @puretrack06 10 วันที่ผ่านมา

    Looks like I'm refactoring this week cuz I could have used this video like 3 weeks ago

    • @git-amend
      @git-amend  10 วันที่ผ่านมา

      Always time to refactor :)

    • @puretrack06
      @puretrack06 8 วันที่ผ่านมา

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

    • @git-amend
      @git-amend  7 วันที่ผ่านมา

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

  • @TuberTugger
    @TuberTugger 10 วันที่ผ่านมา

    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.

    • @git-amend
      @git-amend  9 วันที่ผ่านมา +1

      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.