The State Machine
The state machine has five states controlled by two events, one for left page flips
and one for right flips. The machine controls and coordinates the pages of
the album and the sound effects of the album. The sample uses notification
objects because of the cyclic dependency in the finite state machine
(not because of event data, which is the second purpose for using notification
objects). Notification objects, by providing a delayed execution construct,
make it possible to construct cyclic calling dependencies without infinite looping.
The sample also uses the until2 method instead of untilNotify since it allows the
aggregatation of two notification events each with a different notification method;
see the opened state below.
Note that both cyclic dependency and branching from one
state into two or more states upon different events are commonly
occuring patterns in general state machines. Hence the example below
has the building blocks that are needed for typical state machines.
This state is the entry point into the state machine
and is also returned to upon flipping the
front page back (effectively going back to the start state).
It sets the left page to blank, the right page to
the front page of the album, and it emits the page-flip completion sound
through the right speaker.
The state waits on the leftEventNotify event upon which it
invokes the transLeft notification object which implements the
"transition left" state. |
public static TupleBvr frontState () {
NumberBvr leftInd = toBvr(0);
Behavior newBvrs[] = { leftInd, add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(+1)};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, leftEventNotify);
}
This state is entered upon the end of a page flip
that causes the album to be properly opened
(i.e., not in a boundary condition). It waits on either a left or a right
event, at which point it invokes the transLeft or transRight
notification objects, respectively, which carry it through either
the left transition or to right
transition state. It accepts an index to the
left page plus the side to which the previous page was flipped to,
in order to emit the page flip termination sound. |
public static TupleBvr opened (NumberBvr leftInd, int side) {
Behavior newBvrs[] = {leftInd , add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(toBvr(side))};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, orEvent(rightEventNotify,
leftEventNotify));
}
public static TupleBvr backState () {
NumberBvr leftInd = toBvr(A3DM.numPics);
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(1)),
emptyGeometry, endSnd.pan(-1)};
TupleBvr tuple = new TupleBvr(newBvrs);
return (TupleBvr)untilEx(tuple, rightEventNotify);
}
This notifier object flips the center page to the left side until the
completion of the page flip. At that point if we've flipped
the last page then we go to the back state, else we go to
the opened state, which is the nominal one.
Notice how we extract the present left page index from the "previous"
parameter of the "notify" method. |
class TransLeft extends Statics implements UntilNotifier {
public Behavior notify(Object eventData, Behavior previous, BvrsToRun blst) {
NumberBvr leftInd = (NumberBvr)((TupleBvr)previous).nth(0);
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(2)),
A3DM.flip(add(leftInd, toBvr(1)), -1), A3DM.flippingSnd(-1)};
return (TupleBvr) until(new TupleBvr(newBvrs), A3DM.endFlip,
cond(eq(leftInd, toBvr(A3DM.numPics - 1)),
A3DM.backState(),
A3DM.opened(add(leftInd, toBvr(1)), -1)));
}
}
class TransRight extends Statics implements UntilNotifier {
public Behavior notify(Object eventData, Behavior previous, BvrsToRun blst) {
NumberBvr leftInd = sub((NumberBvr)((TupleBvr)previous).nth(0), toBvr(1));
Behavior newBvrs[] = {leftInd, add(leftInd, toBvr(2)),
A3DM.flip(add(leftInd, toBvr(1)), +1), A3DM.flippingSnd(+1)};
return (TupleBvr) until(new TupleBvr(newBvrs), A3DM.endFlip,
cond(eq(leftInd, toBvr(0)),
A3DM.frontState(),
A3DM.opened(leftInd, +1)));
}
}
interaction events
Right and left arrows to flip pages. |
static final DXMEvent rightEvent = keyDown(Event.RIGHT);
static final DXMEvent leftEvent = keyDown(Event.LEFT);
signals the conclusion of a page flip animation |
static final DXMEvent endFlip = timer(toBvr(period));
instantiate the notifier objects |
static final TransRight transRight = new TransRight();
static final TransLeft transLeft = new TransLeft();
Define notify events based on the previous objects,
these events get used in the state machine. |
static final DXMEvent rightEventNotify = rightEvent.notifyEvent(transRight);
static final DXMEvent leftEventNotify = leftEvent.notifyEvent(transLeft);
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.