Designing Web Games in Flash

Download Report

Transcript Designing Web Games in Flash

Designing Web Games
in Flash
Scott Kim, scottkim.com
Game Developers Conference 2001
Given as part of Gary Rosenzweig’s day-long tutorial on Shockwave Games
Win Win
Over the last year I have built 30 games in Flash 4. In this talk I will describe how I built a game called “Win Win”. Usually I work with
other people who do art and programming, but in this case I did the programming and most of the art myself. The goal here is to move
both balls onto both stars simultaneously. Pressing an arrow key causes both balls to move one square in that direction. You don’t want to
fall into a hole or off the edge of the board. If a ball hits a wall it won’t roll any further, but the other ball may still be able to move.
For MentalWorkout.com
I built Win Win for mentalworkout.com, which was launched as part of an ad campaign that ad agency TMP Worldwide is doing for the
business consulting company Cambridge Technology Partners (recently acquired by Novell). If you go to the site, you can download a
copy of this game. My Flash game was embedded in a larger Director program to make a stand-alone Director projector.
Based on Double Maze
Win Win is based closely on an earlier game I designed for the Segasoft web site.
Why Flash?
Runs everywhere (vs. Director)
 Graphic (vs. Java)
 Programming (vs. HTML)
 Flash 5 has better programming
environment

Although Shockwave is more capable than Flash, Flash has a huge advantage in compaitibility — something like 90% of all browsers
support Flash, making it even more compaitble than Java. Flash isn’t great for action games, but puzzle games don’t need speed.
Flash 4
No arrays. Use interpreted variable names:
FLASH 4: Set Variable: “array” & “4” = 0
FLASH 5: array[4] = 0
 Movie clips act like objects.

Flash 5 has a much better programming environment than Flash 4, but I’ll be showing you examples built in Flash 4. I’ve modified the
programming langage a bit to make it easier to read (and much more like Flash 5 syntax).
Programming Techniques
1. Data Structures
2. Event Loop
3. Parsing a Text Field
4. Scripted Motion
5. Falling Ball
6. Undo
7. Scoring
8. Art, Sound, Interaction
9. Variation
Here are the techniques I used to build Win Win. Let’s look at them one at a time.
1. Data Structures: Cells
Win Win is played on two side-by-side square board. Each board has holes and walls. To represent a board I used three arrays of movie
clips, one array each for the cells, horizontal walls, and vertical walls. There are two copies of each array, for the Left and Right boards.
The two arrays that represent cells, LC and RC, which are indexed 1 to 6 in the horizontal and vertical directions. Each cell can have one
of three possible states: Plain, Hole or Goal. In addition, the Ball is always located on a cell.
1. Data Structures: Cell Clip
Each cell is represented by an instance of a movie clip. This representation is space efficient, since every cell is an instance of the same
clip. Within each clip different frames show the object in each of its possible states, as shown above. To change the state of an object, I
send it a message to go to a different labeled frame. Using movie clips this way is a common trick in Flash.
1. Data Structures: Walls
There are also separate arrays that represent the vertical and horizontal walls at the edges of cells. Here are the arrays for the vertical
walls. Note that there are seven columns in the array, not six, since vertical walls can occur at either the left or right edge of a cell. There
are similar arrays for the horizontal walls.
1. Data Structures: Flags & Sizes
Initialization:
finalScore = –1
theQuit = –1
moveNumber = 0
score = 0
penaltyFlag = False
winFlag = False
Frames in Cell clip
frameOn = 5
frameHole = 6
frameGoal = 10
Grid position, spacing
Lx0 = 59
Ly0 = 58
dx = 36
dy = 36
Rx0 = Lx0+(6*dx)+dx
Ry0 = Ly0
Here are the main variables set in the Initialization routine. The Win Win game, written
in Flash, is embedded in an enclosing program, written in Director, which navigates
between different games and keeps track of scores. The Flash program tells the Director
program that it is done executing by setting the variable theQuit to 1, and setting the
variable finalScore to the score.
The moveNumber keeps track of which move the player is currently on. Normally
moveNumber increases by one every time the player moves. When the player undoes a
move, moveNumber decreases by 1. The score increases by one every time the player
makes a move, just like moveNumber. But the score never decreases: when the player
undoes a move the score increases by 1, and when a ball falls into a hole, the score
increases by 5, as a penalty.
The two flag variables penaltyFlag and winFlag are are set True when certain
conditions occur, in order to let the main event loop know what to do. Finally there are
six variables that keep track of the positions and spacing of the board grids. This makes
it easy to reposition the boards without having to change numbers in many places.
2. The Event Loop
As in most games, the main control structure is an event loop that waits for user input, then does an action based on the input. The main
loop checks to see if the game has been won, or if the ball has fallen off the board, requiring a penalty. In either of these cases it invokes
the appropriate subroutine. Events are initiated when the user either types an arrow key or clicks an arrow button. The script decides how
each ball should move, then updates the ball positions. RecordPosition stores each board position in a list by move number, so Undo can
go back to an earlier position. Finally, there are scripts for the Restart, Undo and Quit buttons.
3. Parsing a Text Field
Loop While (v<=6)
If (v>0)
Call ("ParseVWallRow")
End If
Call ("ParseHWallRow")
End Loop
Most puzzle games need a way of specifying opening position. In a conventional programming language you can do this by initializing the
values in your main data structure. In a graphic authoring tool like Flash you can do this by arranging objects directly on the screen. For
most of my games I prefer to specify a gameboard through an ASCII text file that makes it easy for me to create a position by typing it in.
Here the text file is actually a text field positioned off-screen to the right. You can see this field during authoring, but not during playback.
This requires a bit of programming that reads the values in the text file and positions objects accordingly. As long as you assume that the
syntax of the text field is exactly right, it is easy to write a parser.
3. Parsing a Text Field: one row
GOAL:
If (Substring(s,n,1) eq "G”)
Begin Tell Target (LC[h,v])
Go to and Stop ("Goal")
End Tell Target
LGoalh = h
LGoalv = v
BALL:
Else If (Substring(s,n,1) eq "B")
Set Property (LBall, X Position) =
Lx0 + (h-1)*dx
Set Property (LBall, Y Position) =
Ly0 + (v-1)*dy
Lh = h; Lv = v
HOLE:
Else If (Substring(s,n,1) eq "H")
Begin Tell Target (cellName)
Go to and Stop ("Hole")
End Tell Target
EMPTY:
Else If (substring(s,n,1) == " ")
Begin Tell Target (cellName)
Go to and Stop ("Plain")
End Tell Target
Here is the script that processes an individual row of vertical walls and cells. The possible symbols that can occur in such a row are:
| = vertical wall
G = goal
B = ball
H = hole
Note that a ball cannot start off on a hole or goal cell.
4. Scripted Motion: Move Right
Decide Move Types when action is Move Right:
If (GetProperty (LV[Lh, Lv], _currentframe) = frameOn)
Lmove = "bounce"
Else If ((GetProperty (LC[Lh+1, Lv], _currentframe) = frameHole)
OR Lh=6)
Lmove = "fall"
Else
Lmove = "move"
End If
End If
Most animators create motion in Flash (or Director) by putting objects in different positions on different key frames. That works fine as
long as the motion is always the same. For interactive games, it is better to drive the motions from a script. Here I store the X,Y positions
of the two balls in variables, then update the positions whenever a cursor key is pressed. Note that I invoke different motions depending on
whether there is a wall to the right. I could have made the animation of a ball sliding from one square to the next last several frames, but
that can make the game feel sluggish, especially on slower computers. So instead I made the ball pop instantaneously to the next position,
and relied on the sound to create the illusion of motion.
4. Scripted Motion: Wall? Hole?
Bounce:
If (Lmove == "bounce")
Begin Tell Target ("/sounds")
Go to and Play ("Bounce")
End Tell Target
Move:
Else If (Lmove == "move")
Lh = Lh+1
Begin Tell Target ("/sounds")
Go to and Play ("Move")
End Tell Target
Fall:
Else If (Lmove == "fall")
Lh = Lh+1
Begin Tell Target (Lball)
Go to and Play ("Fall")
End Tell Target
penaltyFlag" = True
Do after everything else:
Call ("UpdateBalls")
Call ("CheckWin")
Here is the code that actually resets Lh, which determines the horizontal position of the ball. The actual object position is updated in the
subroutine “UpdateBalls”.
5. Falling Ball
When a ball goes off the edge or into a hole it falls off the board. Originally I thought I would have to animate the ball so it would pass
behind part of the board. Depending on where it fell, it would pass behind different parts of the board. Rather than have lots of special
cases, I decided to use a visual trick that avoids the problem of deciding what should pass behind what. There is just one animation of the
ball falling. The animation stays entirely within a square, so it never needs to pass behind part of the board. Instead of travelling down and
to the right a great distance, the ball shrinks and fades to the background color as it moves a tiny distance down and to the right. Together
with the sound effect, this creates the illusion of a falling ball.
6. Undo
RecordPosition:
Undo:
oldLh[moveNumber] = Lh
oldLv[moveNumber] = Lv
oldRh[moveNumber] = Rh
oldRv[moveNumber] = Rv
moveNumber = moveNumber+1
score = score+1
If (moveNumber>0)
moveNumber = moveNumber–1
score = score+1
Lh = oldLh[moveNumber]
Lv = oldLv[moveNumber]
Rh = oldRh[moveNumber]
Rv = oldRv[moveNumber]
Call ("UpdateBalls")
Else
Go to and Play ("Play")
End If
The Undo button lets players back up as many moves as they want. To do this I created an array that records the positions of the two balls
on each move. When the player presses the Undo button, the game resets the balls to that position. Note that the score is NOT reset.
7. Scoring
Penalty:
Score:
INITIALLY: 0
MOVE: add 1
UNDO: add 1
FALL: add 5
moveNumber = moveNumber-1
score = score+5
penaltyFlag = False
Lh = oldLh[moveNumber]
Lv = oldLv[moveNumber]
Rh = oldRh[moveNumber]
Rv = oldRv[moveNumber]
Call ("UpdateBalls")
Since players can compete for prizes on mentalworkout.com, I need a way of scoring the game. I wanted a scoring system that would
make it hard to achieve the best possible score, so everyone’s scores wouldn’t tend to cluster on the same best number. Here, the score is
the number of moves you take to reach the goals. Lower scores are better. Note that you are penalized five points for falling into a hole,
but allowed to continue playing. Players normally have to play a Win Win puzzle many times before achieving the best score.
To implement this scheme I have two variables: moveNumber = Increases when you make a move, decreases on Undo, score = Always
increases. +1 on undo, +5 on fall into a hole
7. Scoring: animated penalty
If a ball falls off the edge of the board or into a hole, the balls are put back where they belong, and a 5-point penalty is added to the score,
instead of restarting the game. To make sure the player understood what was happening on a penalty, I carefully animated a “+5” crashing
into the score after a ball fell. The animation is designed to catch the player’s attention, and explain what is happening.
8. Art, Sound: color palette
Programming isn’t the only skill that goes into building a game. Art, sound design and writing matter too. Even if you don’t do them
yourself, it is important to understand their importance. I created the art myself in Illustrator, then imported it into Flash. The colors are
based on a color palette given to me by the art director. Note how different the effect is from the original game Double Maze. I change the
art both to avoid copyright infringement (copying art or the name of a game is generally illegal), and to fit the look of the ad campaign.
8. Art, Sound: walls
One of the main art issues was how to represent the walls. I needed walls that looked three dimensional, yet (for convenience of
programming) never blocked the balls. I used a technique common in computer game art: beveled walls that are light one one side and
dark on the other. Another approach, used by the game Mummy Maze (popcap.com), is to use short shadows. Most of the sounds were
given to me by the client. I spent a good deal of effort editing the sounds in Soundedit to get them to be just the right length and have the
right impact. A few sounds, like the sound of the ball sliding, I created from scratch. I chopped an abrasive sound out of a longer sample,
filtered it, and reversed it in time to get the start of the sound. Good user interface design is critical in building a game. I have redundant
controls that let you play the game with either the keyboard or mouse, since different players prefer one or the other. An important issue is
responsiveness: nothing is more frustrating to a player than having to wait for the screen to update after making a move.
9. Variation: Convergence
One of the secrets of surviving in this business is to steal from yourself as much as possible. Here is a puzzle I built for NewMedia.com
shortly after building Win Win. The graphics, sounds and themes are different, and the rules are slightly different (three objects on one
board, vs. two objects on two boards), but most of the code is the same.
9. Variation : Tilt Maze
Another maze that uses similar rules is Tip Mazes by Andrea Gilbert She built this game in Java, as part of her highly original maze site
clickmazes.com.
Conclusions
FlashScript is a full programming language
 Tips: clips as objects, parsing text field
 Strategy: re-usable puzzle engine
 For the notes from this talk, see
www.scottkim.com
