Drag and Drop ENEMY AI With Scriptable Objects in Unity

Learn how to setup Enemy Brains or AI Behavior using Scriptable Objects allowing you to easily drag and drop new ai behavior through the Unity inspector.
Scriptable Objects are a powerful tool in structuring your code cleanly, and here is no exception. With this approach you can setup a complex enemy a.i. behavior tree while all of the behavior logic is separated into individual scriptable objects.
This follows the delegate pattern, which enables separation of concerns amongst your scripts which is an important practice in producing clean, maintainable code that will see your project through to the end.
Also its fun to play around with enemy "brains".
✨Want to support the channel?
Buy me a coffee ☕: ko-fi.com/bmoli
SUBSCRIBE or else I'll play around with your brain
➤Scriptable Object talk by Richard Fine: • Unite 2016 - Overthrow...
➤LIKE the video if you enjoyed, it really helps the channel!
➤Join our DISCORD SERVER: / discord
We have channels to help you with your problems!
Thanks for watching!
#bmo #unity #tutorial

Пікірлер: 42

  • @clarencetinator3782
    @clarencetinator37822 жыл бұрын

    Dood I was literally making a game rn, and figuring out how can I use scriptable objects to organize my enemy ai behaviors . Then this video got recommended to me like youtube is reading my mind and I realized this video was just uploaded 5 hours ago lol . What's more funny is I just subscribed to you like 15 hours ago. Anyways, keep up the good work man !!

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    Haha thanks! Let me know of theres any specific topics youre looking for

  • @Fyres11
    @Fyres112 жыл бұрын

    I've just used this idea to remake the AI in a game project. What we expected to take a month to rebuild. We did a working base in less than 2 days. Best idea ever to make modular behaviours. Old AI was over 1500 lines. The new one with all behaviours so far combined 260 lines. Update. We still use this system as base for our new Enemy AI, but with all the stuff we've covered we found out a few little limits. Pro: -Making modular AI behaviours easy to switch with another. -Specific behaviours for specific enemies. Con: -You can't use Async or IEnumerator in a scriptable object. They do work but for exemple 2-3 enemies die at the exact time, only one will trigger the Async or IEnumerator. You need to put them in the main script and use the the scriptable object behaviours to call it. -Start and update function doesn't exist in scriptable obj. Possible to create a ''fake'' update function called from the main script calling the update on the active behaviours.

  • @stefan429
    @stefan4292 жыл бұрын

    Great vid as always! This is my fave way to do AI in unity. You can also pass the target directly as a parameter. I also like to pass "context" (list of surrounding objects) as a parameter to allow boid like behaviors ☺

  • @eileeng2492
    @eileeng24922 жыл бұрын

    You deserve so many more subs! Great video

  • @mandamoon9149
    @mandamoon91492 жыл бұрын

    Bmo big brain 🧠 super helpful AI tutorial!

  • @Sam4Progress
    @Sam4Progress3 ай бұрын

    Honestly if I hadn't been subscribed already, that last bit would've earned it regardless haha! Keep up the good work and sense of humor! I have learned a great deal from your tutorials already!

  • @XPLexi_
    @XPLexi_2 жыл бұрын

    Thank you youtube recommended for this blessing.

  • @ibelonghere
    @ibelonghere Жыл бұрын

    Thank you for the tutorials. Making my way through them all, including the occasional BMO "Ted Talk" videos.

  • @suicune2001
    @suicune20012 жыл бұрын

    Thanks! I didn't think you could use those with AI.

  • @bobbville
    @bobbville2 жыл бұрын

    Showing love! 🔥🔥

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    Thanks!

  • @sr_viny2724
    @sr_viny2724 Жыл бұрын

    muito bom, justamente oque eu estava procurando.

  • @GamePhysics
    @GamePhysics3 ай бұрын

    This seems really good! I will try it. If I want to create different behaviors and have conditions for switching between them, would you contain the logic for switching between states within each scriptable object?

  • @NicDev
    @NicDev2 жыл бұрын

    Nice video! Thanks a lot for the tutorial, now my enemy becomes very flexible. But one problem tho, when I duplicate the enemy, all of the enemies suddently becomes very weird, but when I duplicate the behaviours, all of the enemy works fine. Is this becouse a behaviour act as all of the enemies brain? If so is there any way that I can make the enemy to have different brains without having to duplicate everything?

  • @noisemaker0129
    @noisemaker01292 жыл бұрын

    Awesome.

  • @Nitys
    @Nitys Жыл бұрын

    How do you make it that you want the enemy to go for an objective but if the player gets inside his range he go for the player and if the player ran (out of his range) he goes back to his objective? There is also when the enemy collides you can just push him back and it just does not chase you anymore.

  • @inkofthedragon
    @inkofthedragon Жыл бұрын

    Does this concept replace the need for a State Machine then?

  • @NotSoSeriousGaming
    @NotSoSeriousGaming2 жыл бұрын

    Once again another amazing video !?! I was just wondering if you have any videos on this... I have a pick up item (call it a perk) that give me a super jump automatically.... but I wanted it so u could scroll through different perks and then picking one to enable the super jump... if that makes sense.. kinda like a weapon list but for a perk lol

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    Hmm not directly, you could modify something from my Powerup vid but Ill add this to my video idea list

  • @NotSoSeriousGaming

    @NotSoSeriousGaming

    2 жыл бұрын

    @@BMoDev thank you so much ! Keep up the great work love your content !

  • @Stompin40
    @Stompin402 жыл бұрын

    BIG BRAIN!!!!!!!

  • @lazydude5681
    @lazydude5681 Жыл бұрын

    I don't like this system because of the assets duplication (base script + scriptable object per single behavior), but I use scriptable objects for stats management and let machine states or behavior nodes do the actual behavior, that's probably a way less cluttered method if you don't mind dealing with code to "register" each enemy behavior in a dictionary so they can be found by a name passed in a manager class

  • @deseanteneves8026

    @deseanteneves8026

    5 ай бұрын

    Would you mind explaining this to me? Im currently making an rpg and one thing im trying to figure out is how i wanna handle stats and other things ect.

  • @durrium
    @durrium2 жыл бұрын

    Nice video, however I really don't understand the difference with scriptable object vs regular scripts? It's just using an abstract class which we are inhereting from. This can be done using regular scripts. How is inhereting from scriptable objects different? (really trying to grasp it😂)

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    Id watch the talk i have linked in the description it shows the advantages with scriptable objects over monobehaviors. These things can definitely all be done with regular scripts but using scriptable objects gives you better modularity/testability in a lightweight serializable asset you can play around in in the unity editor. Because its an asset its not confined to being in a scene at runtime like monobehaviors

  • @durrium

    @durrium

    2 жыл бұрын

    @@BMoDev thanks for the answer, I'll check it out :)

  • @Balakademi
    @Balakademi2 жыл бұрын

    good video, thanks. But, lots of using FindgameObjectswithTag and GetComponent in every Update call

  • @AcIdBARRY

    @AcIdBARRY

    Жыл бұрын

    yeah was thinking the same, but thats something we can easily improve on luckily

  • @philipkaltsounis8097
    @philipkaltsounis80972 жыл бұрын

    Interesting approach and one I might give it a try, I have to say though you do a GetComponent and FindGameObjectWithTag on Update which are both very heavy. It would be best to pass the parameters on Start to the Scriptable Object on its own parameters.

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    You are 100% right. passing it in is good, storing target results in a dictionary for constant time lookup is another good option - the architecture is the focus and more important than the actual demo logic

  • @philipkaltsounis8097

    @philipkaltsounis8097

    2 жыл бұрын

    @@BMoDev yeah sure I know you were showing a demo and that part of the code was not important to Scriptable Objects. I feel, however, like it should be noted in case someone sees this it and tries to copy it

  • @Equisdeification

    @Equisdeification

    2 жыл бұрын

    You could do something similar to Unity Atoms (register the object with the tag and then have a static dictionary, so you can do something like this in your brain once AtomTags.OnInitialization(() => target = AtomTags.FindByTag(_tagToTarget.Value).transform);

  • @butterbombe
    @butterbombe2 жыл бұрын

    Speedrunning Scriptable Objects Any%

  • @synchaoz
    @synchaoz Жыл бұрын

    Neat concept, but calling GetComponent in Update makes my brain hurt (pun not intended). Don't do that if you care about performance.

  • @ChrisHolden
    @ChrisHolden2 жыл бұрын

    Running "find object by tag" inside "think" which is called every frame inside an Update function call? I don't see how this degree of abstraction is helpful (the example is too simple) and surely running gameobject.find on the update call of every enemy object is very wasteful? I just don't get it. I bailed at 7:30 once it became clear you were calling find so often - this could kill a game with lots of enemies?

  • @BMoDev

    @BMoDev

    2 жыл бұрын

    The abstraction becomes beneficial the more types of AI behaviors you have, the more behaviors you have the more you can tweak parameters that define those behaviors (e.g. you can use a slider in the inspector to determine the range before an enemy ai will chase the player, or the variance in accuracy when shooting at the player) these things can be done without modifying a single line of code, and can be plugged into different enemy types at will. In regards to the performance that's just a fault of me trying to keep the tutorial under 30 mins without fleshing out more of a system, and the intent was to showcase the architecture rather than the implementation. Calling GameObject.FindObjectByTag can actually be perfectly fine in update, given on the first call you store the results in, say, a dictionary giving you constant time lookup, and as long as you have a value that lookup will not be performed again. Alternatively, it could be completely unnecessary because you could actually pass in the target without needing to perform a lookup at all. All things I could have illustrated better and explained more - much of this will have to be setup for your specific game, so the deeper into an example I go the less general the information becomes

  • @AcIdBARRY
    @AcIdBARRY Жыл бұрын

    Great explanation, only thing you probably dont want to do is the FindGameObjectWithTag() in the update. for me i went around this issue: by creating another function in my "Brain" and "ChaseBrain" scripts. i called it InitializeThink. inside the "ChaseBrain" i use this function to search for the player tag and pass it to the target variable. in Brain: "public abstract void InitializeThink(EnemyBehaviour behaviour);" in ChaseBrain: " public override void InitializeThink(EnemyBehaviour behaviour) { chaseTarget = GameObject.FindGameObjectWithTag(chaseTargetTag); }" inside "Enemy Thinker" i simply put "brain.InititalizeThink(this)" into the start function. so basically my InitializeThink is my ChaseBrains Start function now wich is pretty handy. in Enemy Thinker: "brain.InitializeThink(this);" of course you can do other stuff there as well. but its sure better than calling things every frame if we dont need to. i hope this helps someone,

  • @user-ts3rv5hb7u

    @user-ts3rv5hb7u

    Жыл бұрын

    Where does it take enemy behaviour as an argument

  • @AcIdBARRY

    @AcIdBARRY

    Жыл бұрын

    @@user-ts3rv5hb7u it's been a while since i wrote this but I think it's in InitializeThink where you would give the enemy behavior as an argument I'm not a pro or anything but it worked for me