Articles Archive
Articles Search
Director Wiki
 

Shockwave VR with a grip

December 6, 1999
by Jean-François Cloutier

As Quicktime VR and Java applets reproducing VR are more and more popular on the Internet, Shockwave developers need to look no further than Director and Lingo to reproduce an equivalent or even better version without using any Xtras or browser plugins. This article will show the basic principles to achieve such a Shockwave VR. And while we're at it, why not add a little something different like grabbing the image to move it around and simulating residual momentum to enhance our project.

The use of this technique can go much beyond the simple viewing of a large image. It could be used for some kind of never ending scrollable menus or simulate the roller motion of a slot machine. Interactivity could be taken much further by adding some clickable hot spots or even use Flash cast members with animated buttons, all of which I will not demonstrate here. The code used in this article is dot syntaxed, so it only works in Director 7.

Let's get started

We need a seamless graphic preferably very wide. A 360 degrees picture is a dream come true for this task but any left and right end seamless graphic can do the trick, you could make your own using Photoshop. For a quick start, you can use a color spectrum gradient. The first thing to do is to take note of your image's width and decide the stage size you want, it should be much less wider than your image. I suggest you pick a stage height smaller than your image in order to be able to allow vertical image movements also. Then modify your image in the following way : at one end of your image (say left end), copy a portion of your image exactly the width of your stage and paste it at the other end (see picture below).

It was seamless wasn't it? Now your new image's width should be that of the original image + the stage width. For memory issues, since the image is now very wide, I suggest you reduce the image colordepth as much as possible.

The infinite loop

What really happens when you move the image horizontally and one end of the image reaches the stage, is that it instantly jumps back or forward a precise number of pixels to bring the image exactly where it was at the other end. Since both ends are identical, the illusion is perfect. This precise number of pixels is, as you may have guessed, the width of the stage. See the little animation below, a slowed down simulation of what's happening. Well ok... not exactly what's really happening, but sort of.

The above animation was done using film loops, however, in the real thing, we will use Lingo in the form of a behavior to do it much more efficiently. We need to understand one more thing before moving on.

Momentum

The idea is to simulate the continuity of the movement we gave to the image after the mouse is released. Momentum is used as a metaphor here since no mass is involved, no vectorial velocity and no vectorial quantity called momentum is really calculated or used here. Now, we don't want the image to move in a direction forever when we let go, so we will introduce a friction coefficient to reduce the horizontal displacement over time.

The horizontal displacement will be measured each exitframe while we drag the image. Then, as soon as we stop dragging the image, if the horizontal displacement value is not equal to zero then the image should keep moving as long as there is some displacement value left. To keep things simple, vertical momentum will be omitted.

Let's define the behavior properties :

Property Comment
pMySprite Reference for sprite number
pMyMember Reference for member
pDragging Boolean, TRUE if the user is dragging
pClickOffset Point, difference between clickloc and sprite regpoint
pDisplacementH Integer, current horizontal displacement of image
pLastMouseLoc Point, remembers the last mouse location
pFriction Integer, friction coefficient to slow down image H movement
pHandCursor Boolean, for cursor management (optional)
pRegPointH Integer, image regpoint.locH
pRegPointV Integer, image regpoint.locV
pOriginalWidth Integer, width of the image before modification
pBottomLimit Integer, image lower locV limit

Some of the properties get their value from a dialog box when the GetPropertyDescriptionList handler is called and some others in a beginSprite handlers, both not shown in this article (so download the example movie). To let our image object know if it is being dragged, we will use a Boolean flag called pDragging toggled on mouse events :

on mouseDown me 
  pDragging = TRUE 
  pClickOffset = the clickLoc - pMySprite.loc 
  pLastMouseLoc = the clickLoc 
end 
on mouseUp me 
  pDragging = FALSE 
end 
on mouseUpOutSide me 
  pDragging = FALSE 
end 

When spinning the image, mouseUp events happen sometimes off the stage, thus the need to have a mouseupOutside handler. To avoid the repositioning of the regpoint of the image with the mouse, pClickOffset is used to take the offset with respect to the regpoint into account while we drag.

You really moved me!

To know the distance travelled, we first need to know the dragging start point, pLastMouseLoc will do just that and it will be refreshed each exitframe as the mouse is dragging the image around. Hence the horizontal displacement will be recalculated each exitframe. The exitframe handler is shown below :

on exitFrame me
  --------- the first part --------- 
  
  if pDragging then 
  -- Position image to the mouse while dragging
    
    pDisplacementH = mouseH() - pLastMouseLoc.locH 
    DisplacementV = mouseV() - pLastMouseLoc.locV 
    
    pLastMouseLoc.locH = mouseH()
    
  else if pDisplacementH <> 0 then 
  -- Not dragging but image still has some 
  -- pDisplacementH value to use
    
    DisplacementV = 0   
    -- No vertical momentum, DisplacementV = 0
    
    if pDisplacementH > 0 then 
      pDisplacementH = pDisplacementH - pFriction   
      if pDisplacementH < 0 then pDisplacementH = 0 
      
    else
      pDisplacementH = pDisplacementH + pFriction   
      if pDisplacementH > 0 then pDisplacementH = 0 
      
    end if
  end if
  
  --------- the second part ---------
  
  -- Check for boundaries and reposition image   
  if pDisplacementH <> 0 then  
    newlocH = pMySprite.locH + pDisplacementH
    if (newlocH < pRegPointH - pOriginalWidth ) then ¬
      newlocH = newlocH + pOriginalWidth
    if newlocH > pRegPointH then newlocH = newlocH ¬
      - pOriginalWidth  
    pMySprite.locH = newlocH
  end if
  
  if DisplacementV <> 0 then 
    newlocV = mouseV() - pClickOffset.locV
    if newlocV > pRegPointV then newlocV = pRegPointV
    if newlocV < pBottomLimit then newlocV = pBottomLimit  
    pMySprite.locV = newlocV
  end if
  
end exitframe

The first part of the exitFrame handler takes care of displacement variations and pseudo momentum. The second part takes care of the repositionning and the infinite loop effect by keeping track of the image boundaries, always ready to make the image jump if ever a right or left end is about to be displayed on the stage. DisplacementV is a local variable, since there is no vertical momentum, there is no need to have it remembered between exitFrames.

Take a look at this Shockwave VR example, go ahead and give it a good spin !

A sample movie is available for download in Mac (580K) or PC (504K) format. This is a Director 7 movie.

In this example the original image dimensions were 2100 x 310 pixels, while the stage is 400 x 240 pixels. So, the final image width is 2500 pixels (2100 + the stage width). To increase fluidity of movement, the frame rate is kept rather high, in this case 30 fps. The friction coefficient is set to 6 . To have a feel of grabbing something I like to use cursor 260 (open hand) and cursor 290 (closed hand) commands. The behavior parameter dialog box in the sample movie finds the original image width by means of simple calculations. It allows you to modify the friction coefficient and lets you decide if you want to use the hand cursors.

Conclusion

The basic principles behind the creation of a VR behavior were demonstrated in this article. A little image editing was necessary to achieve our goal. Some improvements and variations could be made and will be left for you to experiment. Please, let me know of any suggestions you might have while experimenting with this technique.

References

The creation of the behavior in this article was inspired by the some of the work of Jim Collins. The technote section of his website really got me started on this.

I first learned how to use dot syntax by reading Zac's "Director[7].syntax" article.

The nice Prague Castle Garden picture used in this article is from this Czechsite Travel Guide website. The 360 degrees pictures can be used for educational purposes. The author of the pictures is Albert Jindra.

I suggest reading Raman Pfaff's articles called "Bodies, Rest, and Motion" and "The physics of an elastic collision: Part 1" for his excellent description and lingo translation of physics quantities like velocity and momentum.

Jean-Fran&ccedil;ois Cloutier is a multimedia game developer at Kutoka Interactive, a Montreal based company. He previously worked as a math and physics teacher at highschool level. Since attending UCON 99, he fell in love with San Francisco. He can be reached at behave@videotron.ca .

Copyright 1997-2024, Director Online. Article content copyright by respective authors.