[Grace-core] Animations in Grace

Kim Bruce kim at cs.pomona.edu
Thu Aug 29 15:38:33 PDT 2013


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.




More information about the Grace-core mailing list