Interactive Simulation Newsletter

Vol. 1, No. 2 (May, 2003)
This Edition's Contents:
This newsletter is brought to you by Jonathan Kaye and David Castillo, the authors of "Flash MX for Interactive Simulation," the first practical guide to building interactive product simulations and performance-based training in Flash.

Enter your email address here to receive the accompanying source code and automatic notification on future newsletter releases.

WELCOME!

Welcome to the second issue of our interactive simulation newsletter! Since the release of the first newsletter, we've received a lot of positive feedback about the word we're spreading. It's great to hear about all the interesting work being developed using interactive technologies and simulation.

This month, we're featuring a "lessons learned" article by Jan Meyer, creator of the Curta simulator, a Flash-based simulator of the Curta mechanical calculator. Jan shares with us experiences in thinking about approaching this project and what was learned during design and implementation. We also offer some tips and thoughts regarding developing practice simulators, and, in the Component Corner, how to extend listener functionality to communicate with listeners on different timelines.

If you have a story to tell about a simulation project you are developing or have developed, please let us know. By sharing and discussing our experiences, we all become better simulation developers!

Jonathan & David

 
YOUR OPINION COUNTS
 

Note: While we encourage you to join the discussion, we feel we've heard enough about making money fast, cheap or natural Viagra, African dignitaries wanting to give us money, low cost insurance, penis enlargement, dates for married men, Russian girls waiting to hear from us, reducing wrinkles, tips for exploding our income, and losing weight rapidly. So if your post was going to be about one of those or along a similar vein, please post somewhere else. On the other hand, if you need any of these services, I'm the man to talk with!

Jonathan

We constantly run into all different people around the country and world who have interesting simulation projects they have in mind or have prepared. We want to encourage you simulator programmers, instructional designers, gamers, managers, and other developers to share your stories and best practices with the rest of us. We invite you to lead or join the discussion on our FlashSim discussion board:

http://FlashSim.infopop.cc/

We also will monitor the discussions for particular topics that might make good newsletter information, so go forth and post!

If you have suggestion for topics you'd like to see in the newsletter, or links to events or interesting Flash pieces you've made, please email us at newsletter@FlashSim.com.

 
ELEMENTS OF PRACTICE
 

One of the oldest jokes I know goes something like this. A male tourist approaches a man standing at the corner of 57th Street and 7th Avenue in New York*. He asks the man at the corner, "how do I get to Carnegie Hall?" He replies "practice, man, practice!"

Practice is essential to developing skill proficiency and mastery. Common sense tells us that the more practice opportunities using a product or skill that you give to users, the more comfortable they will feel operating the product, or the better they can evaluate whether the product meets their needs. Practice helps users develop skill proficiency, which is usually defined as responding/performing correctly in the given situation and within an appropriate amount of time. This is especially true for work situations in which a rapid, correct response is critical. One of the great values of product simulation is to permit such practice opportunities when the actual device and circumstances are not available or are otherwise prohibitive in some respect.

One significant caveat, however, is that merely giving your users access to a product simulator will not, by itself, encourage more practice and better use. While practice is usually less structured than a tutorial, with respect to detailed sequencing of steps, you still need to decide

  • Which types of activities can the user practice
  • What are typical scenarios in which those activities and skills are practiced
  • What the initial configuration (setup) for each of those scenarios will be
  • Which interactions to allow the user to control
  • How the user can perform the steps or interaction
  • What the goal, or end state, is
  • How you will measure that the goal has been achieved, and
  • What hints, feedback, and assistance to provide to the user, and when.

We have found that weaving a story about a real-life problem scenario into practice sessions are the kinds of 'hands-on' learning that users appreciate, rather than practicing skills based on an abstract, theoretical need to perform.

Building a simulator for use in practice sessions may seem like a tough task, since you have to anticipate the way in which the user will operate the device properly and improperly. However, rather than rushing off to build a complete simulator, you can accomplish quite a lot with limited resources so long as you define the elements of practice clearly for the tasks you need your users to accomplish. The more specifically you understand the mechanics behind the skills that require practice, the better you can design focused exercises and opportunities that really employ those mechanics.

A common pitfall in designing practice, particularly with devices, is to require that the operator manipulate controls in exactly the way in which the controls are manipulated in real life. The problem is that sometimes the way in which one manipulates the controls via the computer is different from the way in which he or she manipulates the control on the device, for example, knob turning. It may be perfectly reasonable to allow your users to "turn" virtual knobs by clicking on the final knob value, rather than forcing the user to click and drag the cursor in a circular motion. Key considerations in deciding to simplify interactions are

  • How relevant is having the user replicate the physical movement to the behavior and tasks you want to teach
  • How much different would the manipulation be on the computer screen versus in real life.

For simulation outside of direct manipulation of controls, you can even write "simulation-like questions" that permit practice without the expense of building a simulator (see Will Thalheimer's articles and resources on this subject, at http://www.work-learning.com).

Performance Metrics to Asses Practice Effectiveness

Two important performance measures used to assess practice effectiveness are

  1. Response Ratio. What is the ratio of correct answers (in our case, demonstrations of procedure or skill completion) to incorrect answers?
  2. Latency. How quickly did the operator perform the appropriate response?

Increased response rates coupled with shortened latency are correlated with better retention, less distraction, and better transfer of skills to the work environment. Increasing response rate and shortening latencies are best accomplished with short, but rapid, drills in which the learner must make responses that approximate the types of tasks they are expected to perform on the job.

Rather than dumping a user into a single, complex, practice scenario, in a "sink or swim" approach, you may want to consider staging your practice sessions, from simple to complex, just as in a game. Focus first on training specific, elemental skills in the simple exercises, and then more involved, composite skills exercise in a less guided skill application for the complex scenarios.

Some Preparatory Questions

Here are some questions we ask ourselves when designing practice opportunities:

  • What specific skills do we want the operators to develop / demonstrate?

  • Will the practice be supervised? This has to do with what type of feedback we feel we need to include in the presentation, as opposed to feedback that the instructor will provide.

  • Do we have any practical feedback or experience in what types of practice sessions have been successful for usin the past?

  • Do we have any practical feedback or experience in what types of practice sessions have not been successful for usin the past, and why they were not successful?

  • What constitutes successful attainment of a skill? This involves choosing an appropriate starting point (configuration), verifying the user's correct application of interactions based on procedure steps, and seeing whether the simulator ends up in the correct final state.

    In some cases, there may be several correct sequences to achieve the final state. For example, if the procedure involves setting three knobs, it may not be relevant which knob is set first, second, and third. In some circumstances, however, it may be desirable to teach the knob setting in a particular order so as not to rely on individual variety that can introduce error, even if that order is not required for real use.
    Such an ordering may be a useful pattern to ensure that all the values are checked and/or adjusted. For example, in some industries, a mnemonic such as "set the knobs on the panel in a C pattern" is taught to mean the operator should methodically start with the knob at the upper right corner (of the "C"), moving left to the next knob, then down, then to the right (base of the "C"), as if drawing the letter "C". An operator who applies this pattern will reduce the chance of missing the setting of a knob, especially in situations in which the operator needs to act quickly.

Common senses says that people will be more interested and attentive if they find the opportunity rewarding in some way, such as because

  • They find the activity fun to do
  • They see the opportunity as a way to make themselves more efficient at tasks (presuming of course that they recognize the value of being more proficient), or
  • There is some professional accomplishment or incentive tied to it.

We have even found that creating a basic scoring system based on response rate and/or latency, and introducing competition, workers will find incentives themselves, even just for "bragging rights" among colleagues.

One positive side effect of developing a good practice simulation is that much of the same simulator you develop for practice can be used for assessment and certification. With more practice opportunities, and simulation-based assessment, we can really talk measurable results!

 
* For the non-New Yorkers: this is next to Carnegie Hall, one of the great concert halls in the US.
 

 

LESSONS FROM BUILDING THE CURTA SIMULATOR
 
Jan Meyer's Curta Simulator
(click to open the simulator from www.curta.de)

We invite community members to share their experiences in designing and building simulations.  Jan Meyer wrote this nice article about experiences in building a simulator for the Curta mechanical calculating machine.  We have edited it for details but not for content.  If you have any questions, please direct them to Jan at jan.meyer@t-online.de.

Language Note: Jan has provided a lot of information about the Curta device on www.curta.de, but it is in German. There is an English Curta manual at http://www.vcalc.net/cu-man2.htm. The German version of the simulator (labels in English) is here: http://www.curta.de/kr34/curta_simulator.htm. You can get a quick-and-dirty translation of most of the information using free Web translation services such as http://babelfish.altavista.com.

CLICK HERE for the English translation (via BabelFish) of www.curta.de.

1         About Jan Meyer

I’ve worked for more than 20 years in the IT Industry, but my work in Flash is only a hobby. The Curta Simulator project is part of my main hobby, which is the history of mechanical calculating aids and calculating machines.

I have two web sites: www.rechenhilfsmittel.de and www.curta.de .

2         The idea

I was thinking for a long time about building a Curta simulator, but the problem I kept running into was how to make the Curta’s 3D interface, with sliders on the front and back, as well as dials on the top, onto a 2D computer screen?

My first idea was to make the Curta using real 3D computations.  The user could manipulate it to see the front, back, or top.  However, I felt this would be too complicated for a few reasons:

  1. Too complicated to represent visually/graphically
  2. Too complicated to program
  3. Too complicated for the user to manipulate.

Therefore, I decided to separate it into a top and a front view and to show the slider on the back as a small cutout.  For an easier readout and to make clear how a Curta works, I added a extra panel.

3         The Curta project

3.1        The graphics

This was the hardest part for me (I am no artist). First I took a picture of a Curta from the front and from the top. I used this picture as a drawing template in Flash. Not for the details, but to get the right size and proportions.

The first trial was not very impressive. The front of the Curta was only a gray rectangle and the top of the crank was only a gray circle. But after adding some gradients and other touches, things looked better.  At the breakouts for the slider, I added some dark line to the left and a light line to the right. The sliders are smaller when they are not in the center. And so on ....

All this together gives a good representation of a real Curta.

By the way: I have been searching for years for a good book that teaches such technique for making realistic computer graphics, so if someone knows one, please let me know (jan.meyer@t-online.de).

3.2        The user interface

One of the issues I faced in designing the interface was whether I wanted to the sliders to be what I call ‘direct’, meaning if I grab the indicator and drag it, the same as I would use a mechanical slider, or ‘indirect’, as if I click somewhere on the slider and the indicator jumps to that position.  I call this ‘indirect’ because no mechanical slider works this way.

I finally decided to use the indirect way.  Why? 

When the user see a red arrow that points down near the crank, then it is clear that he can click the arrow and the crank will go down.  If there were no arrow and I had used the direct method, the user would have to drag the crank up or down.  But how was I going to show the user that there was something to drag at all?

3.3        The components

At first, I made the moving components as movie clip tweened animations, for example, the rotation of the reset ring.  But it turned out that this was not a good idea, because the reset ring had to rotate left and right at different angles.  This would be hard to do right using a tweened animation.

By the end, I had no tweens at all!  All rotation and translation was done programmatically.  It really only took a few lines of ActionScript to do this, but it required some basic knowledge of trigonometry (sines and cosines).

I found it was very important to have a consistent naming scheme for the components, for example, top_crank ("top crank"), frt_crank ("front crank"), for the two views of the crank.  As well, I found it useful to make the components have methods with the same name, for example, RotateRelativBy(degree,steps).  With this as an example, if the crank sends the message “button pressed,” than the central control calls

top_crank.rotateRelativBy(360,17);
frt_crank.rotateRelativBy(360,17);

The front and top cranks make a whole revolution in 17 frames. This concept works great. Every component can be tested separate.

During testing, I made a text window (with a clear button) to document all the messages that were sent from the components, and all the methods invoked. This was very helpful and pretty amazing to see how all the components working together when you calculate with the Curta.

3.4        Programming details

I used the concept of components, messages and central control, from Jonathan’s and David’s book, for the first time. However, I didn’t use a state machine because I didn’t want to tackle too much for this first try.

In general, the program was pretty simple, but here are some tips I can pass along.

The calculation starts when the crank begins to rotate, but the digits should not change all at the same time—only once the crank or reset ring passes by.  When the arrow on the top view is clicked, I do the calculation in the background.  The results are saved as numbers then converted into an array in which each element holds a digit.

As the crank rotates, it sends messages such as “I just passed digit 5 of the revolution counter,” and the central controller calls methods to set the digit on the Curta and the panel.

3.5        The sound

After the Curta was finished, I missed the sound. So I recorded it from a real Curta. Some of the sounds are only in effect if there is really something to do. For example: If all dials are at zero and you make a reset not a single gear is turned. And so there is no sound. Therefor the sound is only played if the new value of a digit is different from the old.

Thanks to getting the concept down in my mind clearly, I added the sound in less than an hour!

3.6        Conclusion

With the help of Jonathan’s and David’s book, I made this Curta simulator in a relatively short amount of time. After building and testing the components it was really fun to put it all together. When problems occurred, I could easily locate them and fix them.  The problems I used to have making Flash applications as one big program did not occur.

In spite of my urge to start programming, I saw in this project how important good planning was.  I would strongly recommend that you take more time for planning than for drawing and programming in Flash.  Once I started the drawing and programming, I found it helped me to complete the project rapidly by focusing on one thing at a time, not making a little change here or a little new function there, and so on.

If anyone has a special question about the Curta simulator, please don’t hesitate to contact me!

 
 
COMPONENT CORNER: Communicating with Listeners on Different Timelines
 
This month's download is a file called FISBase.fla, which contains the source code for the revised listener mechanism. To download the source code, you must sign up for the newsletter by email (click here).

The column this month is about how to program the addListener mechanism to accept a listener by name (such as through the property inspector), accounting for the situation in which the listener exists on a different timeline than the component.  But first, the motivation…

Why Would a Listener be on a Different Timeline?

One of the principles we teach in our book for building scaleable and complex interfaces is the importance of centralizing the event handling with respect to the current context (“state”).  This means separate the coding of states first, then, for each state, separate the event handling for that state.  A good design expresses what the device does (and the possible interactions and results) in each state.

However, the typical way one might write an event handler, such as

myPowerButton.onPress = function () {
   // figure out what state the device is in then make any
   // change that occurs by button being pressed

   if (deviceOn) {
      turnDeviceOff();
      deviceOn = false;
   } else {
      turnDeviceOn();
      deviceOn = true;
   }
}

follows a pattern opposite to this principle.  This latter approach separates the events foremost, and for each event (such as the power button press), it has to figure out which state the device is in, and then handle the particular event for that context.  While this doesn’t seem on the surface to be much different from the former approach, the problem with the latter approach is that it is more difficult to see the behavior of the system in a particular state—the behavior is the collection of code across all the event handlers.  If you inherited this project and wanted to understand what the device does in a particular state, you would have to look through all the event handlers and pull out the code that is relevant for that state.  If it’s more difficult to see the behavior for the particular context (state), then it can be much harder to debug, validate, and extend the code.

Our book describes how to centralize event handling with respect to state.  All the interface elements send their events to a central “control object” event handler, we call “ieh” (for “internal event handler”).  The event handler ieh is a method of our state engine data structure, for convenience.  The role of the ieh method is formally to distinguish the states, and handle the event for the particular current state.

Since each of the interface elements are communicating with a single method, a problem sometimes arises when elements are placed on different timelines from the event handler, or state engine.  When you drop a component from our book onto the Stage, you can enter in the property inspector (see Figure 1) the variable name of a listener that will receive event broadcasts from that component.  For example, if you enter “xyz”, then the component will invoke the ieh method of the xyz object.


Figure 1. Entering the listener name into the property inspector

In our components, you can pass to addListener either a string with the name of the listener (object)—this is the mechanism used with the property inspector—or a pointer to the listener object itself.  If you pass in the string name, then the components in the book assumed the listener was on the same timeline as the component.

However, a user interface may have several layers of movie clips.  Therefore, if you use the property inspector to tie your component to your central coordinator (control object), you may want to use the _parent variable to give a relative address of the listener.  For example, suppose your listener “xyz” is at one timeline, and your components are two layers deep.  You would want to say “_parent._parent.xyz”, (as in Figure 1), but this will not work for the components given in the book.

Modifying the Listener routines

Using _parent doesn’t work for the book’s components because ultimately, when a string is used as a listener name, the notifyListener routine invokes the event handler by using

(this.timeline)[ <listener name> ].ieh(msg, val, this);

This looks for the listener on the timeline specified by “this.timeline”.  Therefore, if _parent (or _root, or _level, for that matter) is part of the string, then the method invocation will fail.

The answer is to change the processing of addListener so that if it sees the _parent keyword, it converts the string into something that does not rely on the invocation as above—it turns the string into the absolute address of the listener.  For example, if the listener is listen1 on the _root, but the component is located in clip xyz, then the absolute address is “_root.listen1”.  This is the same as “_root.xyz._parent.listen1”.  Do you see what we’re about to do?

Thankfully, if we pass in “_root.xyz._parent.listen1” to Flash, it is equivalent to “_root.listen1”.  Therefore, when it sees a _parent keyword, addListener simply concatenates the timeline (in this case, “_root.xyz”) with the listener string (in this case “_parent.listen1”):

if (typeof(nm) == "string") {
            var pfx = nm.toUpperCase();
            if (pfx.substr(0, 7) == "_PARENT") {
                      nm = this.timeline + "." + pfx;
            }

          this.lnames[nm] = nm;

 ...

Now, to get notifyListeners to evaluate the string properly.  To cut to the chase, we decided that if there is a period (“.”) in the listener string, then the string represents an absolute address, and we simply evaluate an absolute address:

eval(this.lnames[i]).ieh(msg, val, this);

In the code, this works out to be

if (this.lnames[i].indexOf(".", 0) == -1) {
           // no '.', so use the current timeline (p == this.timeline)
            p[this.lnames[i]].ieh(msg, val, this);

} else {
            // some kind of level, parent, or root prefix, so evaluate string
            eval(this.lnames[i]).ieh(msg, val, this);
}

We could have simply looked for “_parent” in the string, but then processing would not work if the user uses the _root or _level keywords.  This way is relatively unobtrusive, and it captures the use of all three keywords (_parent, _root, and _level).

Fortunately, all of our components use a common class called FISBase that implements the event (listener) behavior.  Therefore, if you change the FISBase code in one place, all your components will work properly with the new functionality.  How is that for a benefit of OOP!

The Code

To use this code, you’ll need to replace the actions inside the FISBase movie clip, which is the foundation for all the components.  To change FISBase in the installed component file from the book,

  1. Open in Flash the FISComps.fla file found in the directory in which Flash MX is installed on your machine (see page 155, Table 10-2, in the book to find this location)
  2. Open the Library of the FISComps.fla file.
  3. Open the FISBase file included in the subscriber version of the newsletter (CLICK HERE to subscribe).
  4. Open the Library of the FISBase movie. Separate the Library windows by clicking and dragging on the left border of the grey title bar of the Library for each file
  5. Find the FISBase movie clip in the Library (within the Library, inside the FIS Interface Components > Developer Assets folders), and drag it into the Library of FISComps.fla.
  6. When Flash asks you whether to use the code already present or replace the existing code, choose Replace existing items (not undoable). Save the FISComps.fla file, and voila!

As always, please post message on the discussion board if you have any questions, or email Jonathan directly!

 
UPCOMING EVENTS
 
Do you know about a simulation event you'd like to announce? Tell us about it at events@FlashSim.com!
Date Event Location
June 23 How to produce simulation-based e-Learning without breaking the bank, at the eLearning Instructional Design Symposium Boston, MA
June 24 One day workshop on Building Device Simulations, Slice of Life Philadelphia, PA
June 24 How to build product simulations, Boston MMUG (in the process of being scheduled) Boston, MA
 
ADMINISTRATION

This newsletter also is available on FlashSim in the RESOURCES section, but it does not link to the component download file:
http://www.FlashSim.com/resources/newsletter/v1n2.html

If you'd prefer not to receive this newsletter, send us your name, your registered e-mail address, and the message: "Unsubscribe" to removeListener@FlashSim.com.

If you are receiving this newsletter from a friend and want to subscribe yourself, please email us a message with the subject "Subscribe" to addListener@FlashSim.com.

 
LET US HELP YOU WITH YOUR PROJECTS
If you have an interactive-simulation problem or project you would like to discuss with Jonathan and David, please email us and we'd be happy to help you. Through our company, Equipment Simulations LLC, we offer customized workshops and project assistance to help you avoid wasting money on training that doesn't improve performance. We can help you save time and money by enhancing your skills with methodologies that provide a scaleable, sound, and reusable framework.
 
 
All content © 2000-3 Equipment Simulations LLC