Open/Close - Reversing Animations

Another good question: in Spazz 3D, how do you make something like a door that opens when you click it, then closes when you click it again.

Here are three ways of doing it:

1) A single animation with a toggle.

2) An animated invisible trigger.

3) A VRML script.

Single Animation with a Toggle

Files: door1.wrl, door1.spz

Open door1.wrl. If you click the door just once, it will open, remain open for about 4 seconds, then close again. You can also click it to start the animation; then, when it's open, click to stop the animation and keep it open. Click again to start the animation, and (after a short pause) it will close again.

This is the method I use with my Deluxe Recliner.

There is only one animation for reclining - it tilts the chair back, then sets it upright again. In the middle of the animation, I pause for a few seconds. I use a TouchSensor on the handle, and set it as a toggle. When you click the handle, the animation starts, tilting the chair back to its fully reclined position. When you click it again, the animation stops in the current position. This method will work for drawers and other objects that essentially have two positions and animate between them.

Summary:

  1. Create an animation that opens the door, pauses with the door open, then closes the door.
  2. Create a TouchSensor node to trigger the animation, and set it as a toggle.
  3. Click the sensor object to start the animation, and stop it in the open position. Click it again to close the door.

Animated Invisible Trigger

Files: door2.wrl, door2.spz

Open door2.wrl. Click the door, and you'll see the "invisible" trigger appear around the door. Click the invisible trigger, and the door will close again. In this example, I make the Invisible Trigger only half transparent (.5), so that you can see it in action - when you use it on your objects, set the transparency to 1.

I've used this method most recently on the lid to my Happy Homemaker Washing Machine. It uses two triggers - one on the door, the other on an invisible object.

First I make the door, and animations that open and close the door.

I put the door in a group (hint - put the group between the hinges of the door, and animate the group - easier to animate the group at the hinges than to try to animate the rotation of the object from its own center). I add a TouchSensor to the group, and have it trigger the Open animation.

I create a second box named InvisibleTrigger that's slightly larger than the door in all directions. I position it in the exact center of the door. Then, I set its scale to .001, hiding it inside the door. I put the InvisibleTrigger into a group, drag that group into the Door group, and set its Trans to x0, y0, z0 (center it in the door - be sure you add the InvisibleTrigger's group to the door group, so that it moves with the door). I add a TouchSensor to the group, and have it trigger the Close animation.

I go back into the Open animation, and add the InvisibleTrigger to the list of nodes. I animate the scale of the InvisibleTrigger so that when the animation is complete, it is uniformly scaled at 1 (i.e., slightly larger than the door in all directions).

I go back into the Close animation, and add the InvisibleTrigger to the list of nodes. I animate the scale of the InvisibleTrigger so that when the animation is complete, it is back to its tiny .001 size.

Finally, we have to make the InvisibleTrigger invisible. Selecting one of the materials that I'm not using in the object (say, Shiny_Purple), I assign that color to the InvisibleTrigger, and change the Transparency of the material to 1 (making it 100% transparent).

Now, when I click the door, the animation opens it and expands the InvisibleTrigger to cover the door. When I click again, I hit the InvisibleTrigger, rather than the door itself. As the door closes, the InvisibleTrigger shrinks down again, and is hidden inside the door.

Summary:

  1. Make a door.
  2. Add it to a group that is centered at its hinges.
  3. Make an animation that opens the door group (not just the door)
  4. Make a second animation that closes the door group.
  5. Create a box that is slightly larger than the door in all dimensions, and name it InvisibleTrigger.
  6. Set the uniform scale of the InvisibleTrigger to .001.
  7. Center the InvisibleTrigger in the door.
  8. Create a group for the InvisibleTrigger, and center it in the door.
  9. Add the InvisibleTrigger to the InvisibleTrigger group.
  10. Go back to the Open animation, and add the InvisibleTrigger to the node list.
  11. Animate the uniform scale of the InvisibleTrigger to 1.
  12. Go back to the Close animation, and add the InvisibleTrigger to the node list.
  13. Animate the uniform scale of the InvisibleTrigger to .001
  14. Assign an unused material to the InvisibleTrigger.
  15. Set the transparency of the material to 1.
  16. Save your work and test the results!

VRML Script

door.wrl

Here's a simple world where I've modified (by hand) the VRML script produced by Spazz3D to alternately open and close the door.

If you look at the script, all that I'm doing is intercepting the TouchSensor event. I use a Boolean (TRUE/FALSE) variable to remember whether the door should be opened or closed.

The first time, the value is true, and the current time is sent to the openDoor TimeSensor to start its animation. The next time the TouchSensor is clicked, the Boolean variable is changed to false, and the current time is sent to the closeDoor TimeSensor to start its animation. Don't be intimidated by VRML script - it's not much more difficult to learn than HTML,and it gives you much more control over the worlds you create.

#VRML V2.0 utf8
WorldInfo {
 title "Spazz3D"
 info [
  "This VRML World was created with Spazz3D, a VRML 97 authoring tool"
  "www.spazz3d.com"
 ]
}
DEF dad_GROUND Transform {
 children [
  DEF GROUND Group {
   children [
    DEF dad_doorGroup Transform {
     translation -0.5 0.0 0.0
     children [
      DEF doorGroup Group {
       children [
        DEF dad_door Transform {
         translation 0.5 0.0 0.0
         children [
          DEF door Shape {
           appearance Appearance {
            material DEF Red_mat Material {
             ambientIntensity 0.200
             shininess 0.200
             diffuseColor 1.0 0.0 0.0
            }
           }
           geometry Box {
            size 1.0 2.0 0.05
           }
          }
         ]
        }
        DEF Sensor1 TouchSensor {
        }
       ]
      }
     ]
    }
   ]
  }
 ]
}
DEF openDoor TimeSensor {
 cycleInterval 2.000
 loop FALSE
 startTime  -1
}
DEF openDoor_rot0 OrientationInterpolator {
 key [
  0.0 1.0 
 ]
 keyValue [
  0.0 1.0 0.0 0.0
  0.0 1.0 0.0 1.571
 ]
}

DEF closeDoor TimeSensor {
 cycleInterval 2.000
 loop FALSE
 startTime  -1
}
DEF closeDoor_rot0 OrientationInterpolator {
 key [
  0.0 1.0 
 ]
 keyValue [
  0.0 1.0 0.0 1.571
  0.0 1.0 0.0 0.0
 ]
}

#theScript
DEF ToggleDoor Script {
  field  SFBool  state FALSE  
  eventIn  SFTime toggle
  eventOut SFTime startClose
  eventOut SFTime startOpen
  url "vrmlscript:
 function toggle(curtime) {
  state = !state;
  if (state) {
    startOpen = curtime;
    startClose = -1;
  }
  else
  {
    startOpen = -1;
    startClose = curtime;
  }
 }
 "
}

ROUTE Sensor1.touchTime            TO ToggleDoor.toggle
ROUTE ToggleDoor.startClose        TO closeDoor.startTime
ROUTE ToggleDoor.startOpen         TO openDoor.startTime
ROUTE openDoor.fraction_changed	   TO openDoor_rot0.set_fraction
ROUTE openDoor_rot0.value_changed  TO dad_doorGroup.set_rotation
ROUTE closeDoor.fraction_changed   TO closeDoor_rot0.set_fraction
ROUTE closeDoor_rot0.value_changed TO dad_doorGroup.set_rotation

Do you have some better ideas for opening/closing doors? Send them to Epistomolus, and I'll add them to this page.


Back to Creating Objects for Cybertown


Send your comments on this page to Epistomolus.

Updated February 23, 2007