I. Concept
This demonstration applies the simpler of the two techniques suggested earlier for simulating 3D perspective in a flat scene. I've added a maneuverable character who can be steered with the arrow keys. There's not much new here: you've already seen the perspective trick, the maneuverable character is mainly a refinement of the bi-directional fish last seen in our Virtual Fishtank, and the one new feature (animation) is done outside of Flash. Nonetheless here's an anatomy of the project if you're interested.
II. Architecture
The main movie is very simple: two layers, each with a single frame. The lower layer contains the background graphic, that simple grayscale gradient. The upper layer contains a single Movie Clip called "figure."
As I hinted, "figure" is a somewhat more highly evolved descendant of our old "fish"--it's a compound Movie Clip containing several subsidiary Movie Clips, each assigned to a layer and each given an instance name. The sub-clips are:
- stand
- walkAhead
- walkAway
- walkLeft
- walkRight
Except for "stand," which consists of a single image, each sub-clip contains 15 frames, each holding a PNG graphic exported from the modeling and animation program Poser. (If you're curious about Poser, see www.curiouslabs.com. The program is capable of much better picture quality. The images used here were rendered with very low-resolution Sketch settings in order to cut down on bandwidth. I also stepped the animation down from its native 30 fps, where it's quite smooth, to the present 15 fps.)
III. Scripting
The compound Movie Clip "figure" houses two handlers, one for load and the other for enterFrame. The load handler sets up some initial conditions and declares the following function:
function hideAll(){
this.stand._visible = false;
this.walkLeft._visible = false;
this.walkRight._visible = false;
this.walkAhead._visible = false;
this.walkAway._visible = false;
}
As you might guess, hideAll() is a utility function that makes all the sub-clips within "figure" invisible.
The enterFrame handler contains these lines, among others:
hideAll();
if(Key.isDown(Key.DOWN)){
if(this._y < 320){
turned = true;
this.walkAhead._visible = true;
this._y +=ySpeed;
}
else{
turned = false;
}
}
if(turned == false) this.stand._visible = true;
//adjust size to simulate perspective
adj = (this._y/400);
this._width = basicW*adj;
this._height = basicH*adj;
XSpeed = basicW*.0125;
YSpeed = basicH*.005;
The first line invokes hideAll(), blanking out all the sub-clips in "figure."
The if/else block reads one of the arrow keys, in this case Down, and does several things.
If it finds no key event, it sets the turned flag to false. As you can see in the line immediately following the if/else block, the sub-clip called "stand" is made visible if the character has not turned. That sub-clip contains a single, non-animated image showing the walker at rest.
If the Down key has been pressed, the rest of the code block comes into play. The code first asks whether "figure" is at some point less than 320 pixels from the top of the screen--this feature keeps the walker from strolling out of the lower part of the window. If we're safely within the window, the code does several things. First it sets the flag variable turned to true. Then it makes the sub-clip "walkAhead" visible, and changes the vertical position of "figure" by an increment stored in the variable YSpeed (to which we're coming).
For the sake of space I've omitted three other if/else blocks, one each for the Left, Right, and Up arrow keys. You should be able to figure out how they work.
The lines that begin with the comment about simulating perspective apply the simpler method for doing this, calculating a percentage from the ratio of current Y position to the total height of the screen, which is 400 pixels at full size. This percentage is then multiplied against the basicWidth and basicHeight variables (which are created in the load handler).
The amounts of vertical and horizontal change (YSpeed and XSpeed) are products of multiplication by two fractions. That means the apparent speed of the walker remains proportional to her position, so that she doesn't seem to be walking at 40 miles per hour when she's out near the horizon. You'll still notice a bit of unwanted speed change near the limits. That's because even when YSpeed becomes less than 1, the Flash player rounds its value to exactly one--Flash (and indeed your computer) can't draw fractional pixels. There are possible solutions to this problem, but they make the code considerably more complicated so I've left them out.
IV. Source file
The source file for this demonstration, Z-WalkerDemo.fla, can be found in MMShare/Z-Walker on Crow.
