ID:160204
 
Hey, currently my game is going great, but I have tons and tons of monsters that spawn and begin walking towards the user, using many checks for each movement. When I have these 100+ enemies spawning, is there any way to reduce the lag?

None of the monsters ever go out of site, it's just a small map and you have all these hundreds of monsters attacking you.


Thanks!

--Beatmewithastick
Make the AI more efficient. Remove useless looping, extra variables, etc. For example, you can recycle variables.

mob/verb/Recycling_example()
var/mob/M = locate(/mob/Monkey_Hunter)
var/X = M.name //store the monkey hunters name
M = locate(/mob/Monkey) //reuse M
M << "[X] is hunting you!"


It should, in theory, use less RAM. Well, my example probably doesn't because I made that extra var, but you get the point. Also delete useless resources that aren't being used (empty lists).
In response to Jeff8500
Reusing vars excessively on purpose is rather pointless.
The effect is very very minimal - if not actually counterproductive. And local vars are also highly temporary. Rather, yes, you should cut down on the actual resources instead of number of vars.
In response to Kaioken
I'll try and let you know what happens.

EDIT: I tried to fix it, but my AI system bases a lot on movement checks too. I'm still getting a lot of lag.

Here's my previous AI code:
mob
var
mob/target
delaytime=3 //minimum
proc
ai()
for()
sleep(src.delaytime)
var/templist[]=new
for(var/mob/m in world)
sleep()
if(m.client&&m.playing) //change if auto turrets should be specifically targetted.
templist+=m
var/playersfound
for(var/a in templist)
playersfound=1
if(!playersfound) //no targets found.
return
src.target=pick(templist)
var/mob/n=src.target
while(src.target&&src.target.playing)
sleep(src.delaytime)
if(get_dist(src.target,src)<2)
step_towards(src,src.target)
continue
else
for(var/mob/a in view(2))
if(a.playing)
src.target=a
step_to(src,src.target)
src.target=n

Here's my updated AI code:
mob
var
mob/target
delaytime=3 //minimum
proc
ai()
for()
sleep(src.delaytime)
var/templist[]=new
var/truelist //makes sure there's something in the list.
for(var/mob/m in world)
if(m.client&&m.playing) //change if auto turrets should be specifically targetted.
templist+=m
truelist=1
if(!truelist)
return
src.target=pick(templist)
while(src.target&&src.target.playing)
sleep(src.delaytime)
if(get_dist(src.target,src)<2) //so they still bump targets using step_to as their\
basic movement function.

step_towards(src,src.target)
continue
for(var/mob/a in view(2)) //if a player get's too close, they switch targets.
if(a.playing)
src.target=a
step_to(src,src.target)


not much to be changed, it my opinion.

Here's my base movement code:
mob
var
canmove=1
monstermove //Whenever a monster moves, it checks for different things.
save_loc_x
save_loc_y
save_loc_z
oldloc
firstmove//being placed on the map should be automatic.
Move()
if(!src.canmove)
return
save_loc_x=src.x
save_loc_y=src.y
save_loc_z=src.z
oldloc=src.loc
..()
if(monstermove)
for(var/atom/a in src.loc)
if(a==src||a.name==src.name) continue
src.trigger(a)
else
for(var/atom/a in src.loc)
if(a==src||a.name==src.name||!src.playing&&src.client) continue //can't trigger yourself.
a.trigger(src)
for(var/atom/a in src.loc)
if(a==src) continue
if(a.name==src.name)
step(src,pick(EAST,WEST,NORTH,SOUTH))
sleep(10)
for(var/obj/hitpoints/o in world)
if(o.owner==src)
o.loc=src.loc



So is there anything there that really significantly causes lag when you have hundreds of them rushing at you at once? :S

Thanks.

--Beatmewithastick
In response to Beatmewithastick
There is definitely room for optimization and fixes to make.
In response to Kaioken
Do you think it would significantly reduce the lag with hundreds of monsters?

I want to make sure it's easily possible.

--Beatmewithastick


EDIT: I'm working on a system where all ai run off a single infinite loop, instead of each monster having their own infinite loop.

EDIT: Well, I did it, but it still lags like hell. :s

var/mob/ai_handle/ai_handler
mob
ai_handle
var/list/monsters
New(mob/ai)
ai_handler=src //quick reference.
for()
sleep(1)
for(var/mob/a in world)
if(!a.client&&!a.playing)
spawn a.target_attack()


mob
var/speedstop
proc
target_attack()
if(speedstop)
return
speedstop=1
sleep(delaytime)
if(!target||!target.playing)
var/templist[]=new
var/temp_list_is_true
for(var/mob/m in world)
if(m.client&&m.playing)
templist+=m
temp_list_is_true=1
if(!temp_list_is_true)
return
target=pick(templist)
for(var/mob/m in view(3))
if(m.playing)
target=m
if(get_dist(target,src)<2)
step_towards(src,target)
else
step_to(src,src.target)
speedstop=0
In response to Beatmewithastick
I'm having similar problems.
In response to Beatmewithastick
Okay, I just reduced the code to basically nothing, just as a test and it still lags (CPU lag) like hell. :S

var/mob/ai_handle/ai_handler
mob
ai_handle
var/list/monsters
New(mob/ai)
ai_handler=src //quick reference.
for()
sleep(1)
for(var/mob/a in world)
if(!a.client&&!a.playing)
spawn a.target_attack()


mob
var/speedstop
proc
target_attack()
sleep(5)
if(speedstop)
return
speedstop=1
for(var/mob/m in world)
if(m.client)
src.target=m
step_to(src,src.target)
speedstop=0
In response to Beatmewithastick
I just did a little test, I'm beginning to think it has something to do with step_to.

mob
density=0
verb
add_units()
for(var/i=1,i<100,i++)
new/mob/soldier(src)
soldier
icon='dot.dmi'
icon_state="blue"
New(mob/m)
..()
world<<"soldie creat"
src.loc=locate(1,1,1)
spawn ai(m)
proc
ai(mob/m)
for()
for()
sleep(1)
step_to(src,m) //lags like hell


mob
density=0
verb
add_units()
for(var/i=1,i<100,i++)
new/mob/soldier()
soldier
icon='dot.dmi'
icon_state="blue"
New()
..()
world<<"soldie creat"
src.loc=locate(1,1,1)
spawn ai()
proc
ai()
for()
for()
sleep(1)
step_rand(src) //no lag! even at 300 soldiers!


EDIT: okay, so I just confirmed it. Is there anything as simplistic as step_to that functions the same way that I can use in place of step_to? I still need the monsters to create paths. Without the lag.
In response to Beatmewithastick
I may have missed something, but why do you have for() twice?
for()
for()

I'm sure you don't need this.
In response to Kaiochao
Erm.. It's an infinite loop.

EDIT: Oh, well I could have done it with a single for(), but I just copied/paste my original code to demonstrate with had two for's because the second one was checking for(mob/m in world).Just ignore that.
In response to Beatmewithastick
Beatmewithastick wrote:

EDIT: okay, so I just confirmed it. Is there anything as simplistic as step_to that functions the same way that I can use in place of step_to?

This so called "AI" is nothing but a costly implementation of the already existing walk_to proc. Instead of calling step_to(src,m) every tick, simply call walk_to(src,m,1,1) once and your problem will be solved.
In response to CIB
There's a lot of problems with this though: It needs to keep checking to make sure the target exists, and if the target get's too close it needs to started step_towards in order to Bump() the target.
In response to Beatmewithastick
If you use 0 for the distance argument in a proc like walk_to(), it WILL try to get on the same tile as the destination mob and will bump into it (multiple times at that, unless you stop the walk() after the first one, etc).
In response to Kaioken
What happens though if the target is lost?

I wish there was just a non-laggy step_to available. :s It gives a lot more freedom.
In response to Beatmewithastick
step_towards() probably use less CPU. It's quite stupid in comparison to step_to(), though.
In response to Jeff8500
Exactly, I need the monsters to find their way around obstacles.
In response to Beatmewithastick
A* For Beginners. A great article and uses tiles to explain it so the implementation is really straight-forward.

George Gough
In response to KodeNerd
... That's quite out of place here, though.
In response to Beatmewithastick
Beatmewithastick wrote:
What happens though if the target is lost?

I wish there was just a non-laggy step_to available. :s It gives a lot more freedom.

...

mob
var
mob/target = null
proc/assign_target()
var/list/L = new
for(var/mob/M in world) if(M.z == z) // no use trying to get to stuff on other Z levels
L+=M
target = pick(L)
proc/check_target()
spawn while(1)
sleep(1)
if(!target || target.z!=z)
assign_target()
walk_to(target)


All do-able with walk-to. There indeed are more complicated situations where you will require more control, in this case I would recommend Deadron's pathlib, but you should first learn how to use the simple things.
Page: 1 2