📄 ch20.htm
字号:
if (($d eq "right") &&
($p[$me]{'xpos'} == 28)) {<BR>
} elsif ($d eq "right") { $p[$me]{'xpos'}++;
}<BR>
if (($d eq "left") &&
($p[$me]{'xpos'} == 1)) {<BR>
} elsif ($d eq "left") { $p[$me]{'xpos'}--;
}<BR>
}<BR>
<BR>
if ($a = $FORM{'a'}) { #
If attacking,<BR>
$I = 0; #
Find id number of target<BR>
while ($p[$I]{'name'} ne $a) { $I++; } #
and store it in $I.<BR>
<BR>
# Now calculate the distance between the
players (using the<BR>
# Pythagorean theorem.) The maximum range
is (arbitrarily) sqrt(50)<BR>
# (Which is just above 7.)<BR>
$dis = abs(sqrt(abs($p[$I]{'xpos'}**2
+ $p[$I]{'ypos'}**2)) -<BR>
sqrt(abs($p[$me]{'xpos'}**2
+ $p[$me]{'ypos'}**2)));<BR>
<BR>
# If the player are out of range, set
a message.<BR>
if ($dis**2 > 50) {<BR>
$message = "$p[$I]{'name'}
is out of range!<br>\n";<BR>
} else {<BR>
# If they are in range, give them a 50-50
chance of hitting.<BR>
$roll = int(rand(100))
+ 1;<BR>
# If they miss, set a message.<BR>
if ( $roll <
50 ) {<BR>
$message
= "You missed $p[$I]{'name'}<br>\n";<BR>
} else {<BR>
# If they hit, set a message, add the
attackers name to the target's<BR>
# list of attackers, and decrement the
target's hit points.<BR>
$message
= "You hit!\n";<BR>
$p[$I]{'mes'}
= "$me,";<BR>
$p[$I]{'hp'}-;
<BR>
}<BR>
}<BR>
}<BR>
<BR>
# Now we actually print the game page. The "cage"
itself is done in a<BR>
# 30x15 table, bordered with '*'s. Enemies are presented by their
id number<BR>
# in a link which initiates attack. The player himself is represented
by<BR>
# an asterisk.<BR>
<BR>
print "<HTML><HEAD><TITLE>The Cage</title></head><BODY><TABLE
BORDER=0>\n";<BR>
for ($y = 0; $y < 15; $y++) {<BR>
print "<TR>\n";<BR>
for ($x = 0; $x < 30; $x++) {<BR>
for ($I = 0; $I
<= $n; $I++) {<BR>
if
(($x == $p[$I]{'xpos'}) && ($y == $p[$I]{'ypos'})) {<BR>
if
($I == $me) { $c = "*"; }<BR>
else
{<BR>
$c = "<A HREF=\"cage.cgi?name=$p[$me]{'name'}&pass=$p[$me]{'name'}&a=$p[$I]{'name'}
<BR>
Â\">$I</a>";<BR>
}
<BR>
}
<BR>
}<BR>
if ($c eq "")
{ $c = "&nbsp"; }<BR>
if (($x==0)||($y==0)||($x==29)||($y==14))
{ $c = "*"; }<BR>
print "<TD>$c</td>";
<BR>
$c = "";
<BR>
}<BR>
print "\n</tr>\n";<BR>
}<BR>
print "</table>\n";<BR>
<BR>
# Now print any message that may have been set above.<BR>
if ($message) { print $message, "<BR>"; }<BR>
# Then print the names of all recent attackers.<BR>
foreach $att (@atts) {<BR>
print "$p[$att]{'name'} hit you!<br>\n";
<BR>
}<BR>
# Print the player's hit points.<BR>
print "You have $p[$me]{'hp'} hit points left!<br>\n";
<BR>
print "</body></html>\n";<BR>
<BR>
# Now open the database and regenerate the entire thing. We must
rewrite<BR>
# all players, because we may have changed another player's hit
points.<BR>
open (P, ">state.dat");<BR>
for ($I = 0; $I <= $n; $I++) {<BR>
print P "$I:$p[$I]{'name'}:$p[$I]{'xpos'}:$p[$I]{'ypos'}:$p[$I]{'pass'}:$p[$I]
<BR>
Â{'hp'}:$p[$I]{'mes'}\n";<BR>
}<BR>
close P;<BR>
system ("rm statelock"); # Unlock database.</FONT></TT>
</BLOCKQUOTE>
<P>
And that's it. An entire multi-player Web game in less than 200
lines of Perl. Granted, it's not Mortal Kombat 5, but it has possibilities.
It also has a few notable areas that could be improved:
<UL>
<LI><FONT COLOR=#000000>The program completely violates namespace
by making the reference </FONT><TT><FONT FACE="Courier">$p[0..$n]</FONT></TT>
global. This is fairly easily rectified by returning a reference
to the entire <TT><FONT FACE="Courier">@p</FONT></TT> array instead
of <TT><FONT FACE="Courier">$n</FONT></TT>.
<LI><FONT COLOR=#000000>It's not turn based! Despite </FONT>all
the earlier talk of the advantages of a turn-based mechanism,
this game has no turns at all as it is. This means that all players
will be able to move and attack as fast as they can click the
mouse. This isn't a bad thing if all players are in the same room
using similar equipment. However, if one player is two feet from
the server and another is on another continent, problems will
arise. The Internet is not instantaneous (yet), and to make the
game fair, a turn-based mechanism is required. Fortunately, it
wouldn't be hard to add one to our sample game. One way to accomplish
this would be to queue moves. An extra stat could be added to
the database for move requested ("move left," "attack
Gary"). If a move already exists, further requests could
be ignored. Then at the beginning of each turn (every 10 seconds,
minute, or whatever), another script would run, probably as a
cron job or maybe a running daemon (cron is a UNIX program that
runs other programs at given time intervals, anywhere from once
every minute to once every year). This script would execute each
move (perhaps in random order) and then erase all moves to allow
a new turn to begin.
<LI><FONT COLOR=#000000>There is no player collision. This is
pretty trivial to implement by including a check for player positions
when checking for</FONT> the boundaries when a player moves.
<LI><FONT COLOR=#000000>Nothing happens when a player "dies."
As is, when a player drops below 0 hit points, he or she just
has negative hit points. Again, fixing this is trivial. If a player
with less than 1 hit point attempts to make a move, the script
could generate a "Game Over" page and erase that player
from the database.</FONT>
<LI><FONT COLOR=#000000>Security, security, </FONT>security. This
is an overriding concern for all CGI programs, especially those
dealing with databases. Perhaps you typed in the previous scripts,
and while they ran fine from the command line, they did nothing
when accessed from the Web. This is because most Web servers are
run as a user with minimal access rights to prevent security breaches
(usually user "nobody" on UNIX machines). This means
the server (and hence the CGI program run by the server) does
not have permission to modify the database. The easiest method
around this is to set the database with world writable permissions.
(On UNIX-like machines, the command is <TT><FONT FACE="Courier">chmod
o+w</FONT></TT>.) Now, however, any user on your machine can modify
(or even erase) the database. Because the name of the database
is not available from the game pages themselves, you could make
the database an obscure file in some obscure directory so that
it is unlikely to be found; but if someone is intent on breaking
the game, that is hardly going to stop them. In Perl, however,
there is another option (which is also available in one form or
another when using other languages). A module exists called CGIWrap
(<TT><FONT FACE="Courier"><A HREF="http://wwwcgi.umr.edu/~cgiwrap">http://wwwcgi.umr.edu/~cgiwrap</A></FONT></TT>).
This enables you to run your CGI program as the user who owns
the program. Therefore, the cage.cgi could be run as if it were
you, and then you could modify the database that is owned by you.
However, this creates another problem. Now that the CGI is being
run as if it were you, it has all the same permissions you do,
and as such it can modify (or delete) any file in your account.
You must, therefore, make absolutely sure that your script is
foolproof and can be used to access other files in your account.
More information on the security aspects of CGI can be found in
<A HREF="ch9.htm" >Chapter 9</A>, "Security."
</UL>
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Tip</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
Flags are your friends. One good way to check this is to run the script with the <TT><FONT FACE="Courier">-T</FONT></TT> flag in Perl. This turns on taint checking, which is designed to prevent such abuses of your script. In addition, always test Perl
scripts with the <TT><FONT FACE="Courier">-w</FONT></TT> flag before using them. This turns on Perl's warning mode that gives out helpful hints on any mistakes, or even just bad decisions, you have made. Having Perl spot goofs you might have made can save
hours of debugging for mistakes you have made.
</BLOCKQUOTE>
</TD></TR>
</TABLE></CENTER>
<P>
<P>
These are just the glaring problems. Many (if not most) of the
routines in the previous scripts could be made much more efficient
and less naive. Also, you can make many improvements by using
this game as a springboard:
<UL>
<LI><FONT COLOR=#000000>Add graphics! The </FONT>game does not
need to be this plain. Make tiny icons for the players and the
background. Instead of putting ASCII characters in the table,
put the appropriate icon in (using <TT><FONT FACE="Courier"><IMG
SRC="whatever"></FONT></TT>). This simple modification
improves the enjoyment of the game tremendously.
</UL>
<P>
<CENTER><TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>
<TR><TD><B>Caution</B></TD></TR>
<TR><TD>
<BLOCKQUOTE>
As of this writing, Mosaic (and possibly other browsers, as well) has problems with generating inline images within tables. Most other graphical browsers (including OmniWeb, Netscape, and Internet Explorer) do handle this correctly.</BLOCKQUOTE>
</TD></TR>
</TABLE></CENTER>
<P>
<UL>
<LI><FONT COLOR=#000000>Allow players to chat. Human </FONT>interaction
is the <I>raison d'etre</I> of multi-player games, and any Web
game worth its weight will have some capability to allow players
to exchange messages. (What would network DOOM be like without
the capability to hurl insults with your rockets?) This is a less
trivial mechanism to implement, but its importance is paramount.
Consider this (relatively) simple approach for implementing chatting
in our sample game:<BR>
Add extra fields in "con.cgi" that allow a player to
choose another player to talk to (perhaps by pull-down menu) and
another field for the player to type in a message.<BR>
"cage.cgi" must then place these messages into the database
(or maybe in another database). Each time the game screen is drawn,
the messages will be printed and then erased from the database.
</UL>
<P>
This is just the beginning of what you can do with this game.
Slight modifications in the idea could produce entirely new games.
Perhaps there could be another database that includes coordinates
of obstacles (some that block movement, some that block attacks,
some that do both). Maybe a goal could be included (the player
must reach a certain coordinate while preventing other players
from doing the same).
<P>
In this chapter, we have used Perl exclusively to create our programs.
This is not to say that it could not be done in other languages.
Perl's text-handling routines are superb, but C's speed can be
vital. If you are working on a Windows machine, perhaps Visual
Basic or C++ is all that is available. The sample Perl scripts
here are not magical; you could write equivalent programs in any
CGI language-even "sh" (the exact implementation is
left as an exercise for the reader).
<H2><A NAME="Summary"><FONT SIZE=5 COLOR=#FF0000>Summary</FONT></A>
</H2>
<P>
With the tools in this chapter as a springboard, there is an entire
world of possibility when using CGI to design multi-player games
for the Web. Take a look at what's out there (and don't limit
yourself to multi-player games, either). Plan out your game and
make an outline. Test your game on as many browsers as possible,
and beware of performance issues. Take care to make your game
secure, especially if you are using databases.
<P>
Finally, when considering the capabilities of the Web with respect
to gaming, don't ignore the non-CGI alternatives available. Java
has become a popular platform for gaming because of its graphical
capabilities. However, Java does come with a whole bag full of
security concerns, so use it with caution. Macromedia Shockwave
is another environment that allows you to be very flashy and graphical,
but its multi-user capabilities are limited. Finally, Penguin,
a new module for Perl, promises to enable Perl code to be executed
securely on remote machines. This opens the door for Web games
that maintain stable connections with servers and other players,
allowing for the real-time interaction that will really bring
Web multi-player games to the next level.
<P>
<HR WIDTH="100%"></P>
<CENTER><P><A HREF="ch19.htm"><IMG SRC="pc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="#CONTENTS"><IMG SRC="cc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="index.htm"><IMG SRC="hb.gif" BORDER=0 HEIGHT=88 WIDTH=140></A><A HREF="ch21.htm"><IMG
SRC="nc.gif" BORDER=0 HEIGHT=88 WIDTH=140></A></P></CENTER>
<P>
<HR WIDTH="100%"></P>
</BODY>
</HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -