Tips on storing general enemy AI inside of a ModuleScript?

Hello there!

Thanks to @Harisaiyo for a code review for an enemy AI, he suggested that I should consider using a structured ai loop which I’d assume is just a ModuleScript containing “General” AI of every enemy within a game. If you’re wondering what I mean by “general”, I’ll try to explain it as best as possible.

I’m planning on making the ModuleScript (Structured ai looping or whatever you call it) contain the “general” AI of two enemies inside of my game, Slimes and Walkers. (Those are just example names fyi.) Both Slimes and Walkers will share “general” AI which is essentially just AI that makes both Slimes and Walkers somewhat act similar to each other.

An example of such is pathfinding, they both find and chases the nearest player or ally NPC and harm them when near with the only difference being Slimes will hop towards target while Walkers, as their name suggests, simply just walk towards their target.

Although I’ve rarely used ModuleScripts and new to this whole structured ai looping thing. Of course, if you have tips or anything else I should use, feel free to tell me.

1 Like



1 Like

To followup you need to use OOP (object oriented programming). LUAU doenst really use OOP (it uses metatables) but you can pseudo fake OOP like OP did in the regular post when they created BaseEntity. BaseEntity is the general class to extend from. They made SadHog and MadHog from BaseEntity. In your case youd make a Base module then 2 more modules for Slime and Walkers.

So something like this:

 > BaseMob.lua
 > SlimeMob.lua
 > WalkerMob.lua

Then youd have your models which have a server scripts to animate. For this example say your workspace has a mob folder that you place mobs in and you currently have 2 slimes and 1 walker.

> mobs
  > Slime (this is a model)
      > Humanoid
      > Animate (server script which contains the state machine or queued state machine logic) 
  > Slime
  > Walker

You can use ClientScripts to aniamte instead of server scripts but the animation will not replicate and itll be up to you to coordinate that. Its more complex and its an optimization thing. TowerDefense games in roblox are popular with ClientScript animation). For simplicity use ServerScripts to animate using humanoid.Animator:loadAnimations(). Make sure to use animator otherwise replication across all clients is not guaranteed! This is a separate topic and will go off in a tangent so lets just focus on th AI stuff.

Idk how much experience you have with programming but Modules allow you to define the function and access them almost like a singleton.

For more info on the “AI loop” the actual term you want to search are “state machine”. The one I explained to OP in the thread you referenced is a step higher called a “Queued State Machine (QSM)” typically used for async tasks of the AI. I use QSM in my games because of the high action per minute. If youre building a tower defense, simulator or something with slow combat then you dont need QSM. As a beginner Id stick with State Machines for now.

Alright then! So, in simpler terms, I should:

  1. Create a base module script which serves as a general class to extend from (I’d assume it also has functions like create new enemies and such.)
  2. Inside of said base module (or place it right next to the base module in general), create module scripts for both Slime and Walkers. Those module scripts will probably contain the AI of the enemies as well as animating them.
  3. Create the models of the enemies and add a humanoid and Animate script inside of the enemies.

Now, according to you, I can either animate the enemies either on the client or server side. Although since my game is going to be I guess somewhat of a roguelike, I might need to animate in the client side, right?
Anyway, I’d notice you use a “Queued State Machine (QSM)”. What’s that exactly?


And to be clear when I say clientside animation that just means your server logic still contains animation logic but instead of humanoid.Animator:PlayAnimation() on the server script you would send an event to all clients. The Clients would have a LocalScript which would listen on that event and play the animation. For many mobs this is ideal so as long as you dont have physics based combat.

Anyway, I’d notice you use a “Queued State Machine (QSM)”. What’s that exactly?

Read the original post you linked. QSM is a State Machine with a Queue.

So basically, instead of having the default Roblox animator, I create an entirely new one and then use a remote event to play the enemy animations on every client?

Yes by using your own custom animator. Actually if you look at the default Animate.lua script its a state machine thats because humanoid has states and it listens to events like when damaged and death.

But tbh its quite messy.

Alright then. Thanks for the helpful information!

Youre very welcome and no problem! Good luck!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.