ID:1893609
 
(See the best response by Maximus_Alex2003.)
So im rewriting my pet AI. So far it does what i set out to do. However when i change direction i would like it to smoothly walk to a position directly behind the player. Any nice ways of doing that? right now it just changes it location to be behind the player

Generally you just look at the pet owner and figure out where "behind" him/her is.

Then you have your pet walk to that location.

This might get you started. Although it should be edited to suite your needs.

mob
pet
icon='Mob.dmi'
var/mob/target
var/tx
var/ty
var/tz
New()
..()
spawn(10)target=locate(/mob/player)
spawn(20)AI()
proc
AI()
set background=1
loop
tx=target.x
ty=target.y
tz=target.z
if(src.z!=tz)
src.z=tz
src.x=tx
src.y=ty
switch(target.dir)
if(EAST)
tx-=1
if(NORTH)
ty-=1
if(WEST)
tx+=1
if(SOUTH)
ty+=1
step_to(src,locate(tx,ty,tz))
sleep(1)
goto loop
In response to IchiroKeisuke
Best response
Although you're intentions are true, this is a terrible way to go about this.

First off, you should be reducing the amount of variables from 3 (tx, ty, tz) to one associated list variable instead. Like
last_location["x"] = target.x
last_location["y"] = target.y
last_location["z"] = target.z


Secondly, you should be "summoning" pets via Move(), and not directly setting their x, y, and z unless Move() fails (but if Move() fails, you should be checking why, whether the location they plan to teleport to is already occupied, or it's a dense location that pets shouldn't be on anyways (roofs, boulders, etc).)

Thirdly, you shouldn't need an infinite loop to move your pet. Change the pet location via the player's movement procedure, not a loop (regardless of whether you've set it to a background process or not). This will reduce the amount of calls and overhead since you only need to move the pet when the player moves, you don't need to check locations every tick.

Fourthly, this won't work like you plan on it working:
spawn(10)target=locate(/mob/player)

I can photobomb your pet and steal it if I was playing. This will make the pet's target variable reference to the first /mob/player type it finds. That means there's going to be the chance someone can jump right in when the pet is summoned via New() and steal it.

Finally, don't use goto loops. Use while() and for() loops. They're much more pleasing and code-efficient.
In response to Maximus_Alex2003
should be edited to suite your needs.

Please don't tell me how to write my own code. This is a simple setup that can be improved, and that's all I intend to provide. No one learns how to stand on their own two feet if your holding them up all the time.
Maybe it was because I wasn't using step_to my idea was similair except I didn't use a loop. What I did was when my character moves I also check for a pet. If it has a pet I make the pet move with the player.

Though maybe step_to will make it looks nicer than what I was doing never used it I don't think.

Anyway thank you I'll try it out after work
In response to IchiroKeisuke
IchiroKeisuke wrote:
should be edited to suite your needs.

Please don't tell me how to write my own code. This is a simple setup that can be improved, and that's all I intend to provide. No one learns how to stand on their own two feet if your holding them up all the time.

To be fair, "should be edited to suite your needs." and reworked entirely are different things.

On that note, the person is more likely to learn if you explain how to do whatever they're asking for, much like Maximus did. Your approach was to give copy/paste code that was "intentionally" poorly made for the sake of "learning". Sabotage and learning don't really go hand-in-hand.
In response to Lige
Accusing me of sabotage doesn't help anything or anyone, but go ahead if it makes you feel better.

but to clarify, its a rather simple concept.

1)You identify where you want the pet to be at.
                    tx=target.x
ty=target.y
tz=target.z
switch(target.dir)
if(EAST)
tx-=1
if(NORTH)
ty-=1
if(WEST)
tx+=1
if(SOUTH)
ty+=1

2)You have your pet walk to that location.
step_to(src,locate(tx,ty,tz))

3)rinse and repeat when necessary.

All in all, there are tons of different ways to solve problems in code. Those snippets could be rewritten in many different ways, and I'm going to leave that part up to Dante to experiment with. Got a better snippet of code? fine, just don't talk to me about how great it is or how terrible my suggestion is.
Wouldn't that put the pet over the player? I want it behind which I have.

My main problem is when changing directions let's say from North to west. The pet will just teleport 2 tiles over to do that. Which looks unclean. My main question was how do I make pets have a smooth transition when walking all directions. Not just have them teleport behind you
In response to DanteVFenris
Would you mind posting what you have tried so far?
In response to DanteVFenris
You'll want to use Enter() in this case.
Grab the old-location, and have the pet walk_to() or step_to() or whatever your movement method is. Modify the turf's Enter() to grab the atom/oldloc param and send that to the pet as the target location to walk to.

Or save the player's last-location and have the pet reference that.

//corrected
You can get the tile behind a player at any instant with: get_step(player, turn(player.dir, 180)). No verbose logic necessary.
In response to Kaiochao
Kaiochao wrote:
You can get the tile behind a player at any instant with: get_step(player, turn(player.dir, 180)). No verbose logic necessary.

this. the turn proc didn't even occur to me. :(
https://www.youtube.com/watch?v=1ZIfcUvHZck

go to 6:36. this is what i want. See what happens when he changes directions
If you want your follower to step towards where you were before you moved, it can be as simple as this:
mob/player
var tmp/atom/movable/follower

Move()
var old_loc = loc
. = ..()
if(. && old_loc && follower && follower != src)
follower.animate_movement = SYNC_STEPS
step_towards(follower, old_loc) // or walk_to() or just follower.loc = old_loc

This is similar to what Maximum_Alex2003 mentioned.
In response to Kaiochao
it doesnt seem to do as mentioned. Like it does for the south side kinda. it underestimated the south side and overestimates the north. southside it want to go on my tile, north side it want to be an extra tile back for some reason
In response to Kaiochao
no no its not doing that. its just by tile when i want by exact pixel. Moving at the last location of the mob is the right idea though. It did help.

oh man i need to experiment more. I want the movement to look identical to that movement in the video. But ill try with this new info it might help get me somewhere
In response to DanteVFenris
If you wanted a pixel movement solution, you should've mentioned that when you posted that tile-based Pokemon demo!

// set to match world.icon_size
#ifndef TILE_WIDTH
#define TILE_WIDTH 32
#endif
#ifndef TILE_HEIGHT
#define TILE_HEIGHT 32
#endif

mob/player
var tmp/atom/movable/follower

proc/SetFollower(atom/movable/Follower)
set waitfor = FALSE // don't interrupt the caller
if(follower == Follower) return // avoid stacking loops
follower = Follower
while(follower && follower == Follower)
// the player's center (these are standard formulas)
var cx = (x-1)*TILE_WIDTH + bound_x + step_x + bound_width/2
var cy = (y-1)*TILE_HEIGHT + bound_y + step_y + bound_height/2

// the follower's center
var fx = (follower.x-1)*TILE_WIDTH + follower.bound_x + follower.step_x + follower.bound_width/2
var fy = (follower.y-1)*TILE_HEIGHT + follower.bound_y + follower.step_y + follower.bound_height/2

// the target destination (the part we're adding is the desired distance between the player and follower's centers)
var tx = cx, ty = cy
if(dir & NORTH) ty += (bound_height + follower.bound_height) / 2
else if(dir & SOUTH) ty -= (bound_height + follower.bound_height) / 2
if(dir & EAST) tx += (bound_width + follower.bound_width) / 2
else if(dir & WEST) tx -= (bound_width + follower.bound_width) / 2

// vector from the follower's center to the target coordinate
var dx = tx - fx, dy = ty - fy
if(dx)
// avoid vibration caused by over-stepping
follower.step_size = min(abs(dx), step_size)
step(follower, dx > 0 ? EAST : WEST)
if(dy)
follower.step_size = min(abs(dy), step_size)
step(follower, dy > 0 ? NORTH : SOUTH)
sleep world.tick_lag

Untested, but it might work, assuming your follower is non-dense (or at least Cross() lets players and their followers cross over each other, e.g. using the "group" variable).

edit: may have fixed a vibration issue, but still untested because phone.
In response to Kaiochao
one of the formulas was a bit off but i fixed it. I thought it would have been this complicated. Thank you probably couldnt have wrapped my head around this one as easily as you did. Thank you so much!!