ID:2304347
 
(See the best response by Ter13.)
Code:
mob/Login()
..()
src.loc=locate(100,100,1)
src.invisibility = 1
src.client.StartHotkeys()
for(var/mob/Walkingmobforlogin/M in world)
client.eye = M
mob/Walkingmobforlogin
New()
..()
sleep(1)
spawn(10)if(!key)RandWalk(0.1)
proc/RandWalk(Delay)
for()
sleep(Delay)
step_rand(src)


Problem description:
Hi! I'm trying to do something cool in login screen like some invisibility mobs walking around the map for show a bit of the game but im having some erros.
After some time I get black screen using the code this way(like in 10 seconds?) I tried to check what could be causing but nothing uses eye.
How I can pick "Walkingmobforlogin" randomly also?

when you switch client.eye to an object that isn't the client's mob, you need to set client.perspective to EYE_PERSPECTIVE.

It defaults to MOB_PERSPECTIVE. This affects what is in range of your mob's viewport.

As for picking your eyes:

for(var/mob/Walkingmobforlogin/M in world)


for in world pattern... Bad. The sooner you break this habit the better your code is going to be. Read Snippet Sunday #6

http://www.byond.com/forum/?post=1810538

For in world literally has to look at everything in the memory of your game just to find a specific set of objects you might already have laying around.

var/wandercams = list() //we're going to store every wandercam in the world here, because we know we'll need them infrequently later. This is a global variable.

mob/wandercam
New()
..()
wandercams += src //add this cam to the wandercams list
walk_rand(src,1) //tell it to walk randomly every 1/10th of a second (0.1 (your original value) = 100 steps per second, which is insane)

Del() //reference management is important to speed up deletion
wandercams -= src
walk(src,0)
loc = null
..()



Notice we're storing wandercam in a global list. If you need data later, best practice is to hang on to it somewhere you can access it later. In this case, our only real choice is in the global scope.

Now for swapping cameras every ten seconds:

client
proc
WanderCam()
var/next_cam = pick(wandercams), cur_cam
perspective = EYE_PERSPECTIVE

do //do whiles are a perfectly valid, if underutilized loop pattern. In this instance, they are actually ideal because their condition is being checked at the end of the loop rather than at the top.
eye = next_cam //swap the current eye to the next one.
cur_cam = eye
sleep(100)
next_cam = pick(wandercams-cur_cam) //pick another eye to swap to after the specified time.
while(eye==cur_cam)



And now let's drop in your initial code, modified to do what you want.

mob/Login()
..()
src.loc=locate(100,100,1)
src.invisibility = 1
client.StartHotkeys()
client.WanderCam()


One other point:

for()

This isn't technically wrong. It's best practice to avoid an unconditional infinite loop though. This can cause problems for you when shutting down a world. Every "infinte loop" in your code needs a termination condition at the very least. You risk running into problems down the line if you don't do this.
In response to Ter13
wow I got it! Thanks,I could not ask better explanation. I will try to avoid "in world" and place like "in some lists" on nexts codes
In response to Ter13
just more one question plz. I'm trying to break the loop but for some reason the eye not return to the mob.

mob/Login()
..()
src.loc=locate(100,100,1)
src.invisibility = 1
src.client.StartHotkeys()
sleep(200)
client.eye = src
client.still= 0
client.perspective = MOB_PERSPECTIVE
client
var/still = 1
proc
WanderCam()
var/next_cam = pick(wandercams), cur_cam
perspective = EYE_PERSPECTIVE

do //do whiles are a perfectly valid, if underutilized loop pattern. In this instance, they are actually ideal because their condition is being checked at the end of the loop rather than at the top.
eye = next_cam //swap the current eye to the next one.
cur_cam = eye
sleep(100)
if(still==1)
next_cam = pick(wandercams-cur_cam) //pick another eye to swap to after the specified time.
while(eye==cur_cam)
Best response
I made a small mistake in my code.

client
proc
WanderCam()
set waitfor = 0


I only realized it because I was about to say you should never sleep() in Login(). This is the case for a spawn(). WanderCam() is set by default to be waitfor = 1, we're going to change that to 0 so that the Login() proc won't wait around for it.

var/wandercams = list() //we're going to store every wandercam in the world here, because we know we'll need them infrequently later. This is a global variable.

mob/wandercam
New()
..()
wandercams += src //add this cam to the wandercams list
walk_rand(src,1) //tell it to walk randomly every 1/10th of a second (0.1 (your original value) = 100 steps per second, which is insane)

Del() //reference management is important to speed up deletion
wandercams -= src
walk(src,0)
loc = null
..()

client
proc
WanderCam()
set waitfor = 0
var/next_cam = pick(wandercams), cur_cam
perspective = EYE_PERSPECTIVE

do //do whiles are a perfectly valid, if underutilized loop pattern. In this instance, they are actually ideal because their condition is being checked at the end of the loop rather than at the top.
eye = next_cam //swap the current eye to the next one.
cur_cam = eye
sleep(100)
next_cam = pick(wandercams-cur_cam) //pick another eye to swap to after the specified time.
while(eye==cur_cam)

mob/Login()
..()
src.loc=locate(100,100,1)
src.invisibility = 1
client.StartHotkeys()
client.WanderCam()
spawn(200) //this is relatively unsafe.
if(client) //we need to make sure that the client is still connected, because the future state of the client cannot be certain after a spawn/sleep.
client.eye = src
client.perspective = MOB_PERSPECTIVE


You don't need the still variable at all. It doesn't matter if the next_cam picks before being applied. We can just discard the data in the case of the wandercam being broken early. It's of no consequence and complicates the design unnecessarily to add another client variable.

IMO, it's better to allow a little overhead waste from the unused pick than it is deal with the more complicated design.

Make note of the spawn() comment that it's unsafe. We're not doing any kind of state tracking for WanderCam(), so we can't be certain that the client eye variable is in the correct state to be canceled.

A safer alternative would be to modify WanderCam() if you have a specific duration in mind:

client/proc
WanderCam(duration=1#INF) //default duration is infinite
set waitfor = 0
var/next_cam = pick(wandercams), cur_cam, etime = world.time + duration
perspective = EYE_PERSPECTIVE

do //do whiles are a perfectly valid, if underutilized loop pattern. In this instance, they are actually ideal because their condition is being checked at the end of the loop rather than at the top.
eye = next_cam //swap the current eye to the next one.
cur_cam = eye
sleep(min(100,etime-world.time))
next_cam = pick(wandercams-cur_cam) //pick another eye to swap to after the specified time.
while(eye==cur_cam && world.time<etime)

if(world.time>=etime&&eye==cur_cam) //if the loop exited, and the wandercam routine wasn't interrupted by an eye swap.
eye = mob
perspective = MOB_PERSPECTIVE


Then you can just add an argument to your call of WanderCam to specify how long it will happen for:

mob/Login()
..()
src.loc=locate(100,100,1)
src.invisibility = 1
client.StartHotkeys()
client.WanderCam(200)
Thanks again !