Hey there, everyone! Today's topic is quite advanced, so if you're feeling a bit lost, drop any questions you have in the comments below! If you're a beginner or intermediate C# dev, take note of anything that's new to you. Use this opportunity to fill in those knowledge gaps! Let's go!
@Ayushmaan_Singh775 ай бұрын
I am someone who already crossed the threshold of beginner programmer long ago but was having a lot of difficulty being better as a intermediate programmer and rising even further. Your videos are simply awesome and provide guys like us with valuable knowledge. Thanks a lot.
@git-amend5 ай бұрын
Thanks for the nice comment! I'm really glad to hear that!
@banoulka8 ай бұрын
This channel and these videos were such a goldmine to find, hopefully the algorithm gods keep up the new engagement for you!
@git-amend8 ай бұрын
Thank you!
@DetectivePoofPoof8 ай бұрын
Excellent! It's great to see more advanced things instead of just the basics which are very over-represented in tutorial videos.
@git-amend8 ай бұрын
Glad you enjoyed it!
@matthewthomas11058 ай бұрын
I've been looking for more advanced Unity content (with explanation) so these are fantastic!
@git-amend8 ай бұрын
Glad to hear that! Welcome!
@prometheus11008 ай бұрын
Yeah I love these! They're a regular Sunday thing now for me ;)
@git-amend8 ай бұрын
Nice! Glad to hear that!
@Fitz0fury8 ай бұрын
Sundays I get up with my kid and get my first watch in before he is awake enough to have TV opinions!
@SuperTungbi8 ай бұрын
every time i saw a video from you, i feel my self so small, so much to learn, thank you for sharing your knowledge.
@git-amend8 ай бұрын
You are very welcome! I hope the channel is helping you in your journey to becoming an expert!
@AnotherGameDev24118 ай бұрын
I need an audiobook of you teaching me C#... Incredible topic, loved the implementation!
@git-amend8 ай бұрын
An audiobook… interesting idea! Lol. Glad you liked the vid!
@NathanSL118 ай бұрын
Another great video! I usually pull out the string key into another ScriptableObject that can then cache the FNV hash at editor time instead of runtime, I usually also cast the number down to a short and then check for collisions in the editor. This is mostly for some slight bandwidth saving over the network. The benefit of the key also being a SO is it lets you reduce string naming errors across your project whether you use them as blackboard keys or any other type of named keys.
@git-amend8 ай бұрын
Great insights! Thanks for sharing that!
@NadjibBait8 ай бұрын
Great video. The Arbiter/Experts system works kinda like Utility AI. Small note: Vector3 is a struct and will be boxed when cast to an object.
@git-amend8 ай бұрын
Thanks for the comment and for noticing that. I've updated the repository to handle Vector3s without boxing! Cheers!
@SuperLordee8 ай бұрын
Damn dude releases one high quality video after another.
@git-amend8 ай бұрын
Thank you!
@kpm258 ай бұрын
awesome, the best unity coding channel on KZbin!!
@git-amend8 ай бұрын
Made my day, thanks!
@rucesocial8 ай бұрын
I've tried something like this before and this is a good example! Thanks
@git-amend8 ай бұрын
Nice, glad to hear that!
@DrGrooАй бұрын
Thanks for a great, in depth video on Blackboards.
@git-amendАй бұрын
You're welcome!
@sizcate8 ай бұрын
thank you so much for your content, i'm learning a lot and you are helping me achieve my first game!
@git-amend8 ай бұрын
Glad to hear it!
@jeffreyhersh9082 ай бұрын
I recently updated this to use the Unity.Mathematics library and used Odin to make an inspector value drawer for the AnyValue struct along with a bunch of custom editor fields for things like uInts, VectorXInt, etc. Working now on including collections which is a whole can of worms.
@selmansavas5868 ай бұрын
Always a treat, love your videos ❤️
@git-amend8 ай бұрын
Thanks so much 😊
@GTZ-988 ай бұрын
Lets goooo! Another video where I‘m glad if I atleast understand half of it haha :D
@git-amend8 ай бұрын
Fantastic! Another chance to grow! Keep it up!
@GTZ-988 ай бұрын
Yes, for sure! I really appreciate the content you‘re dropping for free! You‘re great, man!
@borailkinonu41368 ай бұрын
Another great video! Thank you, Adam!
@git-amend8 ай бұрын
Glad you enjoyed it! You're welcome!
@CodiushMaximush7 ай бұрын
A very interesting video, you've found a new subscriber. My nose scrunched up a little when you had to add explicit support for each data type in the same file for your configuration scriptable object. I can't confidently come up with a better solution yet though. Also, it may be a regional thing, but I don't think that's how Arbiter is pronounced.
@git-amend7 ай бұрын
Thanks for subscribing! Glad to have you on board!
@Saiyugi16Ай бұрын
Excellent, i recently have been experimenting with Behaviour Trees and was trying to implement the Blackboard Architecture to combine both but Blackboard Architecture has been a well kept secret with alot of mentions but no pudding (example best practices)... I curious how to combine Behaviour Trees to take advantage of the Blackboard Architecture if i coulf get an example of that I woulf have a better idea of potential best practice
@paulm85017 ай бұрын
Truly amazing!! Thanks, man
@git-amend7 ай бұрын
My pleasure!
@protobilly8 ай бұрын
I've been looking solid intermediate-skill level examples of game systems! Thank you! Something that might help make these concepts easier to grasp (across all your content) is a few more infographic breakouts to reinforce the broad (or current) concepts (like you did at 19:27). You do a great job of laying it out at the start, but I find it a bit dizzying when following the implementation for 10-15 min at a time. Stepping back to talk about what was just done and how it fits in might make your videos a bit easier to digest.
@git-amend8 ай бұрын
Thanks for the comment. The goal of this channel is to help game devs advance to a professional level; I'll keep your suggestion in mind!
@youssefkhaled4127 ай бұрын
Hey, Adam, just wanted to say I absolutely love the content, I hope your channel grows to the numbers you deserve! Have you considered making an advanced Unity/architecture course? I'm thinking maybe something that builds on a game like your 3D platformer, but with more fleshed out details and systems. Obviously the game itself doesn't have to be anything new (it's not a game design course after all) but something that employs different design patterns where they actually fit and make sense, not "just because." I'd definitely pay for something like that! Keep up the great work.
@git-amend7 ай бұрын
Thanks for the kind words! I have been thinking about making a longer course about architecture actually, but it might not come until next year. I should have plenty of notes by then. In the mean time, we'll keep talking about the subject, and more about patterns and so on in smaller KZbin chunks!
@youssefkhaled4127 ай бұрын
@@git-amend Of course, man, that’s understandable! The quality of your content is already unbelievable as it is, good luck with everything 💪🏻
@techdave998 ай бұрын
I think I understand the concepts. This is different from what chatgpt would have you do to implement a blackboard. Will watch again to see how it is implemented. Going to watch your other related videos again. Will definitely checkout the code for this one.
@git-amend8 ай бұрын
Sounds good. I should see what ChatGPT would say.
@techdave998 ай бұрын
@@git-amend it would just have you implement a basic string based system. Would much rather have an adamgpt to use. :)🤣
@git-amend8 ай бұрын
@@techdave99 Haha!
@jumpkut2 ай бұрын
Really great video! Am I right in that the blackboard pattern is often what's used to create 'Stats' systems? Seems familiar!
@Illasera2 ай бұрын
Question on FNV1A, what is the collision frequency? as i use XXH3 (Not via C# but a C code loaded as a .dll). Low collision rate is nice but... is there a figure? Can't run a test of my own to check it because the amount of RAM that will be needed... *A server is needed to run billions of hash tests; that's why i am asking is there a figure for it. Note : 19:34 - The last part; was the part you were suppose to start the video with; first you explain what it is; then you get to code.
@t33h33studio5 ай бұрын
Now THIS is content!!
@git-amend5 ай бұрын
Thank you!
@gsggshhhh4558 ай бұрын
Great video! Just wondering what would happen if the experts sent the same importance number to the arbiter?
@git-amend8 ай бұрын
Good question! I think the way you handle that would really depend on your game - but if you didn't do anything, it priority would go to the expert that registered first. Keep in mind too that you would probably implement much more complex values than 100/0 in the example, since you could base it on all kinds of Blackboard data as well as environment data and make it relative instead of static numbers. But it's definitely a good thing to consider.
@muhannadw8 ай бұрын
Man, I wish I have your knowledge, keep going :]
@git-amend8 ай бұрын
I appreciate that! Glad the channel is helping you in your own journey!
@TheKr0ckeR8 ай бұрын
Thanks a lot for your effort!
@git-amend8 ай бұрын
Haha how did you comment so fast! Thank you!
@TheKr0ckeR8 ай бұрын
@@git-amend Notifications on for your channel mate! Been waiting the video on sunday. I cant miss that.
@actk16 ай бұрын
OMG! This is so advance. You are one level higher than me.
@git-amend6 ай бұрын
Glad you like the vid!
@tr25ny2 ай бұрын
Hi this was amazing thanks for the tips, I've implemented it and it's working well. However, I was just wondering if it is possible to change the arbiter to make the insistence a bool instead of an int, and make it so it would execute all execution actions at once instead of the best one at that time. Or is there going to be race conditions while trying to write to the blackboard at the same time? and if it does then what about adding the actions for writing to the blackboard to a que then execute them one after another? I can make those changes fine, I just don't know if it would cause problems in the long run.
@git-amend2 ай бұрын
That's a good consideration, and you are exactly right. Race conditions, or unpredictable behaviour is exactly why they take turns. You can modify the system to handle more actions in a priority queue style so you can get more done in one frame, however.
@xbbotz8664 ай бұрын
This might be a silly question but I don't get it. In your AnyValue implementation, why would you choose to use a generic ConvertValue() function? why not simply return the value since we use an enum to determine the type?
@git-amend4 ай бұрын
The generic ConvertValue() function ensures type safety and flexibility by allowing a single method to handle conversions for all supported types, reducing redundancy and making the code easier to maintain. This approach centralizes type conversion logic and supports future extensions without requiring changes across multiple methods. Simply returning the value based on the enum would require multiple methods or manual casting for each type, resulting in less type safety, more redundancy, and a less flexible codebase. Keep in mind that directly returning values of different types using an enum without conversion would require boxing them in a common type (object) which would introduce performance overhead.
@Fitz0fury8 ай бұрын
"I'm just here to do my part to keep engagement numbers up" -sun tzu
@git-amend8 ай бұрын
And I appreciate that! Hopefully the video is also useful to you lol
@Fitz0fury8 ай бұрын
@git-amend tbh I knew nothing about blackboard. seems It's a pretty cool idea. My prototype AI isn't in my main project yet. All it did was store a target porirtization array, iterate over until it hits a condition it meets, then it selects an ability based on the target. the open of the method it also has a heal curve that can interrupt the normal targeting based on party status. It's super rudimentary. I figured once I had everything else in the new core project, I'd test out other AI methods. I could see an argument for this model. It would certainly be a better model to show effective team tactics/synergy. It would also solve my hate/provoke problem, which my only solution for before was to nest the rest of the targeting logic in an isprovoked bool check. I'm just not tackling AI again until after I have the remaining core systems back in the project. Probably in 2-3 months I'll revisit to make some AI decisions. I could easily get lost having fun with coding various synergies between units with this model l. It would be pretty cool, but it could easily turn into a hole where i overengineer an AI that doesn't yield a proportional increase in game quality. It's very complex solution for a turn based rpg -but I might not feel that way after another watch and some supplemental research.
@fokeyjo8 ай бұрын
I see this as bit of a blend of some other things I've seen, one is derived from Ryan Hipple's UniteAustin talk about scriptable objects holding a value, but of various types (but allowing them to be grouped into a single scriptable object you've definitely packed it much better). The other is that the arbiter stuff is just a utilityAI. So is blackboard just another term for utility AI? Or is it the globalised data access service, the BlackboardData stuff?
@franciscooteiza8 ай бұрын
Hello Adam, Congratulations on your fantastic video! I need some advice from you. I've developed a game UI launcher and divided it into two parts for simplicity: the left panel contains links for navigation, and the right part displays the actual pages. I'm using the MVC pattern you explained in one of your previous videos, and that part is working fine. However, I need some sort of Manager to control the calls resulting from user actions. For example, when a user clicks on the 'home page' option, the system would direct to the UIManager, which receives a string indicating which page to display in the content area. I'm currently using a simple switch statement, but I feel there might be a better approach. Do you think implementing a blackboard architecture would be overkill? Or is there another architecture you would recommend like an Event-driven architecture? Plus I have some DataCacheManager to keep in memory all the games loaded from a json list, but that is another story 😄 Thank you so much for all your informative videos and the knowledge you share with us. 🥰
@git-amend8 ай бұрын
I think an event-driven architecture would be highly effective. This would allow different components of your UI to communicate via events rather than direct calls, making your system more modular and easier to maintain than a simple switch statement. Implementing a blackboard architecture might be overkill for this use case, as it's generally better suited for more complex decision-making scenarios in AI systems rather than UI navigation.
@franciscooteiza8 ай бұрын
@@git-amend Thanks Adam! I highly appreciate your response.
@Legionope8 ай бұрын
I'm having trouble with the BlackboardData's T ConvertValue() method. I'm on Unity 2019.4 and it says that Feature 'recursive patterns' is not available in C# 7.3 Please use language version 8.0 or greater. :( Any way to get that method to work somehow?
@git-amend8 ай бұрын
I'm afraid not. Support for pattern matching did not come along until just recently. With older versions of Unity you are not going to be able to avoid boxing value types using this neat trick. You can still use the Blackboard, but you don't need the ConvertValue method. Just return everything as type object and let the compiler figure it out - there will be a bit more overhead, but in many cases you probably won't notice unless you are calling it many times per frame.
@codecombustion78788 ай бұрын
At 23:04: var actions = blackboard.PassedActions; // is this by value? If not, then wouldn't ClearActions clear the collection? blackboard.ClearActions();
@git-amend8 ай бұрын
Thanks for pointing that out, I've updated the repository to correct that.
@Bluequaz8 ай бұрын
Love some architecture discussion in your videos Just FYI arbiter is pronounced (arr-bit-err)
@git-amend8 ай бұрын
I was wondering about that afterwards if I was pronouncing it correctly in English. We have a similar word in Norwegian.
@vidmarmarko8 ай бұрын
Yeah I got confused for a moment. I thought he was saying worker in german. Great video, btw.
@isleeg8 ай бұрын
The hero still response on the space input, is this correct? If so then what does the scout do to impact the behaviour of the hero because it gets overruled. I used the latest code from the git
@git-amend8 ай бұрын
For the example you can remove the code from the Hero class
@xbbotz8666 ай бұрын
Hi, I wish to know is it safe to override Equal() with hashedKey == hashedKey. As far as I know hashedKey does not guarantee equality
@git-amend6 ай бұрын
Interesting comment - I was just thinking about talking about this in the next video... stay tuned!
@JP-yo4zt8 ай бұрын
Hi! I was wondering if you could make a video on implementing an inventory system similar to Witcher 3. Would really be helpful
@git-amend8 ай бұрын
Maybe one of these days!
@metsker48768 ай бұрын
I think you've made a mistake in the Scout class. On space input you're setting value directly to the blackboard, when you should've had just toggle the dangerSensor bool. So the IExpert interface is never actually used in that case 😅 Thanks for the video though, pretty informative
@git-amend8 ай бұрын
I see what you mean, thanks for pointing that out. I'll update it in the repository later on to be correct. Thanks!
@aurelienlerochbermuda66008 ай бұрын
Thanks you !
@git-amend8 ай бұрын
No problem
@DisturbedNeo6 ай бұрын
Huh, it's like a Reducer and a State Machine had a weirdly complicated baby
@MarkRiverbank7 ай бұрын
This is excellent, and you're teaching me many new tricks. But at 26:34 you're still directly toggling the "IsSafe" entry in the Update() method, and nothing ever sets the "dangerSensor" to true. Shouldn't your Update() code flip the value of dangerSensor [and flip it back again in Execute()] to actually use the Arbiter? Also, it looks like there's an issue with PassedActions; since it's returning a reference to the list, the ClearActions() causes the returned actions list to be cleared as well so they're never executed. The ClearActions() method probably needs to create a new empty list rather than clearing the existing one (or alternatively, the returned actions needs to be cloned from the existing list instead of a reference to it).
@git-amend7 ай бұрын
Good observations. This was actually an oversight on my part as I rushed to complete the video. The code was updated in the repository shortly after the video was released, as another subscriber also spotted that. Please refer to the most recent commit on the repo if necessary, but it seems you already know what's been updated.
@AliHosseiniDev8 ай бұрын
Nice video! If we use an obsfucator tool to encrypt our scripts, this architecture will not work at all. any suggestions for this issue?
@git-amend8 ай бұрын
One approach to address this issue is to use an obfuscator that supports exclusion rules. You can exclude specific types or members from obfuscation. In the case of your BlackboardKey class, you could exclude the name field from being obfuscated to ensure the ComputeFNV1aHash() function always operates on the correct data. If excluding fields from obfuscation isn't an option, you might want to reconsider how you're hashing keys. For example, instead of using a string name, you could use an identifier (like an enum or GUID) to generate your hash. This way, even if your scripts are obfuscated, your hashes should remain consistent.
@nullx23688 ай бұрын
Im making a roguelike card game with lot of dif stats/behaviour/unknowns. I have no idea what I'll be adding and this morning i was thinking to use a blackboard for this. It's likely not the perfect solution but it should allow me to add new things faster on the fly. Awesome timing on the video, do you think this is a good usecase? In the past I'v done some extensive extendable code that allowed you to configure lot of things in editor forthe cards, but as a solo developer I felt it didnt make things faster for me..
@git-amend8 ай бұрын
Yeah, it might be a useful tool for building this kind of thing. My only word of caution is to be careful that the Blackboard does not become a god object where every different system in your game is connecting to it. It can become a real nightmare to debug if you have problems. Consider using multiple Blackboards if necessary that are specific to certain systems.
@정동우-n2x8 ай бұрын
To be honest, I think you should adopt your video officially on Unity official KZbin.. I was watching terrible types of lectures that come up on KZbin and I fixed my code while watching your lectures.
@git-amend8 ай бұрын
Kind words, thank you.
@정동우-n2x8 ай бұрын
@@git-amend I'm learning a lot from you.
@あれくす8 күн бұрын
What does "BOXING" mean?
@git-amend8 күн бұрын
In C#, boxing means converting a value type (e.g., int, float, struct) into a reference type (object), which involves copying the value from the stack to the heap and creating a reference to it.
@あれくす8 күн бұрын
@git-amend thank you!
@damonfedorick8 ай бұрын
late i know, but nice.
@git-amend8 ай бұрын
Thanks!
@git-amend8 ай бұрын
@damonfedorick Can you ping me with a DM on Twitter or Discord when you get a second?
As always, great video, but one thing gets me: you only compare the BlackboardKey hashes, not their actual values. Given you use a hashing algorithm with very little collisions, you may get away with that. But if you ever get a collision, happy debugging whats going on, good luck.
@git-amend8 ай бұрын
That's a interesting point. I think though, if this were to be made more robust and still maintain efficiency, it would be better to guarantee no collisions than start comparing by value, which defeats the purpose of hashing in the first place. A different way to tackle that would be to keep a list of keys in a hashset and compare/modify the hash against that during creation, which could be done in the extension method with minimal effort. Thanks for the suggestion!
@lyrion08158 ай бұрын
@@git-amend But the only value in the BlackboardKey that is relevant for comparison, is the string name. Now string comparison is only slow, when long strings are almost equal. If they differ in the first few chars, the string comparison is fast. Even faster, if they are ReferenceEqual. I mean comparing ints is probably as performant as it can get, and each new string could just get an incrementing int Id instead of its hash, but anyways 🙂
@ashtarshtvany33013 ай бұрын
I am missing the point of having the Arbiter. What is the benefit of limiting the access to the blackboard to only one expert per frame? I would understand it as a performance optimization so not too much happens within one frame but I don't understand why read/write from the blackboard would be in anyway performance heavy operation. As I understand it, the expert already does the heavy lifting and would be just setting simple value to the blackboard.