Third in a series of how to code articles. Demonstrating coding an Asteroids Clone game with various technologies. This example using Java, implementing as an application for multiple platforms.
In this article I have converted my Asteroids Clone code into Java. I am now publishing the source code here under the GNU General Public License License as a series of articles describing how to write code using various technologies.
The code here can be freely distributed, but only on the condition that a credit to Jason Birch is maintained in the source code files and running application.
The source code is broken down into the classes which make the application, in the tabs on the left of this article. The tabs are placed in order from the simplest classes to the more complex classes last. There is a commentary accompanying each source code file explaining how the code operates.
Compiled class files and audio files can be downloaded here:
To play, click on the game to set focus for the keyboard.
The keys to play are: Cursor left - Rotate left, Cursor Right - Rotate right, Cursor up Fire, Cursor down - Thrust, ' ' Hyperspace, 'F2' Start new game.
APPLET TAG
OBJECT TAG
EMBED TAG
Required Environment
To run a Java application, the Java Runtime Envionment (JRE) is required, which can be downloaded from java.com.
To develop Java applications, the Java Development Kit (JDK) is required, which can be downloaded from java.com.
Writing Code
Any text editor can be used to create and edit Java source code.
Compiling Code
Java code is compiled in an operating system command line console using the javac compiler, see tab for the file make.sh for an example of a generic compile command.
Distributing Application
Java can be run on many operating systems. A big advantage of Java is that the compiled classes from an environment, can be distributed to any environment, without needing to be compiled specifically for the environment.
The application .class files and supporting application files are copied into a directory on the target system. The target system can also be a web server.
Running Application
To run the application, the application class name is used as an argument to the java command line application. See the tab file asteroids.sh for an example of the command.
An application can also be run in a web browser. There are three ways to do this by using one of the following TAGS: APPLET, EMBED, OBJECT. See the tab file asteroids.htm for an example of these HTML TAGS.
To start a Java application, from a command line use the java command with the main class name as an argument. This can be placed in a shell script or batch file so the application can be started from a desktop or file browser.
REF: 1.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
java astroapp
To include a Java applet on a web page, the old method was to use an APPLET tag. This is no longer supported in some browsers, however a Java applet can still be displayed on a web page in an EMBED tag or an OBJECT tag. These new methods require a Java plug-in to be installed for the browser being used.
REF: 2.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
<HTML>
<HEAD>
<TITLE>Asteriods Java</TITLE>
</HEAD>
<BODY>
Click in Window To Set Focus For Keyboard.<BR>
F2 - New Game. Space - Hyperspace.<BR>
Up - Fire. Down - Thrust. Left, Right - Rotate.<BR>
<BR>
APPLET TAG<BR>
<APPLET ID="Application" CODEBASE="./" CODE="astroapp.class"
WIDTH="512" HEIGHT="400">
<PARAM NAME="BackgroundColour" VALUE="0"></PARAM>
</APPLET>
<BR>
<BR>
OBJECT TAG<BR>
<OBJECT classid="clsid:CAFEEFAC-0014-0002-0000-ABCDEFFEDCBA"
width="512" height="400" align="baseline"
codebase="http://java.sun.com/products/plugin/autodl/jinstall-1_4_2-windows-i586.cab">
<PARAM name="code" value="astroapp.class">
<PARAM name="codebase" value="./">
<PARAM name="type" value="application/x-java-applet">
<PARAM name="scriptable" value="true">
<PARAM NAME="BackgroundColour" VALUE="0"></PARAM>
No Java 2 SDK, Standard Edition v 1.4.2 support for APPLET
</OBJECT>
<BR>
<BR>
EMBED TAG<BR>
<EMBED type="application/x-java-applet" width="512" height="400"
align="baseline" code="astroapp.class"
codebase="./" pluginspage="http://java.sun.com/j2se/1.4.1/download.html">
<PARAM NAME="BackgroundColour" VALUE="0"></PARAM>
<NOEMBED>No Java 2 SDK, Standard Edition support for APPLET</NOEMBED>
</EMBED>
<BR>
</BODY>
</HTML>
To compile a Java application, on the command line use the command javac. Once compiled the Java application can be run in any environment without needing to be recompiled specifically for another environment. In a command line, from the directory where the source code resides, type:
javac *.java -classpath .
This will compile all Java source code files in the directory.
REF: 3.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
javac *.java -classpath .
java astroapp
A point class has been defined because it represents a point class in the win32 libraries on a Windows system. The application was originally written on a Windows system, so the conversion process to Java is simpler to integrate some elements by emulating the elements of the original Windows system.
REF: 4.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
public class point
{
public short x;
public short y;
}
A rect class has been defined because it represents a rect class in the win32 libraries on a Windows system. The application was originally written on a Windows system, so the conversion process to Java is simpler to integrate some elements by emulating the elements of the original Windows system.
REF: 5.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
public class rect
{
public long left;
public long top;
public long right;
public long bottom;
}
A win32 class has been defined because it contains functions in the win32 libraries on a Windows system. The application was originally written on a Windows system, so the conversion process to Java is simpler to integrate some elements by emulating the elements of the original Windows system.
REF: 6.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class win32
{
public static void Polyline(Graphics hdc, point Point[], short PointCount)
{
short Count;
for (Count = 0; Count < PointCount -1; ++Count)
{
hdc.drawLine(Point[Count].x, Point[Count].y, Point[Count+1].x, Point[Count+1].y);
}
}
}
In Java the application can run from the local operating system or from a web page. When running from the operating system a Window has to be created for the application. This class is required to inform the application when the user tries to close the Window, and the application needs to shutdown cleanly.
REF: 7.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.event.*;
public class winlisten extends WindowAdapter implements WindowListener
{
private static final long serialVersionUID = 1;
private boolean CloseFlag = false;
public void windowClosing(WindowEvent e)
{
CloseFlag = true;
}
public boolean getCloseFlag()
{
return CloseFlag;
}
}
The application displays information about itself to the user, when the user clicks with the right mouse button in the application Window. This class is a generic message dialog box which can be used for displaying information.
REF: 8.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class msgbox extends java.awt.Canvas
{
private static final long serialVersionUID = 1;
public final static int AUTO_SIZE = -1;
public final static int STYLE_MSGBOX = 0;
public final static int STYLE_PROGRESS = 1;
private final int MIN_XLEN = 10;
private final int MIN_YLEN = 10;
private final int X_FONT_SIZE = 6;
private final int Y_FONT_SIZE = 15;
private int Style;
private int xPos;
private int yPos;
private int xLen;
private int yLen;
private int ClickXPos;
private int ClickYPos;
private int Progress;
private int ProgressMax;
private String Title;
private String MsgText[];
public Dimension MinSize;
public msgbox()
{
setVisible(false);
xPos = 0;
yPos = 0;
xLen = MIN_XLEN;
yLen = MIN_YLEN;
Progress = 0;
ProgressMax = 100;
Title = "";
MsgText = null;
MinSize = new Dimension(MIN_XLEN, MIN_YLEN);
setBackground(new Color(0x00BBBBBB));
}
Java requires some methods of a parent class to be implemented in this class in order for Java classes to obtain information they require from this class.
REF: 8.1
public Dimension preferredSize()
{
return minimumSize();
}
public synchronized Dimension minimumSize()
{
return MinSize;
}
public void update(Graphics GC)
{
paint(GC);
}
Draw this classes content on the display when required.
Handle user initiated events such as mouse and key operations.
REF: 8.3
public boolean mouseUp(Event Evt, int x, int y)
{
if (Style == STYLE_MSGBOX && x > xLen-Y_FONT_SIZE-3 && y < Y_FONT_SIZE+5)
setVisible(false);
return true;
}
public boolean mouseDown(Event Evt, int x, int y)
{
ClickXPos = x;
ClickYPos = y;
return true;
}
public boolean mouseDrag(Event evt, int x, int y)
{
xPos -= ClickXPos-x;
yPos -= ClickYPos-y;
setLocation(xPos, yPos);
return true;
}
Allow application to set the values required for the dialog.
REF: 8.4
public void Display(int NewStyle, String NewTitle, String NewMsgText[],
int NewXPos, int NewYPos, int NewXLen, int NewYLen)
{
int Count;
Style = NewStyle;
xPos = NewXPos;
yPos = NewYPos;
Title = NewTitle;
MsgText = NewMsgText;
if (NewXLen == AUTO_SIZE)
{
xLen = (X_FONT_SIZE * Title.length() + 1) + Y_FONT_SIZE + 9;
for (Count = 0; Count < NewMsgText.length; ++Count)
{
if ((X_FONT_SIZE * NewMsgText[Count].length() + 1) + 6 > xLen)
xLen = (X_FONT_SIZE * NewMsgText[Count].length() + 1) + 6;
}
}
else
xLen = NewXLen;
if (NewYLen == AUTO_SIZE)
yLen = Y_FONT_SIZE * (MsgText.length + 1) + 9;
else
yLen = NewYLen;
setVisible(false);
setLocation(xPos, yPos);
setSize(xLen, yLen);
setVisible(true);
}
public void Progress(int NewProgress, int NewProgressMax)
{
Progress = NewProgress;
ProgressMax = NewProgressMax;
}
}
This is a generic class to provide sound effects for an application. An application loads sound files when the application initializes with the Load member function, and then plays the sound files when required by passing the same file name into the Play member function.
REF: 9.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.net.*;
import java.util.*;
import javax.sound.sampled.*;
public class sound
{
private Hashtable Clips;
public sound()
{
Clips = new Hashtable();
}
public void Load(String Filename)
{
Clip ThisClip;
URL ThisURL;
AudioInputStream AudioFile;
try
{
ThisURL = this.getClass().getClassLoader().getResource(Filename);
AudioFile = AudioSystem.getAudioInputStream(ThisURL);
ThisClip = AudioSystem.getClip();
ThisClip.open(AudioFile);
Clips.put(Filename, ThisClip);
}
catch (Exception e)
{
}
}
public void Play(String Filename)
{
Clip ThisClip;
ThisClip = Clips.get(Filename);
if (ThisClip != null && !ThisClip.isRunning())
{
ThisClip.setFramePosition(0);
ThisClip.loop(0);
}
}
}
This is the class in the application which provides entry points to start the application.
REF: 10.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
/**********************************************************/
/* Compile: */
/* javac *.java -classpath . */
/* */
/* Execute from the command line: */
/* java astroapp */
/* */
/* Use the following HTML code to display this applet: */
/* */
/* <CENTER> */
/* <APPLET CODE="astroapp.class" WIDTH="512" HEIGHT="400">*/
/* </APPLET> */
/* </CENTER> */
/**********************************************************/
import java.awt.*;
import java.awt.event.*;
public class astroapp extends java.applet.Applet implements Runnable
{
private static final long serialVersionUID = 1;
private static winlisten AppWindowFlags = null;
private static asteroids AstroGame = null;
private static Thread Task = null;
private static boolean Abort = false;
This is the entry point when the application is started from a command line. It creates a Window, an instance of the application, which it then places in the Window. And then it starts a thread of execution to run the application.
REF: 10.1
/************************************************/
/* Start the application from the command line. */
/************************************************/
public static void main(String args[])
{
astroapp ThisApp = new astroapp();
GraphicsEnvironment GE;
GraphicsDevice[] GS;
GraphicsDevice GD;
GraphicsConfiguration[] GC;
Rectangle VirtualBounds = new Rectangle();
Rectangle AppWinBounds;
// System.out.println("DEBUG");
/**************************************/
/* Get information about the display. */
/**************************************/
GE = GraphicsEnvironment.getLocalGraphicsEnvironment();
GS = GE.getScreenDevices();
GD = GS[0];
GC = GD.getConfigurations();
VirtualBounds = VirtualBounds.union(GC[0].getBounds());
/*********************************/
/* Create an application Window. */
/*********************************/
Frame AppWindow = new Frame("Asteroids", GC[0]);
AppWinBounds = GC[0].getBounds();
AppWindow.setLocation(10 + AppWinBounds.x, 10 + AppWinBounds.y);
AppWindow.setResizable(false);
AppWindow.setSize(512, 400);
Panel AppPanel = new Panel();
AppWindow.add(AppPanel);
/**************************************************/
/* Add the application to the application Window. */
/**************************************************/
AstroGame = new asteroids(AppPanel, 0x000000);
AppPanel.setLayout(new BorderLayout());
AppPanel.add("Center", AstroGame);
AppWindowFlags = new winlisten();
AppWindow.addWindowListener(AppWindowFlags);
AppWindow.setVisible(true);
/****************************/
/* Animate the application. */
/****************************/
Task = new Thread(ThisApp);
Task.start();
}
This is the entry point for the application when placed in an HTML APPLET tag. It creates an instance of the application, places it on the web page and then starts a thread of execution to run the application.
REF: 10.2
/**************************************************/
/* Start the application from a web browser page. */
/**************************************************/
public void init()
{
int BackgroundColour;
BackgroundColour = Integer.valueOf(getParameter("BackgroundColour")).intValue();
setBackground(new Color(BackgroundColour));
AstroGame = new asteroids(this, BackgroundColour);
setLayout(new BorderLayout());
add("Center", AstroGame);
Task = new Thread(this);
Task.start();
}
There are a few member functions of a parent class which are required to be implemented in this class.
REF: 10.3
/**********************************/
/* Tell the application to close. */
/**********************************/
public void destroy()
{
if (Task != null)
Abort = true;
}
public void update(Graphics GC)
{
paint(GC);
}
public void paint(Graphics GC)
{
showStatus("(C) 2012 - Jason Birch Java Development");
}
This is the thread of execution for the application. It checks to see if the application should be shutdown, if not it tells the application to animate a frame every 1/50th of a second.
This class displays a numeric value like it was drawn on a vector arcade machine display.
REF: 11.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class classnumber
{
private final short DIGITS = 10;
private final short MAX_POINTS = 10;
private short xOffset;
private short yOffset;
private short Scale;
private long NumberValue;
private point Decimal[][];
private point DisplayFrame[][];
private point OldFrame[][];
public classnumber()
{
short Count;
short PointCount;
NumberValue = 0;
xOffset = 0;
yOffset = 0;
Scale = 0;
Decimal = new point[DIGITS][MAX_POINTS+1];
DisplayFrame = new point[DIGITS][MAX_POINTS+1];
OldFrame = new point[DIGITS][MAX_POINTS+1];
for (Count = 0; Count < DIGITS; ++Count)
{
for (PointCount = 0; PointCount < MAX_POINTS + 1; ++PointCount)
{
Decimal[Count][PointCount] = new point();
DisplayFrame[Count][PointCount] = new point();
OldFrame[Count][PointCount] = new point();
}
}
}
Draw the current numeric value of the class.
REF: 11.1
public void Draw(Graphics hdc)
{
int ColourPen;
int BackgroundPen;
short Digit;
short Count;
int Remainder;
long TempNumber;
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = 0x55DD55;
BackgroundPen = 0x000000;
hdc.setColor(new Color(BackgroundPen));
/*****************************/
/* Plot score current value. */
/*****************************/
TempNumber = NumberValue;
for (Digit = 0; Digit < 10; ++Digit)
{
Remainder = (int)(TempNumber - (((long)(TempNumber/10))*10));
// Remainder = (int)Math.IEEEremainder(TempNumber, 10);
TempNumber = TempNumber / 10;
for (Count = 0; Count < Decimal[Remainder][MAX_POINTS].x; ++Count)
{
DisplayFrame[Digit][Count].x = (short)(Decimal[Remainder][Count].x + xOffset
+ (10 - Digit) * 3*Scale);
DisplayFrame[Digit][Count].y = (short)(Decimal[Remainder][Count].y + yOffset);
}
DisplayFrame[Digit][MAX_POINTS].x = Decimal[Remainder][MAX_POINTS].x;
/*************************/
/* Erase previous score. */
/*************************/
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, OldFrame[Digit], OldFrame[Digit][MAX_POINTS].x);
/***************************/
/* Draw the current score. */
/***************************/
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, DisplayFrame[Digit], DisplayFrame[Digit][MAX_POINTS].x);
/***************************************/
/* Plot current score, */
/* next time it will be the old score. */
/***************************************/
for (Count = 0; Count < DisplayFrame[Digit][MAX_POINTS].x; ++Count)
{
OldFrame[Digit][Count].x = DisplayFrame[Digit][Count].x;
OldFrame[Digit][Count].y = DisplayFrame[Digit][Count].y;
}
OldFrame[Digit][MAX_POINTS].x = DisplayFrame[Digit][MAX_POINTS].x;
}
}
Set the initial values of an instance of the class and define the co-ordicates of digits 0-9 to be drawn.
Member functions to get and set the numeric value of this instance of the class.
REF: 11.3
public long GetNumber()
{
return NumberValue;
}
public void SetNumber(long NewNumber)
{
NumberValue = NewNumber;
}
}
This class displays a character string like it was drawn on a vector arcade machine display.
REF: 12.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class classtext
{
private final short MAX_LETTERS = 58;
private final short MAX_TEXT = 2048;
private final short MAX_POINTS = 12;
private final short INFINATE_FRAMES = -1;
private final short FALSE = 0;
private final short TRUE = -1;
private short xOffset;
private short yOffset;
private short Scale;
private int TextColour;
private short Visible;
private short LastVisible;
private short FlashVisible;
private short Active;
private short Frames;
private short FrameCount;
private short Flash;
private String TextString;
private point Letter[][];
private point DisplayFrame[][];
public classtext()
{
short Count;
short PointCount;
xOffset = 0;
yOffset = 0;
Scale = 0;
TextColour = 0x55DD55;
Visible = FALSE;
LastVisible = FALSE;
FlashVisible = FALSE;
Active = FALSE;
Frames = INFINATE_FRAMES;
FrameCount = 0;
Flash = FALSE;
Letter = new point[MAX_LETTERS+1][MAX_POINTS+1];
DisplayFrame = new point[MAX_TEXT+1][MAX_POINTS+1];
TextString = new String();
for (Count = 0; Count < MAX_LETTERS+1; ++Count)
{
for (PointCount = 0; PointCount < MAX_POINTS + 1; ++PointCount)
{
Letter[Count][PointCount] = new point();
}
}
for (Count = 0; Count < MAX_TEXT+1; ++Count)
{
for (PointCount = 0; PointCount < MAX_POINTS + 1; ++PointCount)
{
DisplayFrame[Count][PointCount] = new point();
}
}
}
Draw this instances character string.
REF: 12.1
public void Draw(Graphics hdc)
{
int ColourPen;
int BackgroundPen;
short Digit;
if (Active == TRUE)
{
/********************************************/
/* Display only for given number of frames. */
/********************************************/
if (FrameCount != INFINATE_FRAMES)
--FrameCount;
if (FrameCount == FALSE && Flash == TRUE)
{
FrameCount = Frames;
if (FlashVisible == FALSE)
{
FlashVisible = TRUE;
}
else
{
FlashVisible = FALSE;
}
}
else if (FrameCount == FALSE)
{
Active = FALSE;
}
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = TextColour;
BackgroundPen = 0x000000;
hdc.setColor(new Color(BackgroundPen));
/****************************/
/* Plot Text current value. */
/****************************/
for (Digit = 0; Digit < TextString.length()
&& TextString.charAt(Digit) != '\0'; ++Digit)
{
if (TextString.charAt(Digit) >= '!' && TextString.charAt(Digit) <= 'Z')
{
/************************/
/* Erase previous Text. */
/************************/
if (Active == FALSE || Visible == FALSE || FlashVisible == FALSE)
{
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, DisplayFrame[Digit],
DisplayFrame[Digit][MAX_POINTS].x);
}
else
/**************************/
/* Draw the current Text. */
/**************************/
{
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, DisplayFrame[Digit],
DisplayFrame[Digit][MAX_POINTS].x);
}
}
}
}
}
Initialize the values of this instance of the class. Also define the co-ordinates of ASCII characters from ! to Z.
Get or set the current visible state of the character string.
REF: 12.2
public void SetVisible(short NewVisible)
{
if (NewVisible != LastVisible)
{
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = TRUE;
FrameCount = Frames;
}
}
public short GetVisible()
{
return Active;
}
}
Asteroids game class defines the game objects to be used in the game.
REF: 13.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.applet.*;
import java.awt.*;
public class asteroids extends java.awt.Canvas
{
private static final long serialVersionUID = 1;
private final short TRUE = -1;
private final short FALSE = 0;
private final int MAX_XLEN = 512;
private final int MAX_YLEN = 400;
private final short START_ROCKS = 5;
private final short MAX_ROCKS = 100;
private final short HISCORE_XOFFSET = 40;
private final short HISCORE_YOFFSET = 20;
private final short GAMEOVER_XOFFSET = 90;
private final short GAMEOVER_YOFFSET = 20;
private final short INSERTCOIN_XOFFSET = 110;
private final short INSERTCOIN_YOFFSET = 20;
private final short HISCORE_SCALE = 3;
private final String AboutMsg[] = {"Asteriods Application",
"Version 1.01 Friday 16th March 2012",
"(C) Jason Birch Java Development"};
private Panel Application;
private msgbox ProgressBar = null;
private msgbox AboutBox = null;
private String Progress[] = {"Progress"};
private Image MainImage = null;
private sound AppSound = null;
private rect Desktop;
private astroship Ship;
private astroufo UFO;
private astrorock Rock[];
private short FirstRock;
private short NextRock;
private classnumber HiScore;
private classtext GameOver;
private classtext InsertCoin;
private boolean ThrustFlag = false;
private boolean RotateLeftFlag = false;
private boolean RotateRightFlag = false;
Game initialization can occur in two ways, from a web page or from an application. The only difference being the type of surface the application will draw onto.
The application loads the sound files it will be using into memory. Then it initializes the game objects it will be using.
REF: 13.1
public asteroids(Applet NewApplication, int BackgroundColour)
{
LoadApp((Panel)NewApplication, BackgroundColour);
}
public asteroids(Panel NewApplication, int BackgroundColour)
{
LoadApp(NewApplication, BackgroundColour);
}
private void LoadApp(Panel NewApplication, int BackgroundColour)
{
short Count;
AppSound = new sound();
AppSound.Load("Belt.au");
AppSound.Load("Credit.au");
AppSound.Load("HyperSpace.au");
AppSound.Load("Rock.au");
AppSound.Load("Shot.au");
AppSound.Load("Thrust.au");
AppSound.Load("UFO.au");
AppSound.Load("UFOShot.au");
Application = NewApplication;
setBackground(new Color(BackgroundColour));
AboutBox = new msgbox();
ProgressBar = new msgbox();
Application.add("Center", AboutBox);
Application.add("Center", ProgressBar);
ProgressBar.Display(msgbox.STYLE_PROGRESS, "Loading Please Wait...",
Progress, 0, MAX_YLEN-50, MAX_XLEN, 50);
MainImage = Application.createImage(MAX_XLEN, MAX_YLEN);
Desktop = new rect();
HiScore = new classnumber();
GameOver = new classtext();
InsertCoin = new classtext();
Ship = new astroship(AppSound);
UFO = new astroufo(AppSound);
Rock = new astrorock[MAX_ROCKS];
Desktop.left = 0;
Desktop.right = MAX_XLEN;
Desktop.top = 0;
Desktop.bottom = MAX_YLEN;
GameOver.SetLocation((short)((Desktop.right-Desktop.left)/2 - GAMEOVER_XOFFSET),
(short)((Desktop.bottom-Desktop.top)/2 - GAMEOVER_YOFFSET),
(short)5, (short)200, FALSE, "GAME OVER", 0x55DD55);
InsertCoin.SetLocation((short)((Desktop.right-Desktop.left)/2 - INSERTCOIN_XOFFSET),
(short)((Desktop.bottom-Desktop.top)/2 - INSERTCOIN_YOFFSET),
(short)5, (short)15, TRUE, "INSERT COIN", 0x55DD55);
HiScore.SetLocation((short)((Desktop.right-Desktop.left)/2 - HISCORE_XOFFSET),
HISCORE_YOFFSET, HISCORE_SCALE);
Ship.SetArea(Desktop);
UFO.SetArea(Desktop);
FirstRock = START_ROCKS;
NextRock = FirstRock;
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count] = new astrorock(AppSound);
for (Count = 0; Count < FirstRock; ++Count)
Rock[Count].SetArea(Desktop, (short)-1, (short)-1, (short)-1);
ProgressBar.setVisible(false);
}
Draw all active game objects.
REF: 13.2
public void update(Graphics GC)
{
paint(GC);
}
public void paint(Graphics GC)
{
short Count;
GC.drawImage(MainImage, 0, 0, this);
/*******************************/
/* Draw ship and rock objects. */
/*******************************/
InsertCoin.Draw(GC);
GameOver.Draw(GC);
HiScore.Draw(GC);
Ship.Draw(GC);
UFO.Draw(GC);
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count].Draw(GC);
}
Handle all user key and mouse events.
REF: 13.3
public boolean keyDown(Event Evt, int Key)
{
short Count;
if (Key == 1004)
Ship.Shoot();
else if (Key == 1005)
ThrustFlag = true;
else if (Key == 1006)
RotateLeftFlag = true;
else if (Key == 1007)
RotateRightFlag = true;
else if (Key == 32)
Ship.Hyperspace();
else if (Key == 1009)
{
if (Ship.GetLives() == FALSE)
{
if (Ship.GetScore() > HiScore.GetNumber())
HiScore.SetNumber(Ship.GetScore());
Ship.Reset();
UFO.Destroy();
UFO.GetShot().Destroy();
FirstRock = START_ROCKS;
NextRock = FirstRock;
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count].Destroy();
for (Count = 0; Count < FirstRock; ++Count)
Rock[Count].SetArea(Desktop, (short)-1, (short)-1, (short)-1);
}
}
return true;
}
public boolean keyUp(Event Evt, int Key)
{
if (Key == 1005)
ThrustFlag = false;
else if (Key == 1006)
RotateLeftFlag = false;
else if (Key == 1007)
RotateRightFlag = false;
return true;
}
public boolean mouseDown(Event Evt, int x, int y)
{
if ((Evt.modifiers & Event.META_MASK) != 0)
AboutBox.Display(msgbox.STYLE_MSGBOX, "About", AboutMsg,
80, 70, msgbox.AUTO_SIZE, msgbox.AUTO_SIZE);
return true;
}
Animate a frame of game play and check for object collisions.
REF: 13.4
public void DoFrame()
{
short RockFound;
short Count;
short ShotCount;
if (RotateLeftFlag == true)
Ship.IncAngle(FALSE);
else if (RotateRightFlag == true)
Ship.IncAngle(TRUE);
if (ThrustFlag == true)
Ship.Thrust();
Ship.Move();
UFO.Move();
RockFound = FALSE;
for (Count = 0; Count < MAX_ROCKS; ++Count)
{
if (Rock[Count].GetSize() != astrorock.INACTIVE)
RockFound = TRUE;
/*****************************/
/* Check for ship collision. */
/*****************************/
if (Ship.GetCrash() == FALSE
&& UFO.Collide(Ship.GetXOffset(), Ship.GetYOffset(),
Ship.GetWidth(), Ship.GetHeight()) == TRUE)
Ship.SetCrash(TRUE);
if (UFO.GetShot().Active() == TRUE
&& Ship.Collide(UFO.GetShot().GetXOffset(), UFO.GetShot().GetYOffset(),
(short)2, (short)2) == TRUE)
Ship.SetCrash(TRUE);
if (Ship.GetCrash() == FALSE
&& Rock[Count].Collide(Ship.GetXOffset(), Ship.GetYOffset(),
Ship.GetWidth(), Ship.GetHeight()) == TRUE)
{
Ship.SetCrash(TRUE);
Rock[++NextRock].SetArea(Desktop, Ship.GetXOffset(),
Ship.GetYOffset(), Rock[Count].GetSize());
}
/*************************/
/* Check for shot rocks. */
/*************************/
for (ShotCount = 0; ShotCount < Ship.GetShotCount(); ++ShotCount)
{
if (Ship.GetShot(ShotCount).Active() != FALSE)
{
if (UFO.Collide(Ship.GetShot(ShotCount).GetXOffset(),
Ship.GetShot(ShotCount).GetYOffset(),
(short)2, (short)2) == TRUE)
{
Ship.SetScore(Ship.GetScore() + 100);
Ship.GetShot(ShotCount).Destroy();
}
if (Rock[Count].Collide(Ship.GetShot(ShotCount).GetXOffset(),
Ship.GetShot(ShotCount).GetYOffset(),
(short)2, (short)2) == TRUE)
{
Ship.SetScore(Ship.GetScore() + 5*Rock[Count].GetSize());
Ship.GetShot(ShotCount).Destroy();
if (NextRock+1 < MAX_ROCKS)
Rock[++NextRock].SetArea(Desktop, Rock[Count].GetXOffset(),
Rock[Count].GetYOffset(),
Rock[Count].GetSize());
}
}
}
Rock[Count].Move();
}
if (RockFound == FALSE)
{
++FirstRock;
NextRock = FirstRock;
for (Count = 0; Count < FirstRock; ++Count)
Rock[Count].SetArea(Desktop, (short)-1, (short)-1, (short)-1);
}
if (Ship.GetLives() == FALSE)
GameOver.SetVisible(TRUE);
else
GameOver.SetVisible(FALSE);
if (GameOver.GetVisible() == FALSE && Ship.GetLives() == FALSE)
InsertCoin.SetVisible(TRUE);
else
InsertCoin.SetVisible(FALSE);
/******************************/
/* Display the current frame. */
/******************************/
repaint();
}
}
Rock objects have three sizes. Starting large, each time they are shot they divide by two and become smaller. The smaller the size, the faster the object tends to travel.
REF: 14.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class astrorock
{
private final short TRUE = -1;
private final short FALSE = 0;
private final short FRAMES = 3;
private final short FRAME_POINTS = 9;
private final short ROCK_WIDTH = 36;
private final short ROCK_HEIGHT = 36;
private final short ERASE = 3;
public static final short INACTIVE = 4;
private final short NEW_POSITION = -1;
private final short HYPERSPACE = -500;
private short xMax;
private short yMax;
private short Size;
private short xOffset;
private short yOffset;
private short xVelocity;
private short yVelocity;
private point Frame[][];
private point DisplayFrame[];
private point OldFrame[];
private sound AppSound;
public astrorock(sound NewAppSound)
{
short Count;
short FrameCount;
AppSound = NewAppSound;
Frame = new point[FRAMES][FRAME_POINTS];
DisplayFrame = new point[FRAME_POINTS];
OldFrame = new point[FRAME_POINTS];
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = 0;
yVelocity = 0;
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count] = new point();
OldFrame[Count] = new point();
for (FrameCount = 0; FrameCount < FRAMES; ++FrameCount)
{
Frame[FrameCount][Count] = new point();
}
}
for (Size = 0; Size < FRAMES; ++Size)
{
Frame[Size][0].x = (short)(-30 / (Size*Size+1));
Frame[Size][0].y = (short)(-22 / (Size*Size+1));
Frame[Size][1].x = (short)(-5 / (Size*Size+1));
Frame[Size][1].y = (short)(-32 / (Size*Size+1));
Frame[Size][2].x = (short)(+35 / (Size*Size+1));
Frame[Size][2].y = (short)(-17 / (Size*Size+1));
Frame[Size][3].x = (short)(+25 / (Size*Size+1));
Frame[Size][3].y = (short)(+28 / (Size*Size+1));
Frame[Size][4].x = (short)(+12 / (Size*Size+1));
Frame[Size][4].y = (short)(-2 / (Size*Size+1));
Frame[Size][5].x = (short)(+10 / (Size*Size+1));
Frame[Size][5].y = (short)(+28 / (Size*Size+1));
Frame[Size][6].x = (short)(-20 / (Size*Size+1));
Frame[Size][6].y = (short)(+33 / (Size*Size+1));
Frame[Size][7].x = (short)(-37 / (Size*Size+1));
Frame[Size][7].y = (short)(+5 / (Size*Size+1));
Frame[Size][8].x = (short)(-30 / (Size*Size+1));
Frame[Size][8].y = (short)(-22 / (Size*Size+1));
}
Size = INACTIVE;
}
Draw an instance of the object.
REF: 14.1
public void Draw(Graphics hdc)
{
short Count;
int ColourPen;
int BackgroundPen;
if (Size < INACTIVE)
{
ColourPen = 0x55DD55;
BackgroundPen = 0;
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, OldFrame, FRAME_POINTS);
if (Size == ERASE)
Size = INACTIVE;
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = (short)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = (short)(Frame[Size][Count].y + yOffset);
}
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, DisplayFrame, FRAME_POINTS);
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
}
}
Get and set properties of this instance of the object.
REF: 14.5
public short GetSize()
{
return Size;
}
public short GetXOffset()
{
return xOffset;
}
public short GetYOffset()
{
return yOffset;
}
}
This class is used by the players ship and the UFO. The players ship can shoot multiple shots at a time, the UFO shoots a single shot at a time.
REF: 15.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class astroshot
{
public static final short SMALL_SHOT = 0;
public static final short LARGE_SHOT = 1;
private final short SMALL_SHOT_FRAMES = 40;
private final short LARGE_SHOT_FRAMES = 20;
private final short ERASE_FRAME = 1;
private final short HYPERSPACE = -500;
private short xMax;
private short yMax;
private short xOffset;
private short yOffset;
private short OldxOffset;
private short OldyOffset;
private float xVelocity;
private float yVelocity;
private short Size;
private short FrameCount;
public astroshot()
{
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
OldxOffset = HYPERSPACE;
OldyOffset = HYPERSPACE;
xVelocity = (float)0;
yVelocity = (float)0;
Size = SMALL_SHOT;
FrameCount = 0;
}
public void Move()
{
if (FrameCount > ERASE_FRAME)
{
if (xOffset < 0)
xOffset = xMax;
else if (xOffset > xMax)
xOffset = 0;
if (yOffset < 0)
yOffset = yMax;
else if (yOffset > yMax)
yOffset = 0;
xOffset += (short)xVelocity;
yOffset += (short)yVelocity;
--FrameCount;
}
}
Initialise this instance of the class.
REF: 15.3
public void SetArea(short NewxMax, short NewyMax, short NewxOffset,
short NewyOffset, float NewxVelocity,
float NewyVelocity, short NewSize)
{
xMax = NewxMax;
yMax = NewyMax;
xOffset = NewxOffset;
yOffset = NewyOffset;
xVelocity = NewxVelocity;
yVelocity = NewyVelocity;
Size = NewSize;
if (Size == LARGE_SHOT)
FrameCount = LARGE_SHOT_FRAMES;
else
FrameCount = SMALL_SHOT_FRAMES;
}
Get and set properties of this instance of the class.
REF: 15.4
public short GetXOffset()
{
return xOffset;
}
public short GetYOffset()
{
return yOffset;
}
public void Destroy()
{
FrameCount = ERASE_FRAME;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
public short Active()
{
if (FrameCount != 0)
return -1;
else
return 0;
}
}
A UFO can appear at any time during a game. It shoots shots as it crosses the display left to right, or right to left.
REF: 16.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class astroufo
{
private final short TRUE = -1;
private final short FALSE = 0;
private final short FRAMES = 2;
private final short FRAME_POINTS = 12;
private final short UFO_WIDTH = 16;
private final short UFO_HEIGHT = 6;
private final short INACTIVE = 3;
private final short ERASE = 4;
private final short HYPERSPACE = -500;
private short xMax;
private short yMax;
private short Size;
private short xOffset;
private short yOffset;
private short xVelocity;
private short yVelocity;
private astroshot Shot;
private point Frame[][];
private point DisplayFrame[];
private point OldFrame[];
private sound AppSound;
public astroufo(sound NewAppSound)
{
short Count;
short FrameCount;
AppSound = NewAppSound;
Shot = new astroshot();
Frame = new point[FRAMES][FRAME_POINTS];
DisplayFrame = new point[FRAME_POINTS];
OldFrame = new point[FRAME_POINTS];
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = 0;
yVelocity = 0;
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count] = new point();
OldFrame[Count] = new point();
for (FrameCount = 0; FrameCount < FRAMES; ++FrameCount)
{
Frame[FrameCount][Count] = new point();
}
}
for (Size = 0; Size < FRAMES; ++Size)
{
Frame[Size][0].x = (short)(-(8 + (Size+1)*3));
Frame[Size][0].y = (short)(-(0 + (Size+1)));
Frame[Size][1].x = (short)(-(0 + (Size+1)));
Frame[Size][1].y = (short)(-(3 + (Size+1)*3));
Frame[Size][2].x = (short)(+(0 + (Size+1)));
Frame[Size][2].y = (short)(-(3 + (Size+1)*3));
Frame[Size][3].x = (short)(+(8 + (Size+1)*3));
Frame[Size][3].y = (short)(-(0 + (Size+1)));
Frame[Size][4].x = (short)(-(8 + (Size+1)*3));
Frame[Size][4].y = (short)(-(0 + (Size+1)));
Frame[Size][5].x = (short)(-(8 + (Size+1)*3));
Frame[Size][5].y = (short)(+(0 + (Size+1)));
Frame[Size][6].x = (short)(+(8 + (Size+1)*3));
Frame[Size][6].y = (short)(+(0 + (Size+1)));
Frame[Size][7].x = (short)(+(8 + (Size+1)*3));
Frame[Size][7].y = (short)(-(0 + (Size+1)));
Frame[Size][8].x = (short)(+(8 + (Size+1)*3));
Frame[Size][8].y = (short)(+(0 + (Size+1)));
Frame[Size][9].x = (short)(+(0 + (Size+1)));
Frame[Size][9].y = (short)(+(3 + (Size+1)*3));
Frame[Size][10].x = (short)(-(0 + (Size+1)));
Frame[Size][10].y = (short)(+(3 + (Size+1)*3));
Frame[Size][11].x = (short)(-(8 + (Size+1)*3));
Frame[Size][11].y = (short)(+(0 + (Size+1)));
}
Size = INACTIVE;
}
Draw this instance of the object.
REF: 16.1
public void Draw(Graphics hdc)
{
short Count;
int ColourPen;
int BackgroundPen;
Shot.Draw(hdc);
if (Size != INACTIVE)
{
ColourPen = 0x77FF77;
BackgroundPen = 0;
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, OldFrame, FRAME_POINTS);
if (Size == ERASE)
Size = INACTIVE;
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = (short)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = (short)(Frame[Size][Count].y + yOffset);
}
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, DisplayFrame, FRAME_POINTS);
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
}
}
Animate a single frame of this instance of the object.
Check if this instance of the object has collided with a specific location.
REF: 16.4
public short Collide(short xPos, short yPos, short Width, short Height)
{
short Collision = FALSE;
if (Size < INACTIVE)
{
if (xPos + Width/2 > xOffset - UFO_WIDTH / (Size*Size+1)
&& xPos - Width/2 < xOffset + UFO_WIDTH / (Size*Size+1)
&& yPos + Height/2 > yOffset - UFO_HEIGHT / (Size*Size+1)
&& yPos - Height/2 < yOffset + UFO_HEIGHT / (Size*Size+1))
Collision = TRUE;
else
Collision = FALSE;
if (Collision == TRUE)
Destroy();
}
return Collision;
}
public void Destroy()
{
Size = ERASE;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
Get and set properties of this instance of the object.
REF: 16.5
public short GetSize()
{
return Size;
}
public short GetXOffset()
{
return xOffset;
}
public short GetYOffset()
{
return yOffset;
}
public astroshot GetShot()
{
return Shot;
}
}
The rotation of the players ship is calculated at creation of the object, so that animation is swifter to perform during game play.
REF: 17.0
// Asteroids Clone Java
// Copyright (C) 1997 Jason Birch
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
import java.awt.*;
public class astroship
{
private final short TRUE = -1;
private final short FALSE = 0;
private final short FRAMES = 63;
private final short ERASE_FRAME = (short)(FRAMES + 1);
private final short FRAME_POINTS = 5;
private final short THRUST_POINTS = 8;
private final short SHIP_WIDTH = 25;
private final short SHIP_HEIGHT = 25;
private final short SHIP_START_ANGLE = 31;
private final short MAX_EXPLODE_FRAME = 40;
private final short LIFE_XGAP = 30;
private final short LIFE_XOFFSET = 150;
private final short LIFE_YOFFSET = 35;
private final short MAX_LIVES = 3;
private final short SCORE_XOFFSET = 10;
private final short SCORE_YOFFSET = 20;
private final short SCORE_SCALE = 5;
private final short MAX_SHOTS = 10;
private final short HYPERSPACE = -500;
private final short HYPER_FRAMES = 20;
private double OneDegree;
private double FrameStep;
private short Lives;
private short Crash;
private short ThrustFlag;
private short Fade;
private short xMax;
private short yMax;
private short Angle;
private short xOffset;
private short yOffset;
private short ShotIndex;
private float xVelocity;
private float yVelocity;
private short ExplodeFrame;
private short HyperCount;
private classnumber PlayerScore;
private astroshot Shots[];
private point LifeFrame[];
private point LifeDisplayFrame[];
private point Frame[][];
private point DisplayFrame[];
private point OldFrame[];
private point ExplodeDirection[];
private point ThrustTrail[];
private sound AppSound;
public astroship(sound NewAppSound)
{
short Count;
AppSound = NewAppSound;
Shots = new astroshot[MAX_SHOTS];
LifeFrame = new point[FRAME_POINTS];
LifeDisplayFrame = new point[FRAME_POINTS];
Frame = new point[FRAMES][FRAME_POINTS];
DisplayFrame = new point[FRAME_POINTS*2];
OldFrame = new point[FRAME_POINTS*2];
ExplodeDirection = new point[FRAME_POINTS*2];
ThrustTrail = new point[THRUST_POINTS];
PlayerScore = new classnumber();
OneDegree = (double)6.3 / (double)360;
FrameStep = (double)0.1;
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = (short)0;
yVelocity = (short)0;
Crash = 0;
ThrustFlag = 0;
Fade = 0;
Lives = MAX_LIVES;
ExplodeFrame = 0;
ShotIndex = 0;
HyperCount = 0;
for (Count = 0; Count < MAX_SHOTS; ++Count)
{
Shots[Count] = new astroshot();
}
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
ThrustTrail[Count] = new point();
}
for (Count = 0; Count < FRAME_POINTS*2; ++Count)
{
DisplayFrame[Count] = new point();
OldFrame[Count] = new point();
ExplodeDirection[Count] = new point();
}
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
LifeFrame[Count] = new point();
LifeDisplayFrame[Count] = new point();
}
Angle = SHIP_START_ANGLE;
LifeFrame[0].x = (short)(19 * Math.sin(FrameStep*Angle + OneDegree*0));
LifeFrame[0].y = (short)(19 * Math.cos(FrameStep*Angle + OneDegree*0));
LifeFrame[1].x = (short)(16 * Math.sin(FrameStep*Angle + OneDegree*140));
LifeFrame[1].y = (short)(16 * Math.cos(FrameStep*Angle + OneDegree*140));
LifeFrame[2].x = (short)(8 * Math.sin(FrameStep*Angle + OneDegree*180));
LifeFrame[2].y = (short)(8 * Math.cos(FrameStep*Angle + OneDegree*180));
LifeFrame[3].x = (short)(16 * Math.sin(FrameStep*Angle + OneDegree*220));
LifeFrame[3].y = (short)(16 * Math.cos(FrameStep*Angle + OneDegree*220));
LifeFrame[4].x = (short)(19 * Math.sin(FrameStep*Angle + OneDegree*0));
LifeFrame[4].y = (short)(19 * Math.cos(FrameStep*Angle + OneDegree*0));
for (Angle = 0; Angle < FRAMES; ++Angle)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
Frame[Angle][Count] = new point();
}
Frame[Angle][0].x = (short)(16 * Math.sin(FrameStep*Angle + OneDegree*0));
Frame[Angle][0].y = (short)(16 * Math.cos(FrameStep*Angle + OneDegree*0));
Frame[Angle][1].x = (short)(13 * Math.sin(FrameStep*Angle + OneDegree*140));
Frame[Angle][1].y = (short)(13 * Math.cos(FrameStep*Angle + OneDegree*140));
Frame[Angle][2].x = (short)(5 * Math.sin(FrameStep*Angle + OneDegree*180));
Frame[Angle][2].y = (short)(5 * Math.cos(FrameStep*Angle + OneDegree*180));
Frame[Angle][3].x = (short)(13 * Math.sin(FrameStep*Angle + OneDegree*220));
Frame[Angle][3].y = (short)(13 * Math.cos(FrameStep*Angle + OneDegree*220));
Frame[Angle][4].x = (short)(16 * Math.sin(FrameStep*Angle + OneDegree*0));
Frame[Angle][4].y = (short)(16 * Math.cos(FrameStep*Angle + OneDegree*0));
}
Angle = SHIP_START_ANGLE;
}
Draw this instance of the object. When the ship is destroyed, split the components of the ship into individual lines and fade them out from the display.
REF: 17.1
public void Draw(Graphics hdc)
{
short Count;
short LifeCount;
int ColourPen;
int FadePen;
int BackgroundPen;
for (Count = 0; Count < MAX_SHOTS; ++Count)
Shots[Count].Draw(hdc);
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = 0x55DD55;
FadePen = 0x55DD55 - (0x01 * Fade + 0x0100 * 2*Fade + 0x010000 * Fade);
BackgroundPen = 0x000000;
if (Lives != 0 || ExplodeFrame != MAX_EXPLODE_FRAME)
{
/*********************/
/* Draw intact ship. */
/*********************/
if (Crash == 0)
{
/********************************/
/* Plot ships current position. */
/********************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = (short)(Frame[Angle][Count].x + xOffset);
DisplayFrame[Count].y = (short)(Frame[Angle][Count].y + yOffset);
}
hdc.setColor(new Color(BackgroundPen));
if (ExplodeFrame >= ERASE_FRAME)
{
ExplodeFrame = 0;
/************************************/
/* Erase previous position of ship. */
/************************************/
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
hdc.drawLine(OldFrame[Count].x, OldFrame[Count].y,
OldFrame[Count+1].x, OldFrame[Count+1].y);
}
}
/************************************/
/* Erase previous position of ship. */
/************************************/
win32.Polyline(hdc, OldFrame, FRAME_POINTS);
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, DisplayFrame, FRAME_POINTS);
/******************/
/* Remove thrust. */
/******************/
hdc.setColor(new Color(BackgroundPen));
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
hdc.drawLine(ThrustTrail[Count].x, ThrustTrail[Count].y,
ThrustTrail[Count].x + 1, ThrustTrail[Count].y + 1);
}
/*****************************************/
/* Add thrust point if currently active. */
/*****************************************/
if (ThrustFlag == TRUE)
{
hdc.setColor(new Color(ColourPen));
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
ThrustTrail[Count].x = (short)(xOffset + (short)(Math.random() * 7)-3
+ (long)(15 * Math.sin(FrameStep*Angle + OneDegree*180)));
ThrustTrail[Count].y = (short)(yOffset + (short)(Math.random() * 7)-3
+ (long)(15 * Math.cos(FrameStep*Angle + OneDegree*180)));
hdc.drawLine(ThrustTrail[Count].x, ThrustTrail[Count].y,
ThrustTrail[Count].x + 1, ThrustTrail[Count].y + 1);
}
ThrustFlag = FALSE;
}
/******************************************/
/* Plot ships current position, */
/* next time it will be the old position. */
/******************************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
else
{
if (ExplodeFrame == 0)
{
--Lives;
/************************************/
/* Erase previous position of ship. */
/************************************/
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, OldFrame, FRAME_POINTS);
/******************/
/* Remove thrust. */
/******************/
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
hdc.drawLine(ThrustTrail[Count].x, ThrustTrail[Count].y,
ThrustTrail[Count].x + 1, ThrustTrail[Count].y + 1);
}
/**************************************************/
/* Set direction of individual lines of the ship. */
/**************************************************/
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
do
{
ExplodeDirection[Count].x = (short)((Math.random() * 10) - 5);
} while (ExplodeDirection[Count].x == 0);
do
{
ExplodeDirection[Count].y = (short)((Math.random() * 10) - 5);
} while (ExplodeDirection[Count].y == 0);
ExplodeDirection[Count+1].x = ExplodeDirection[Count].x;
ExplodeDirection[Count+1].y = ExplodeDirection[Count].y;
}
/********************************************/
/* Split polygon shape into seperate lines. */
/********************************************/
DisplayFrame[0].x = (short)(Frame[Angle][FRAME_POINTS-1].x + xOffset);
DisplayFrame[0].y = (short)(Frame[Angle][FRAME_POINTS-1].y + yOffset);
OldFrame[0].x = (short)(Frame[Angle][FRAME_POINTS-1].x + xOffset);
OldFrame[0].y = (short)(Frame[Angle][FRAME_POINTS-1].y + yOffset);
DisplayFrame[FRAME_POINTS*2-1].x =
(short)(Frame[Angle][FRAME_POINTS-1].x + xOffset);
DisplayFrame[FRAME_POINTS*2-1].y =
(short)(Frame[Angle][FRAME_POINTS-1].y + yOffset);
OldFrame[FRAME_POINTS*2-1].x =
(short)(Frame[Angle][FRAME_POINTS-1].x + xOffset);
OldFrame[FRAME_POINTS*2-1].y =
(short)(Frame[Angle][FRAME_POINTS-1].y + yOffset);
for (Count = 0; Count < FRAME_POINTS-1; ++Count)
{
DisplayFrame[Count*2+1].x = (short)(Frame[Angle][Count].x + xOffset);
DisplayFrame[Count*2+1].y = (short)(Frame[Angle][Count].y + yOffset);
DisplayFrame[Count*2+2].x = (short)(Frame[Angle][Count].x + xOffset);
DisplayFrame[Count*2+2].y = (short)(Frame[Angle][Count].y + yOffset);
OldFrame[Count*2+1].x = (short)(Frame[Angle][Count].x + xOffset);
OldFrame[Count*2+1].y = (short)(Frame[Angle][Count].y + yOffset);
OldFrame[Count*2+2].x = (short)(Frame[Angle][Count].x + xOffset);
OldFrame[Count*2+2].y = (short)(Frame[Angle][Count].y + yOffset);
}
}
/************************************/
/* Erase previous position of ship. */
/************************************/
hdc.setColor(new Color(BackgroundPen));
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
hdc.drawLine(OldFrame[Count].x, OldFrame[Count].y,
OldFrame[Count+1].x, OldFrame[Count+1].y);
}
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
if (ExplodeFrame < MAX_EXPLODE_FRAME -1)
{
Fade += 0x55 / MAX_EXPLODE_FRAME;
hdc.setColor(new Color(FadePen));
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
DisplayFrame[Count].x += ExplodeDirection[Count].x;
DisplayFrame[Count].y += ExplodeDirection[Count].y;
DisplayFrame[Count+1].x += ExplodeDirection[Count+1].x;
DisplayFrame[Count+1].y += ExplodeDirection[Count+1].y;
hdc.drawLine(DisplayFrame[Count].x, DisplayFrame[Count].y,
DisplayFrame[Count+1].x, DisplayFrame[Count+1].y);
}
/******************************************/
/* Plot ships current position, */
/* next time it will be the old position. */
/******************************************/
for (Count = 0; Count < FRAME_POINTS*2; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
/************************/
/* Reset for next life. */
/************************/
++ExplodeFrame;
if (Lives != 0 && ExplodeFrame == MAX_EXPLODE_FRAME)
{
ExplodeFrame = 0;
Crash = 0;
ThrustFlag = FALSE;
Fade = 0;
Angle = SHIP_START_ANGLE;
xOffset = (short)(xMax/2);
yOffset = (short)(yMax/2);
xVelocity = (short)0;
yVelocity = (short)0;
}
}
/****************************/
/* Display remaining lives. */
/****************************/
for (LifeCount = 0; LifeCount < MAX_LIVES; ++LifeCount)
{
/********************************/
/* Plot ships current position. */
/********************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
LifeDisplayFrame[Count].x = (short)(LifeFrame[Count].x
+ (xMax - LIFE_XOFFSET) + (LifeCount+1)*LIFE_XGAP);
LifeDisplayFrame[Count].y = (short)(LifeFrame[Count].y + LIFE_YOFFSET);
}
/************************************/
/* Erase previous position of ship. */
/************************************/
hdc.setColor(new Color(BackgroundPen));
win32.Polyline(hdc, LifeDisplayFrame, FRAME_POINTS);
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
if (Lives > LifeCount)
{
hdc.setColor(new Color(ColourPen));
win32.Polyline(hdc, LifeDisplayFrame, FRAME_POINTS);
}
}
}
/******************/
/* Redraw scores. */
/******************/
PlayerScore.Draw(hdc);
}
Check if this instance of the object has collided with a specific location.
REF: 17.6
public short Collide(short xPos, short yPos, short Width, short Height)
{
short Collision = FALSE;
if (Crash == 0)
{
if (xPos + Width/2 > xOffset - SHIP_WIDTH
&& xPos - Width/2 < xOffset + SHIP_WIDTH
&& yPos + Height/2 > yOffset - SHIP_HEIGHT
&& yPos - Height/2 < yOffset + SHIP_HEIGHT == true)
{
Collision = TRUE;
Crash = TRUE;
}
}
return Collision;
}
Get and set properties of this instance of the object.
REF: 17.7
public void SetCrash(short NewCrash)
{
if (Crash == 0 && NewCrash == TRUE)
AppSound.Play("Rock.au");
Crash = NewCrash;
}
public short GetCrash()
{
return Crash;
}
public short GetXOffset()
{
return xOffset;
}
public short GetYOffset()
{
return yOffset;
}
public short GetWidth()
{
return SHIP_WIDTH;
}
public short GetHeight()
{
return SHIP_HEIGHT;
}
public long GetScore()
{
return PlayerScore.GetNumber();
}
public void SetScore(long NewScore)
{
PlayerScore.SetNumber(NewScore);
}
public short GetLives()
{
return Lives;
}
public astroshot GetShot(short ShotCount)
{
return Shots[ShotCount];
}
public short GetShotCount()
{
return MAX_SHOTS;
}
}