Тёмный

Enhance Your Game: EASY Enemy Logic Using Scriptable Objects (State Machine PART 2) | Unity Tutorial 

Sasquatch B Studios
Подписаться 45 тыс.
Просмотров 16 тыс.
50% 1

Опубликовано:

 

2 окт 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 54   
@NightRunStudio
@NightRunStudio Год назад
Love this! I totally would love to see more content like this. Keep it up!
@MarushiaDark316
@MarushiaDark316 11 месяцев назад
Very cool. Very modular. One thing to make this even tidier is, since you're using inheritance, you don't need to override any method whose only purpose is to call the base function. You only need to override things that would be different in child classes. In fact, you can probably get away with a root SO class that has all the base functions like Enter, Exit, Trigger, Update, etc. and override those in child SO classes as well since not every state will necessarily have all of them, but they could. Just saves on duplicate code.
@eduardscobioala9645
@eduardscobioala9645 Год назад
another extremely great and useful video, thanks
@scolate_
@scolate_ 10 месяцев назад
4:25 my bones broke. You are against the DRY principle
@Unity-wb9wv
@Unity-wb9wv Год назад
Hi, can you help me understand why this differs from creating instances of classes per behavior? What is the benefit of the SO in this instance (aside from tweaking at runtime), since we can make public fields on the enemy to drag/drop different idle/attack/chase classes with varied logic as well? I'm a bit unclear what having these as SO's gives us over monobehaviours? Thanks for the videos!😀
@sasquatchbgames
@sasquatchbgames Год назад
That's a great question. You could certain just make Monobehavior scripts and slap them on different prefab versions of enemies. But that doesn't give you the benefit of a state machine with the easier debugging and better performance. As for dragging and dropping different behaviors into public fields, you actually can't do that using monobehaviors. I tried that first. Let's say you create a class, called EnemyIdleBehaviorBase, which inherits from Monobehavior, and then you create 3 different idle behavior classes which inherit from EnemyIdleBehaviorBase...if you set a [SerializedField] private EnemyIdleBehaviorBase enemyIdleBehavior..you can't just drag and drop any of the 3 behaviors on there. Serialization via Inheritance doesn't work like that in Unity's inspector from a Monobehavior. But you CAN do that with ScriptableObjects. (There's likely a method to make this work using generics, but I like ScriptableObjects, and I'm not too comfortable with generics yet.)
@kpickett9128
@kpickett9128 Год назад
Agreed, I like the SO approach here purely bc it's immediately so easy to understand at a glance in the inspector lol The abstraction of "player has one central script where you can drag and drop add different abilities" is very intuitive compared to something like, "player has a bunch of scripts and one of them is the state machine and the others are abilities used by the state machine but they all look the same in the inspector at a glance unless you dig into the code". Maybe there is a simple drag and drop approach that can somehow be done using only monobehaviours that gets around the inheritance wrinkle, but don't know it either... as a noob this setup strikes me as a nice and intuitive way to get started that is easy to work with later in the pipeline as a designer as well!
@Unity-wb9wv
@Unity-wb9wv Год назад
@@sasquatchbgames Thank you!
@Lutojar1
@Lutojar1 Год назад
Thanks so much! I watched about 20 vids about FSM on youtube and this one was the most useful.
@yaboijagerlive7923
@yaboijagerlive7923 8 месяцев назад
Great video, this is actually how I'm currently implementing my own state machine. Although I have some doubts about instantiating the scriptable object states. I love how using scriptable object makes it easier to create new states but It just somehow feels hacky to me, anyone else feels the same?
@midniteoilsoftware
@midniteoilsoftware Год назад
Great stuff Brandon!
@aiden1010
@aiden1010 9 месяцев назад
You're a savior, this and the previous video were the only ones that have actually worked for me. Saved my school project, mad respect 😌
@rafarodriguez4765
@rafarodriguez4765 5 месяцев назад
I tested it in detail, and I have to say that it is not modular...Despite you use another class (Ghost) inheriting from the base Enemy, Enemy is hardcoded with the ScriptableObjects and Custom Classes that derive from EnemyState, so all kinds of Enemies (Ghotst, Dog,...whatever) having the same number of slots serialized despite only use one or four states, and you can not serialize the Scriptable Objects in the Ghost class as the EnemyState classes (Idle, Chase...) call to Enemy. Also, the Transitions between States are hardcoded into the Scriptable Objects ....Summarizing it is really hardcoded Maybe you should avoid using Custom Classes, instead Scriptable Objects to keep Actions and Transitions in a modular way, as it does the father of this kind of tutorial that is the Tank one from Unity
@davidvarga2916
@davidvarga2916 2 месяца назад
This would be so much easier if you could just drag and drop Mono Behaviours like SO's into Serialized fields.
@risingforce9648
@risingforce9648 2 месяца назад
I think , how to deal tiwht Animators class? sincronize the animator ? the coolddowns and the state machine?
@brandonmitchell-kiss2533
@brandonmitchell-kiss2533 6 месяцев назад
Shouldn't you make the reference to player static??
@JanTGTX
@JanTGTX 6 месяцев назад
I'm probably too late to the party to get a response, but maybe someone reads this... The tutorial is very good as it stands, although my head spins. XD Well, it works, and that's cool. I've been programming for 3 years, but all this advanced stuff is kind of overwhelming. I'll probably figure it out over time, but for now, it still feels a bit like a black box. My question is: What's up with this AnimationTriggerEvent stuff that is set up here? I understand what those are, but as it is right now, you're just assigning enums and don't perform any method, no? How or where would I implement the actual logic for those AnimationTriggerEvents? Like for example, playing a sound when a foot hits the ground in the animation. My monkey ass brain would probably set this up in the Enemy script, but that can't be right, as different enemies will have different footstep sounds... well, I dunno...
@JanTGTX
@JanTGTX 6 месяцев назад
Welp, it didn’t take me too long to intuitively figure stuff out. :D For anyone wondering, I've found what worked for animation trigger events using this method. You just create an "event" in the enum and then write it as a condition into either an SOBase or a child SO, depending on where its use is relevant, within the "DoAnimationTriggerEventLogic". Then pass the enum in as a trigger event at the desired frame in the animation and voila. I don't know if this is the intended approach, but it works. And it's state bound as well, which is kind of insane for me. This tutorial has probably been the most helpful I've seen on Unity programming yet. I didn't immediately understand all of it, but it's a hell of a game changer for noobs like me. I was quite stoked to implement this into my game code and it somehow is a hell of a lot of fun to work with. Something must be wrong with me. 😂
@Xiimo_
@Xiimo_ Год назад
i have a little question. at the 8:16 . I get that the timer for the shots should be handled inside the update logic but wouldnt it cause problems to handle de rigidbody velocity of a bullet outside the fixedUpdate logic?
@WeaselOnaStick
@WeaselOnaStick Год назад
Not really, unless the enemy is hugging and shooting the wall, then for one frame there could be some bugs. But in this case we're not affecting any physics over several frames, only once to give the bullet its initial velocity (with any later bullet moving handled by unity's physics engine)
@midniteoilsoftware
@midniteoilsoftware Год назад
By initializing the Player in the Enemy state using FindObjectWithTag() in the Initialize() method, what happens if the player is killed (i.e. destroyed and respawned)? Wouldn't any enemies on the board lose their reference to the player?
@Diablokiller999
@Diablokiller999 Год назад
Only if you destroy the player object, you can just kill the player off and not delete its instance, rather just resetting it for a new scene load.
@Diablokiller999
@Diablokiller999 Год назад
Nice, easy, not too complicated. I'm using state machines with substates, a bit more advanced but gives you more fine tune between states.
@sdflogan2010
@sdflogan2010 3 месяца назад
Hi! Absolutely I LOVE IT. This is just what I was looking for. Just one quick question: You mentioned that each state will generate it own instance loading it on memory. Can we have a problem on mobile games using this solution with a lot of spawned enemies at the same time or the memory consumed is very low?
@12bhan
@12bhan 4 месяца назад
I'm stuggling to understand which script to put various logic in (in general, not the specific tutorial). Especially between the idle script derived from the EnemyState class and the one that is derived from the scriptableobject EnemyIdleSOBase class. Feels like it needs to go in the script that I derive from the scriptableobject class. The various states derived from EnemyClass appear to serve as intermediaries there to run the methods of the scriptableobjects. Great videos!
@muriilouwu
@muriilouwu Месяц назад
great tutorial, thanks!
@roygatz
@roygatz Год назад
Is using task and subscription an more simplified way to achieve similar results? What would be the down side if true?
@shockingchris9809
@shockingchris9809 10 месяцев назад
I've already commented on the first video, and this is no different, AMAZING structure and I love the compartmentalization of scripts. I'm noticing that in the TriggerChecks you are setting the Aggro property when entering and exiting. You have logic to go from Idle to Chase and chase to Idle, but I don't see the change from Attack back to Chase or Chase back to Idle. It... kind of looks like your enemies in your preview are changing from attack to chase and chase to idle, but maybe I just missed that. I assume that it is as simple as adding an if on the AttackSOBase like so: public virtual void DoFrameUpdateLogic() { if (!enemy.IsWithinStrikingDistance) { enemy.StateMachine.ChangeState(enemy.ChaseState); } } and an else if on the ChaseSOBase that checks if the IsAggroed is false (exits the trigger collider area) to change to the Idle state again. But I also think that this seems too simple. Thank you again!! Incredible video!
@shockingchris9809
@shockingchris9809 10 месяцев назад
Nope. I know the solve 😅 I just needed to do some adjusting of the distance to leave (Which I haven't switch out yet), noticing that it was just 3 times bigger than the trigger range. It just has to be set to something understandable as a leaving distance.
@Coco-gg5vp
@Coco-gg5vp Год назад
First
@sebastianhall8150
@sebastianhall8150 Год назад
First
@ItsDan123
@ItsDan123 Год назад
What would you do for an enemy that should keep chasing while in attack range? Duplicating the movement behavior in two states feels wrong, you could have a combo state that is checking range which feels better but also feels like it's reintroduction the "if block" mess that the state machine should reduce.
@shauas4224
@shauas4224 10 месяцев назад
bit late of a reply but the way I see it you have two options: 1) let's suppose your enemy has a cooldown after attack. And you could change state to chase right after attack and add check for cooldown in your if block which changes to attack state. Meh, little bit messy and adds dependencies between states but not the worst option. 2) you could use NFSM - non final state machine which is basically SM that can be in multiple states at the same time. More complex, more complicated but more flexible. 3) and the third option is to use a Behaviour tree which is more upgraded and fancier kind of nfsm.
@connorious455
@connorious455 Год назад
Hey the video is great and very helpful but how would I go about adding more than one attack on a single enemy? Would I just have to put more than one attack on the scriptable object script and set conditions to change between them or would it be better to add another state?
@sasquatchbgames
@sasquatchbgames Год назад
If its just 1 more attack, updating what's already there seems fine. Though if it's more than that I'd suggest adding a new state. Whichever is more readable and manageable for you
@connorious455
@connorious455 Год назад
@@sasquatchbgames okay I will try to do that thank you
@lsysun1
@lsysun1 Год назад
"Thank you for the videos, they have been very helpful. However, I have some questions. For instance, I would like different enemies to have different movement speeds. Should I set the movement speed in each Enemy.cs script and then assign it during EnemyIdleSOBaseInstance.Initialize(gameObject, this)? Or is there a better approach?
@grumpycrouton2279
@grumpycrouton2279 4 месяца назад
With this method you could write a base IdleSO just like it was shown here, then create a separate SO asset for each enemy, which can then all have their own speeds.
@WeaselOnaStick
@WeaselOnaStick Год назад
This is the final boss of boilerplate, oof. Are you certain we need this mane script files for every single entity behaviour? I feel like you could get away with much less code
@puntalic
@puntalic 5 месяцев назад
Its not about the amount of code, its about maintainability. Technicaly you could have something like Helldivers 2 in just 1 script. Debugging and modifying would an undoable feet. You often hear: less is more... here more is less (headaches)
@chadmoberly7044
@chadmoberly7044 Год назад
Congrats on 5K subs!
@sasquatchbgames
@sasquatchbgames Год назад
thanks!!!
@JUNA-ANUJ_YADAV
@JUNA-ANUJ_YADAV Год назад
@SasquatchBStudios Pls make proper video on version controlling ,Save our project after every new addition with the use of source tree and git hub etc
@sasquatchbgames
@sasquatchbgames Год назад
Seeing as how i literally just learned how to do that today (with github), I might just. Thanks for the idea!
@MZ-sr2xr
@MZ-sr2xr 5 месяцев назад
thank👏you👏so👏much👏
@Notreal76
@Notreal76 Год назад
Very nice system :)
@tivasthegamer9817
@tivasthegamer9817 Год назад
Awesome!
@wuushan5961
@wuushan5961 Год назад
🎉
@Arcann_bhp
@Arcann_bhp Год назад
WHERE TF IS PART ONE
@beshkekart3909
@beshkekart3909 4 месяца назад
Yep, bro you find that?
@beshkekart3909
@beshkekart3909 4 месяца назад
A Better Way to Code Your Characters in Unity | Finite State Machine | Tutorial
@fireraccoon_
@fireraccoon_ Год назад
I love your videos and comments. I also love enemy moving everywhere. Is there a possibility that you will paste here Idle/Patrol move on Horizontal or vertical ways? i tryed this but when i implelemt it i cannot assign any "object" becasue i get message "object missmatch" [SerializeField] public float moveSpeed = 1f; [SerializeField] public float startWaitTime; private float waitTime; //public Transform[] moveSpots; //Schemat patrolu public Transform moveSpot; //private int randomSpot; //Schemat patrolu public float minX; public float maxX; public float minY; public float maxY; private void Start() { waitTime = startWaitTime; //randomSpot = Random.Range(0, moveSpots.Length); //Schemat patrolu moveSpot.position = new Vector2(Random.Range(minX, maxX), Random.Range(minY, maxY)); } private void Update() { //transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, moveSpeed * Time.deltaTime); //Schemat patrolu transform.position = Vector2.MoveTowards(transform.position, moveSpot.position, moveSpeed * Time.deltaTime); //if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2f) //Schemat patrolu if (Vector2.Distance(transform.position, moveSpot.position) < 0.2f) { if (waitTime < 0) { moveSpot.position = new Vector2(Random.Range(minX, maxX), Random.Range(minY, maxY)); //randomSpot = Random.Range(0, moveSpots.Length); //Schemat patrolu waitTime = startWaitTime; } else { waitTime -= Time.deltaTime; } } }
@fireraccoon_
@fireraccoon_ Год назад
Ok I did it!!!:) i changed private Transform moveSpot to [SerializeField] public and put prefab object. Worked!!!:)
Далее
Сколько стоит ПП?
00:57
Просмотров 127 тыс.
HA-HA-HA-HA 👫 #countryhumans
00:15
Просмотров 991 тыс.
Провал со стеклянным хлебом…
00:41
Be CAREFUL with Scriptable Objects!
8:27
Просмотров 81 тыс.
Creating SMART enemies from scratch! | Devlog
5:40
Просмотров 332 тыс.
The Power of Scriptable Objects as Middle-Men
17:41
Просмотров 126 тыс.
20 Advanced Coding Tips For Big Unity Projects
22:23
Просмотров 187 тыс.
Unity 2021 Use Scriptable Object instead of Enum
10:57
Optimizing my Game so it Runs on a Potato
19:02
Просмотров 600 тыс.
Сколько стоит ПП?
00:57
Просмотров 127 тыс.