There are many interesting things to chew on and learn about here. I've been doing a bit of studying and playing around. For the benefit of other readers:
Basically, we are dealing with the fact that a computer can only do one thing at a time, and everything is on a clock.
So to make it *look like* more than one thing is happening at time, and to allow the computer to do other things, we have to play some tricks and do some juggling.
You'r right - it did run three times. I tested it. One only sees the last run.
I see now the logic of putting the script in the card. It is reflective of the fact of the message hierarchy.
I redrew the message diagram from the docs (
http://www.runrev.com/developers/lesson ... g-started/), since it was very hard to see. I posted it here:
http://www.ericplatt.com/livecode/Message_Diagram.pdf).
For example, handlers that are triggered in buttons (or any "control", such as an image, on a card), can call upon scripts in the card.
A couple of questions I have:
First, when does one want to place the script in the stack instead of the card – only when there are multiple cards? And is there an equivalent to the Background that HyperCard had?
Second, when is it appropriate to "send" a handler message rather than just call it. In other words, instead of
on mouseUp
if the hilite of me then
send startClouds to card "cloudcard0" of stack "Animation Explorer"
else
send stopMovingClouds to card "cloudcard0" of stack "Animation Explorer"
end if
end mouseUp
you could just say this (and it works), since the card is in the message path:
on mouseUp
if the hilite of me then
startClouds
else
stopMovingClouds
end if
end mouseUp
…because I notice they say in the docs: " Note: Using the send command is slower than directly executing the commands using the normal message path. For best efficiency, use the send command only when you want to delay the message or when the handler you want to execute is not in the message path."
Also, I'm not sure why you have the startClouds handler call moveClouds with a delay –
send moveClouds to me in 2 milliseconds
I thought this technique would be appropriate if a routine is calling itself (making a loop, like the moveClouds routine does), but why when it's calling another routine? It will work without the delay:
send moveClouds to me
Breaking the handlers down into start, stop, and move I realize is a widely applicable technique, whenever you have a running process, and need to allow other things to happen. I thought it'd be fun to make a little clock, and it turns out this technique is perfect for it. For example, one could do this (not using that technique) but then it's not obvious how to cleanly stop the clock:
local stopClock
on runClock
put the long time into field "time"
send "runClock" to me in 1 seconds
//if stopClock = true then exit runClock ?? not that doesn't work
end runClock
Do this instead:
local keepRunningClock = false
on startClock
put true into keepRunningClock
runClock
end startClock
on stopClock
put false into keepRunningClock
runClock
end stopClock
on runClock
if keepRunningClock = true then
put the long time into field "time"
send "runClock" to me in 1 seconds
end if
end runClock
And obviously you have start and stop buttons with something like:
on mouseUp
send startClock to card "clock"
end mouseUp
on stopClock
put false into keepRunningClock
runClock
end stopClock
Again though, one could simple say "startClock" without the "send" and it would work, since the card script is in the path of the message hierarchy.
(For the benefit of other readers:) One could vary the timing, or a distance or other increment inside of the loop in order to speed up or slow down a process. For example, if you wanted a scrolling field, the speed of the scroll could be changed with the send timing:
on doScroll
if scrollTheField = true then
put scrollDistance+scrollIncrement into scrollDistance
set the vScroll of field "prompt_field01" of this stack to scrollDistance
send "doScroll" to me in 100 milliseconds
end if
end doScroll
And change the speed by varying scrollIncrement. If the milliseconds are too large, it would look jerky, so it has to be fast enough to not be irritating. I might want to vary the m,illiseconds downward however… so somehow mix the two ways of varyingt the speed.
Does this seem like a good way to scroll a field dynamically and continuously? I'd like the user to be able to change things (like font size, speed, etc.), on the fly.
But this raised the question in my mind: if you send the move command (or any command in this kind of loop where it calls itself with "send" with a delay) and it's already loopinp, what happens? Because I noticed the scolling got faster if I clicked on the scroll button more than once.
I tested this with the clock stack, using the Message Watcher (Development menu) and discovered that it generates multiple runClock loops. This makes sense, but it was rather surprising and amazing (that the loop could be running concurrently many times). Then I suddenly understood why we need the code that uses the pendingMessages function, like you put in the stack you posted.
if runClock is not in the pendingMessages then
send "runClock" to me in 1 seconds
end if
This will allow only one loop to be running at a time. (The scroll routine needs the same thing)
Another thing I'm trying to puzzle out is the "stop moving" command in relation to move when used with either "without waiting" or not.
For example, if I had the following handler:
on doMove
if runMe then
// Move left:
move graphic "circle" to 0,cardLeftYCenter // If this has "without waiting" the graphic isn't moved to this position
-- because the whole handler (not just the statement) continues without waiting for it. But with no
--"without waiting", the handler pauses until the move is complete
// Move right:
move graphic "circle" relative cardRight-25,0 without waiting // This one is relative (so that it's relative to the initial positioning)
end if
end doMove
And to keep it going back and forth:
on moveStopped
send doMove to me in 10 milliseconds
end moveStopped
This works fine to move the graphic back and forth continuously, but if I use this to stop it:
on StopIt
stop moving graphic "circle"
put false into runMe
end StopIt
it works ok to freeze the graphic in it's tracks when it's moving right, but if it's moving left, it will stop, then move off to the right, off the edge of the card.
This has to do with the use of "without waiting" (or lack of) command, but it's a bit fuzzy to me. Apparently the first move command is halted because it executing and the handler is waiting for it to complete, yet the second move command, with the "without waiting" is still "in the queue" as it were, and subsequently fires off? Am I on the right track?
Moving on (no pun intended), the next thing I'd like to do with this stack is have some UFOs float in from random directions, and then the user be able to grab them and drag them to a goal, avoiding clouds, and bring them down to a “goal”. It should be easy enough figure out the random and coordinates part. For collision detection though, should I use the intersect function? And in order to drag and move an image are the dragStart dragData functions the appropriate ones to investigate?
Thanks!