PITCHER PERFECT: A GAME IN TWO MOVIES

This game provides an example of capturing user data, writing it to a file, and reading it back in. The first movie provides a login, displays top scores of previous users, and launches the second movie. The second movie provides gameplay and records the user's score.

File IO in Lingo

File input/output is handled by an Xtra in Lingo. An Xtra is simply a pre-compiled library of functions that can be called from within your Lingo program. Some Xtras are developed by Macromedia and ship with the program, and some are developed by third parties to extend the features of Director (for example, to control serial ports). To use an Xtra in your program, you must first create an Xtra instance with the new function. The result of this function is assigned to a variable, which can then be used when calling functions defined by the Xtra. For example, this statement creates an instance of the fileio Xtra, and assigns it to a file pointer variable (fp):

set fp = new (xtra "fileio")

Once you have an instance of that Xtra, you can get a listing of the functions that it supports with the interface function. For example, to see the fileio functions supported, you would type:

put interface(xtra "fileio")

You can use the put command in the Message window in Director to view the Xtra methods. These are the functions supported by fileio. In each case the function name is listed first, followed by the arguments that it expects and their types. Use the instance variable (e.g. fp) instead of "object me".


The PitchIntro Movie:

Set Key Down Script, and Display Scores from an External File:

on startMovie

-- RETURN key accepts name, goes to PitchaNoHitta

set the keyDownScript to "myKeyDown"

-- Get top 5 scores, print to field

put printTopScores(5) into field "best scores"

end startMovie


Clear Username Field:

on enterFrame
put EMPTY into field "username"
end


Key Down Script:

on mykeyDown
global gUsername
if the keyPressed = RETURN then
if field "username" = EMPTY then
alert "You must enter a name before you can begin"
else
set gUsername = field "username"
sound stop 1
go to movie "PitchaNoHitta.dir"
end if
end if
end keyDown


Printing Top Scores:

The printTopScores handler reads data from a file where the scores have been kept. It then returns the top N scores.

The first part of this handler opens a file called pitch.txt (for reading only). The handler then copies the file's entire contents to a string called scorefile. Some error checking is done, to make sure the file is OK.

The next part of this handler creates a property list, topscores, containig all the scores and names stored in the file. In the file, and therefore also in scorefile, each line has a name and a score. The last word on the line is the score; this will be used as the property. All the other words on the line are considered to be part of the name; these form a string which is the value of the property. The handler goes through scorefile line by line, creating a property:value pair for each. A call to sort(topscores) rearranges the property:value pairs in ascending order, so that the lowest score is the first on the list, and the highest score is the last on the list.

The last step is to create a string (returnstring) listing the top N players and their scores. Starting at the highest score and ending with the Nth highest score (lowestrecord), the handler writes out N lines of text containing each name and the score that they got.

-- printTopScores
-- handler to return string listing top N scores
-- read from file "pitch.txt"
-- where N is the parameter
on printTopScores n

set filename = the pathName & "pitch.txt" -- file where we store scores

-- initialize a file pointer called fp

set fp = new (xtra "fileio")

-- open the file for reading (read mode = 1)

openFile (fp, filename, 1)

if status(fp) <> 0 then -- can't open file
-- print a message then return
alert "Error opening " & filename
return EMPTY -- failed to read from file
end if

-- read in the entire file (much more efficient than line-by-line)

set scorefile = readFile (fp)

-- close the file

closeFile (fp)

-- put scores into property list (associative array) where
-- score = property, name = value

set topscores = [:] -- initialize empty property list

set numberofrecords = the number of lines in scorefile

repeat with i = 1 to numberofrecords -- loop through all lines from file
set thisline = line i of scorefile
set numberofwords = the number of words in thisline
set thisproperty = the last word in thisline -- the score
set thisvalue = word 1 to (numberofwords - 1) of thisline -- the username
addProp topscores, thisproperty, thisvalue -- add a new item to the list
end repeat

-- sort on the scores (ascending order by default)

sort topscores

-- put top N scores into returnstring

set returnstring = EMPTY

set lowestrecord = (numberofrecords - N + 1) -- lowest # record in top N scores
if (lowestrecord < 1) then -- make sure this is a valid record #
set lowestrecord = 1
end if

repeat with i = numberofrecords down to lowestrecord -- loop through last N records in property list
set thisscore = getPropAt(topscores, i) -- score is the property of this item
set thisname = getAt(topscores, i) -- name is the value of this item
put thisname & SPACE & thisscore & RETURN after returnstring
end repeat

return returnstring -- success!

end printTopScores


The PitchaNoHitta Movie:

Click here to see the Pitch.dcr file.

Declaring and Initializing Global Variables:

on enterFrame
global gPitch
set gPitch = 1
put gPitch into field "pitch#"
global gScore
set gScore = 0
put gScore into field "strike#"
global gOut
set gOut = 0
put gOut into field "out#"
end


Game Play and Keeping Score:

global gPitch
on exitFrame

if sprite 7 intersects 5 and the visible of sprite 7 = TRUE then
go the frame + 1
else
go the frame
end if

on mouseDown
if the mouseH > 64 and the mouseH < 192 and the mouseV > 192 and the mouseV < 256 then
set the visible of sprite 7 to TRUE
set gPitch = gPitch + 1
put gPitch into field "pitch#"
else
set the visible of sprite 7 to FALSE
end if

end


Calculating the Accuracy of the Pitcher & Branching:

global gScore
global gOut
global gAccuracy
global gPitch
on exitFrame
set gScore = gScore + 1
put gScore into field "strike#"
if gScore = 3 then
set gOut = 1
put gOut into field "out#"
else
if gScore = 6 then
set gOut = 2
put gOut into field "out#"
else
if gScore = 9 then
set gOut = 3
put gOut into field "out#"
end if
end if
end if
if gOut = 3 then
set Ratio = float(gPitch)/float(gScore)
set gAccuracy = 100.0/Ratio
put integer(gAccuracy + 0.5) into field "accuracy"
saveScore
go frame 9
else
go frame 2
end if

end


Saving the Latest Score

When the player has finished a game, his or her score is added to the pitch.txt fileby the saveScore handler.

The first step is to open the file for writing only. If the file is not found, a new one is created. Again, error checking is done to avoid writing to an illegal space.

We then find the end of the current file (using flen = getLength(fp)), and have the file pointer point there (using setPosition (fp, flen)). This allows us to write the new score at the end of the file, without overwriting the data that is already there.

-- saveScore
-- handler to write the user's score to "pitch.txt"
on saveScore

global gUsername -- set in PitchIntro.dir
global gAccuracy -- % of pitches that are strikes

set filename = the pathName & "pitch.txt" -- file where we store scores

-- NOTE: to see what xtra methods are available, use
-- put interface(xtra "FileXtra")

-- initialize a file pointer called fp

set fp = new (xtra "fileio")

-- open the file for writing (write mode = 2)

openFile (fp, filename, 2)

if status(fp) <> 0 then -- can't open file

-- try to create file
createFile(fp, filename)

if status(fp) <> 0 then -- can't create file
-- print a message then return
alert "Error opening and creating " & filename
return -1 -- failed to write to file
end if

-- try to open file again
openFile (fp, filename, 2)

if status(fp) <> 0 then -- still can't open file
-- print a message then return
alert "Error opening " & filename
return -1 -- failed to write to file
end if
end if

-- have file pointer point to the end of the file

set flen = getLength(fp)
setPosition (fp, flen)

-- write out the score

set scorestring = gUsername & SPACE & integer(gAccuracy + 0.5) & RETURN
writeString (fp, scorestring)

-- close the file

closeFile (fp)

return 0 -- success!

end saveScore


Reset Game:

on mouseUp
global gAccuracy
set gAccuracy = 0
put EMPTY into field "accuracy"
go frame 1
end


Set Cursor:

on mouseDown me
cursor 290
end

on mouseUp me
cursor 260
end