This is the documentation for unit Animator.
Topics:
This unit adds to our toolboxes the global object
Footprint = '.' ;{use space for erase, or other char, such as dot(.) to leave a "footprint"}
To animate a simulation, instead of Monitor.Runsimulation, call
ANIMATE (SimLength, Samples, SimSlice, RealSlice);-- where
anAnimator = object Animating : boolean; {is animation in progress?} constructor init; procedure RUNAnimatedSIMULATION (SimLength : REAL; SampleSize : WORD; SimSlice, RealSlice : REAL); {USE in place of Monitor.runSimulation} {---- redefine these for graphics screen -----------} procedure Start; virtual; {Animation screen} procedure Stop; virtual; private AnimationList : FifoQueue; {of AnimationObj} lastshown: real; {real time timer used by show} procedure Show (timeslice:real); {show animation after real time interval, in seconds} end;
position = record { screen coordinates } x,y:real; end; AnimationPtr = ^AnimationObj; AnimationObj = object (queueElement) old:position; {where last shown, used by Update} new:position; {--this one you must keep current as appropriate} constructor Init (x, y:real {initial position}); procedure Update; procedure Draw; virtual; procedure Erase; virtual; destructor destroy; virtual; {take out of list} end;
A QueueAnimator gets associated with its queue by the parent pointer, it uses this to find out the current length of its queue. You pass the queue to Init as a parameter, it sets up the pointer.
QueueAnimator = object (AnimationObj) parent : ^list; MaxLen : integer; {max. length shown} constructor init (x,y:real; maxShown: integer; VAR Q:list); procedure Draw; virtual; procedure Erase; virtual; end; VAR ANIMATIONMonitor : anAnimator; {a global object initialized in this unit} procedure ANIMATE (SimLength : REAL; SampleSize : WORD; SimSlice, RealSlice : REAL);ANIMATE will now be used in place of
Monitor.RunSimulation
.
In fact it is simply short for AnimationMonitor.RunAnimatedSimulation
.
Ideally we would want to use multiple inheritance to inherit also the properties of an animationObj. Unfortunately, Turbo Pascal doesn't allow this, so we have to associate it in some other way.For example, a QueueAnimator has a pointer to its parent queue, which it uses to get the queue's length (
parent^.Card
).
In the next example, drawer is a field of the ball object. This uses the default Draw procedure, (currently, a * is drawn.)
ballp = ^ ball; ball = object (procdescr) drawer : animationObj; procedure lifecycle; virtual; procedure calc(VAR p:position); end;Ball happens to have a life cycle. This quasi-continuous object uses its own time slice to periodically update its position, in the new field of drawer.
procedure ball.lifecycle; const slice = 0.5; begin drawer.init(1,1); {throw from upper left} while true do begin Sleep_for (slice); calc (drawer.new); {update ball's position} end; end ; {ball.lifecycle}The procedure calc calculates the ball's position whenever it is called. Actually it should determine position based on last position, velocity, and timeslice, then possibly update velocity based on acceleration. This example is "pre-cooked" to give the parabola we expect.
procedure ball.calc (VAR p:position); begin with p do begin x:= 0.5 + time*0.75; {constant horizontal velocity} y := sqr(time/15)+0.5; {falling} if y > 24 then y:=24; {stick to ground and roll} end; end;That is all we need to do, besides readying the ball process and calling ANIMATE in the main program (instead of RunSimulation). Since drawer has been initialized, the animation of the ball will be seen.
The full example program does this, and it also shows a QueueAnimator in action. It runs for 10 seconds of real time, 100 simulation clock units (shown at lower right.)
Up to top of this document
Back to Simulation notes.
Comments, etc, send to
ljensenn at ubishops.ca