Hey guys! I'm trying to make ai for all monsters in my game. I code the first stage. They are spawning in certain area and they are individually and randomly moving in that area. There is no problem with idle mode. The problem is when someone attack them they should stop what they are doing and attack the player. When they are idle they are waiting random amount of time. I want the cancel that wait or idle movement when they are under attack and if the attacker runs away they should back idle mode. I don't have enought experience with lua and i can't build the logic. What should i use to make it work ? Is there any topic should i research ? Thanks!
This spawn script is child of region part :
--Define Storage service local storage = game:GetService("ReplicatedStorage") --Which mob should spawn? local mob = "Zombie" --Count of mobs local mobCount = 7 --Randomly pick between these times. It will wait idle xx seconds. local idleTime = {10,15} --Coordinates for free walking region local topLeft = Vector3.new((script.Parent.Position.X + (script.Parent.Size.X/2)),0,(script.Parent.Position.Z + (script.Parent.Size.Z/2))) local bottomRight = Vector3.new((script.Parent.Position.X - (script.Parent.Size.X/2)),0,(script.Parent.Position.Z - (script.Parent.Size.Z/2))) --Spawn all mobs local randCoordinate = Random.new() for i=1, mobCount do local randomX = randCoordinate:NextInteger(topLeft.X,bottomRight.X) local randomZ = randCoordinate:NextInteger(topLeft.Z,bottomRight.Z) local spawned = storage[mob]:clone() spawned.safeRegionX.Value = tostring(topLeft.X)..":".. tostring(bottomRight.X) spawned.safeRegionZ.Value = tostring(topLeft.Z)..":".. tostring(bottomRight.Z) spawned.minIdle.Value = idleTime[1] spawned.maxIdle.Value = idleTime[2] spawned.HumanoidRootPart.Position = Vector3.new(randomX,3,randomZ) spawned.Parent = workspace.Mobs end
And this script is child of zombie. Each zombie have it's unique script.
--Bool variable for check if there is any attacker local attacker = false --Random for idle wait time local randIdle = Random.new() --Fixed height for certain mob local height = script.Parent.HumanoidRootPart.Position.Y --Safe region for walk local firstX = string.split(script.Parent.safeRegionX.Value,":")[1] local secondX = string.split(script.Parent.safeRegionX.Value,":")[2] local firstZ = string.split(script.Parent.safeRegionZ.Value,":")[1] local secondZ = string.split(script.Parent.safeRegionZ.Value,":")[2] while script.Parent.Humanoid.Health > 0 do if attacker then print("there is attacker") else print("No attacker!") local moveX = randIdle:NextNumber(firstX,secondX) local moveZ = randIdle:NextNumber(firstZ,secondZ) script.Parent.Humanoid:MoveTo(Vector3.new(moveX,height,moveZ)) print("Moving to : " .. tostring(moveX) .. ", " .. tostring(height) .. ", " .. tostring(moveZ)) wait(randIdle:NextInteger(script.Parent.minIdle.Value,script.Parent.maxIdle.Value)) end end
You should check the wiki for your questions before asking here, this is an extremely broad question and there are many ways to program AI.
However, I would recommend the wiki. If you want it done now without learning a lot of lua then you will have to hire someone to do it for you, or hire someone to teach you how to do it. You should also show your code so that we know what you're working with, or at least portions of it.
Maybe try making a BoolValue
in the enemy with a function binned to the Changed
signal that would make the enemy stop moving or stop idling for as long as it's true.
Or if you are using modules instead of scripts you can make a function in that module (and the server will execute it) that would do the same thing but without a BoolValue
.
Also you will have to remove that long wait
in the idle state, when you think about it, it does way more harm than good. Just don't forget a wait()
in the while loop, don't make it long though.
I think a final product will look something like this:
idleDelay = 2 -- how long the enemy will have to wait to get back to the idle state delayStart = nil -- this will be a tick to measure how long it has been since the enemy got out of the idle state bv = script.Parent.BoolValue -- this should be changed to true when enemy is attacked bv.Changed:Connect(function() if not delayStart then -- then the enemy is in idle state but it shouldn't be now because it has been attacked delayStart = tick() -- don't forget to stop moving animations, movement etc here to show that they are still and attacking else -- this means that the enemy got attacked while not in the idle state delayStart = tick() -- we need to restart it to make sure the delay is up to date -- you don't need much else here because the enemy is already attacking end end) while wait() do if delayStart then -- if they are not in idle state but we want to know if they should local shouldBeIdle = tick() - delayStart >= idleDelay -- if the time since the enemy has been attacked is more than idleDelay then it should be idle, makes sense? if shouldBeIdle then print("the enemy now should be idle and so it will be") delayStart = nil -- make all that idle state things here end end end