ID:1085416
 
Keywords: snake, wiggly, worm
Alright folks, here's my current conundrum. I'm trying to make a snake or worm-like enemy in my game. The snake is actually just a bunch of mobs that follow each other - if a middle piece is destroyed, the part left behind will sprout a new "head." (I'm sure everyone has experienced this type of enemy in their video gaming careers :D)

In my first attempt, I simply created the segments of the snake and ordered each one to walk_towards the one in front of it. This kinda worked, but the segments didn't follow the original path of the head. If they were arranged vertically, and the head stepped southeast, they would all step southeast.

So I am trying to devise a way to do it manually, and I'm having a little trouble. Here's the system I have right now:

    snake

Move()
if(text == "<FONT COLOR=#0A0>@</FONT>" && back)
var/oldloc = loc
var/oldloc2
..()
if(oldloc != loc)
oldloc2 = back.loc
walk_towards(back,oldloc,0)
var/check = 0
var/swix = 0
var/mob/newback
if(back.back)
newback = back.back
check = 1
while(check)

check = 0
if(swix)
oldloc2 = newback.loc
newback.loc = oldloc
else
oldloc = newback.loc
newback.loc = oldloc2

if(newback.back)
check = 1
newback = newback.back
swix = ~ swix


And it's bad, man. Real bad. In case you didn't guess, "back" is a variable that stores the next segment in the snake. So why is it bad?

1. It's laggy. When the heads run into obstacles they start using pathfinding, and it seems to lag out when multiple snakes get tangled up with each other and the map.

2. It's buggy. I think I got one of the snakes to move all segments to the same space as the head mob.

3. It's crappy. I just feel terrible about this code, I want it to be sleek and sexy but instead it is fat and sassy.

I was toying with the idea of somehow keeping track of the moves done by the head mob, and using that in conjunction with each segment's position in the snake, to step() them all in the right direction. But I haven't really thought that one out yet...maybe you think it's a good idea? Or should I take a different approach altogether?
I think making each segment move to the previous loc of the one in front of it would work, with the first segment following the head.

The head moves and the segment tracking it moves to its previous location. The segment tracking the first one moves to the 1st ones previous location, and so on. You'll need to keep track of the previous step_x and step_y and adjust this as well, if using pixel movement.

Though all of this may just sound better in my head.
Heh...well that is exactly what my code does :P The concept is sound but the way I did it isn't great

BTW, this is in text-mode so no pixel movement
I believe this is self-explanatory.
snake
var/snake/tail
Move()
var/turf/old_loc = loc
.=..()
if(tail && old_loc!=loc)
tail.Move(old_loc)
Oh yeah, I should have mentioned that I tried that too. It worked great except that you could actually see each segment catch up with the next one. Did you test that code with perfect results? If so maybe there is another issue....
In response to Magicsofa
That all depends on the Move() proc, the way he has it set up, it'll move the snake then move the tail, so if the movement isn't quick, it'll appear to play 'catch-up'. You'd have to make something different for a instant response, probably calling spawn() when you move the snake and moving the tail in the same manner the snake is moving.

snake
var/snake/tail
Move()
spawn() tail.Move(args)
.=..()

Something like that, don't think my example will work though, good luck with it all.
In response to Magicsofa
I didn't test it though, theoretically, it should not produce any problem. You are using text mode so you should see the movement instantaneously. You should not see gaps unless you called tail.Move before src.Move's default action ( ..() ). Doing so will make tail.Move fail since the "head" is still in the turf you are trying to move your tail to.
Well, I did it exactly as you wrote it. I'll have to test it in a blank environment or whatever to make sure something else in my code isn't interfering. I definitely didn't override Move anywhere else though...
I tested the following code. It works flawlessly.
snake
var/snake/tail
Move()
var/turf/old_loc = loc
.=..()
if(tail && old_loc!=loc)
tail.Move(old_loc)

world
maxx = 20
maxy = 20

snake
parent_type = /mob
text = "\green S"

client
New()
var/snake/snake = new(locate(1,1,1))
mob = snake
mob.text = "\green O"
for(var/i in 1 to 10)
snake.tail = new
snake = snake.tail
return mob
hmmm...well I tried this out and it did seem to work better than my original attmept (I think I used walk_towards instead and that might be why it was stuttery?)

It is still too laggy however. One snake is fine but when you have three of them thats 30 mobs doing this processing, not to mention other mobs that may be present.

I have decided to remove them for now, I may rework them as a special boss battle type of thing. Anyway, thanks for the help :)
In response to Magicsofa
You could combine and re-size the icon and adjust the bounds to fit the snake better and just have it as one piece.
He's doing something like this but in ascii.

In response to Magicsofa
It could be your ai. Are you sure you are calling the ai proc just for the head?
Yup, I made sure of that. There are other issues however that I have to take care of. For example, I completely forgot that I wrote a check into turf/Entered() to see if a mob stepped into a projectile. After I clean this stuff up I might try again with the snake...