[Grace-core] Animations in Grace

Kim Bruce kim at cs.pomona.edu
Sat Aug 31 11:05:46 PDT 2013


The loop constructs I have actually do use the step model as the block after the "do" does a single step.  The problem I am having is with getting nesting and sequential loops working properly with simple high level constructs.  I'll have to look up how some other folks have done this.  i know Andy van Dam and others at Brown have worked with this kind of model, so they must have done something like this. 

I would never have expected the thread-based model to be easier, but perhaps we originally chose examples that did work simply with that model and now need to look at other examples that are easier with timers.

Kim



On Aug 31, 2013, at 6:36 AM, James Noble <kjx at ecs.vuw.ac.nz> wrote:

> Hi KIm & all
> only brief comments - it's good your doing this.
> 
> I did think though that we'd need to think through how to do this:
> the problem - especially but by no means exclusively on JavaScript -
> is that you have to invert the control somehow.
> 
> I guess my question is - how would this look with a global (or per-displayed object)
> "step" or "draw" request that comes out of the event loop, and people only implement
> methods for just one cycle. Pretty much making a  state FSM explicit, via the inverted control.   
> 
> The problem with that, I think, is that you *want* to use animation to *teach* things like iteration.
> You want to write the while loops and have them work with interactive programs....
> 
> I'm not sure how to reconcile this with JavaScripts event based model, unfortunately.
> 
> perhaps Tim or Michael have other udeas...
> 
> (and I'm still sorry I didn't get timers going in GTK)
> 
> James, who probably won't make a teleconf on tuesday...
> 
> On 30/08/2013, at 10:38 AM, Kim Bruce <kim at cs.pomona.edu> wrote:
> 
>> Hi,
>> 
>> I'm about to turn into a pumpkin (classes start on Tuesday), so I've been desperately trying to finish up some of my Grace work.  Lately I've been focusing on getting animations to work.  Happily, Jameson set up a version of Michael's web-based Grace compiler with a timer that allows some of this to work.  I've had some successes, but still have a couple of issues that I'd like to put out here in the hopes that someone will have a great idea.  This email is long, but hopefully I can get some help with this.
>> 
>> First, all the code I am talking about is in the repository in the folder Objectdraw2013.  I have put in slightly revised versions of objectdraw.grace and Animation.grace, as well as a new application BouncingBasketball.grace.  You can try them out by going to:
>> 	http://web.cecs.pdx.edu/~mjameson/index.html
>> Use the "add a file" button at the bottom of the window to first add objectdraw.grace and then select "Go", then do the same with Animation.grace and BouncingBasketball.grace.  I've found that I have slightly better luck using FireFox than Safari for this (Safari gives weird path names in the "Module name" field.
>> 
>> When you run BouncingBaskeball, a window should pop up with two basketballs and a hoop.  If the mouse moves over them (mouse button not depressed), it will "grab" a ball which will follow the mouse though the ball will also bounce up and down in an animation.  When you press the mouse button down, it will stop bouncing, but you can then drag it wherever you want.  If you released the mouse over the "hoop" then it will score points.  There is one weird erratic bug that I haven't figured out yet (sometimes both basketballs will bounce at the same time), but I suspect that is a timing issue with my code.  Other than that, it seems to work out well.
>> 
>> Here is the type Animator from Animation.grace (though you can ignore the first three methods):
>> 
>> // type of object that can simulate parallel animations
>> type Animator = {
>>  // Start animating animated object bd
>>  startAnimating(bd:Animated)->Done
>> 
>>  // stop animating object bd
>>  stopAnimating(bd:Animated) -> Done
>> 
>>  // stop animating anything
>>  stopAnimation -> Done
>> 
>>  // Repeatedly execute block while condition is true with delay between each iteration
>>  while(condition:BoolBlock)do(block:Block)-> Done
>> 
>>  // Repeatedly execute block (with delays) while condition is true
>>  // when condition fails, execute endBlock.
>>  while(condition:BoolBlock)do(block:Block)
>>                        finally(endBlock:Block) -> Done
>> 
>>  // Repeatedly execute block after delays of time as long as condition is true
>>  every(time:Number)while(condition:BoolBlock)do(block:Block) -> Done
>> 
>>  // Repeatedly execute block after delays of time as long as condition is true
>>  // Execute followBlock after condition fails
>>  every(time:Number)while(condition:BoolBlock)do(block:Block)finally(followBlock:Block) -> Done
>> }
>> 
>> The implementation code is different for some of these as I'm still experimenting.  However, I'm having an issue that I'm hoping I can get some advice on.
>> 
>> The code for BouncingBasketball has a method called dribble.  The idea is that there is an outer loop which bounces the ball until the user clicks.  Inside the outer loop, there is first a loop to slowly move the ball down, followed by a loop to slowly move the ball back up.  This is easy to do if the method is running in a separate thread.  Each move is followed by a small pause.  Because this thread is distinct from the event thread, the program still responds to mouse presses, etc., exactly as desired.
>> 
>> Now, I'm trying to build control structures that emulate a thread (or at least allow me to do the same kind of animation), but using only timers.  The timer that Jameson implemented has the following operations (which I assume mirror those of javascript):
>> 
>> 	every(millisec)do(code)
>> 	after(millisec)do(code)
>> 	stop(id)
>> 	stopAll()
>> 
>> The first returns an id which can be used to stop execution.
>> 
>> The difficulty with these is that when these statements are executed (like my while loops above), the timer is set, but control passes immediately to the next statement.  That makes it tricky to stage computations so that one computation waits until another has completed. That is the reason for methods like my
>>    every(tm)while(cond)do(blk)finally(endblk)
>> where endblk is not executed until the while loop condition fails.  Thus the core of my dribbler code to stage the two while loops is:
>> 
>>       animator.every(1100) while {!stopDribbling} do {
>>           var moveCount := 0
>>           def animatorDown = anim.AnimatorClass.new
>>           print "starting down"
>>           animatorDown.every(100)while {(moveCount <= MOVES) && !stopDribbling} do {  // first inner while loop moves ball down
>>               print "down {moveCount}"
>>               ballInPlay.moveBy(0, MOVE_SIZE)
>>               moveCount:= moveCount + 1
>>           } finally {
>>               // make the ball bounce up
>>               def animatorUp = anim.AnimatorClass.new
>>               moveCount := 0
>>               print "starting up"
>>               animatorUp.every(100)while {(moveCount <= MOVES) && !stopDribbling} do { // 2nd inner while moves ball up
>>                   ballInPlay.moveBy(0, -MOVE_SIZE)
>>                   moveCount := moveCount + 1
>>               }
>>           }
>>       }
>> 
>> The outer while loop controls each iteration of a full drop and rise.  The "animatorDown" while loop brings the ball down slowly
>> The "animatorUp" every()while()do() loop is in the "finally" block of the earlier loop, and bring the ball up again slowly.  
>> 
>> What's the problem?
>> 
>> There are two issues (1) the complexity of the code and (2) the sensitivity of the code to the time parameter.
>> 
>> For (1), you can just see how complex the code is for method dribbler.  By comparison, see the Java code in:
>> 	http://www.cs.pomona.edu/~kim/CSC051F12/demos/BouncingBasketBall/Dribbler.java
>> which is the solution using a class extending ActiveObject (which itself extends Thread).  It is a pretty straightforward implementation of  two successive while loops with another while loop wrapped around them.  Not trivial, but pretty easy to explain.  On the other hand the code above (even without the outer while) has the second while loop nested in the finally clause of the first -- an extra complexity that is unfortunate.
>> 
>> Moreover if students neglect to put the animatorUp loop in the finally clause of the animatorDown above then the two will run at the same time, causing the ball to just vibrate a little -- and that will be a common mistake for them.
>> 
>> Moving on to issue (2):  to get this to work I had to get the times just right.  If the outer while loop had a delay of less than 1000 then the timer starts firing for the next iteration before the first finished, causing the animation to get completely screwed up.  Of course, all I had to do was get the arithmetic right (a total of 10 iterations each triggered every 100 ms), but students don't always get that.
>> 
>> What I really wanted was to have the next iteration of the outer loop to start immediately after the first finished.  Now I can actually encode that with a couple of mutually recursive functions using the timer class -- and that can cover exactly this case -- but only this case.  However, what I'm looking for is a general control construct that I can put in a library.  Then I could give them the library and have them write code very much the Java code cited above.
>> 
>> I didn't see an easy way of doing that, but I don't have much experience with timers and may be missing something obvious.  Anyone have any useful ideas (and sample code)?
>> 
>> Thanks!!
>> 
>> Kim
>> 
>> P.S.  I expect similar issues to arise in the C-based compiler, so I think this is important.
>> 
>> 
>> _______________________________________________
>> Grace-core mailing list
>> Grace-core at cecs.pdx.edu
>> https://mailhost.cecs.pdx.edu/mailman/listinfo/grace-core
> 




More information about the Grace-core mailing list