Overview
|
Asteroids.hpp
|
Asteroids.cpp
|
Number.hpp
|
Number.cpp
|
Text.hpp
|
Text.cpp
|
AstroRock.hpp
|
AstroRock.cpp
|
AstroShip.hpp
|
AstroShip.cpp
|
AstroShot.hpp
|
AstroShot.cpp
|
Astro_UFO.hpp
|
Astro_UFO.cpp
|
GNU License
|
|
Coding a Windows Screen Saver
2012-02-23 16:15 By Jason Birch
First in a series of how to code articles. Demonstrating coding an Asteroids Clone game with various technologies. This example using C++ and implementing as a Windows screen saver.
Back in 1997 I wrote a screen saver for Windows NT 4, later I converted it to DirectX and then Java. Recently I dug out the source code and converted it to Linux. 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.
A compiled version of the screen saver is available here, it is just 65KB in size.

Screen Shot Of Linux Conversion
Having reviewed the code now for this article, fifteen years on, I would write the code significantly differently today, as the code could be simplified by using inheritance. There are also some untidy parts of the code which could do with being refined. However, the code does provide a good simple example of what it achieves.
Required Environment
To run the screen saver application, a Windows operating system is required.
To develop the screen saver application, Microsoft Visual Studio Express is required, which is freely available from www.microsoft.com.
Writing Code
Visual Studio is the best tool as it provides support for resources and good inline tools.
Compiling Code
Visual Studio is the best tool to compile the project.
Distributing Application
The application can only be run on a Microsoft Windows operating system. Copy the file into the Windows install directory so it appears in the list of installed screen savers.
Running Application
The application can either be run by double clicking on the application icon or by configuring it as the screen saver in Control Panel.
|
The main header file for the application contains an enumeration of values to configure the visual elements of the application. These will be explained in detail in the source code file Asteroids.cpp.
REF: 1.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __ASTERIODS_HPP
#define __ASTERIODS_HPP
enum
{
START_ROCKS = 5,
MAX_ROCKS = 100,
HISCORE_XOFFSET = 55,
HISCORE_YOFFSET = 20,
GAMEOVER_XOFFSET = 90,
GAMEOVER_YOFFSET = 20,
INSERTCOIN_XOFFSET = 110,
INSERTCOIN_YOFFSET = 20,
HISCORE_SCALE = 3
};
#endif
|
|
The main application code includes a header file for the standard Windows API and a header file called scrnsave.h which contains prototypes and definitions for Windows screen saver features. Then all of the application's class header files are included.
REF: 2.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include <scrnsave.h>
#include "RESOURCE.H"
#include "TEXT.HPP"
#include "NUMBER.HPP"
#include "ASTROSHOT.HPP"
#include "ASTROSHIP.HPP"
#include "ASTRO_UFO.HPP"
#include "ASTROROCK.HPP"
#include "ASTEROIDS.HPP"
|
The application uses a main message loop to receive events from the Windows system. These events can be key presses, mouse clicks, requests to redraw the applications Window, ... Because of this some variables in the application require global scope, in order for the message loop to act on events and manipulate objects the application owns.
REF: 2.1
|
HWND hwnd;
RECT Desktop;
AstroShip Ship;
AstroUFO UFO;
AstroRock Rock[MAX_ROCKS];
short FirstRock;
short NextRock;
Number HiScore;
Text GameOver;
Text InsertCoin;
short MouseRightDown = FALSE;
short MouseX = 0;
|
The entry point to the application is a function named ScreenSaverProc, this is the name called by the Windows operating system when starting a screen saver application. This function will also be called if starting the application like a standard application from a file browser.
This function contains a message handler for processing messages passed from the operating system to the screen saver. In a standard Windows application a message loop handles the messages, a screen saver is slightly different in that the message loop is handled by the operating system and the screen saver just receives the messages.
REF: 2.2
|
LONG WINAPI ScreenSaverProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
short Count;
short ShotCount;
short RockFound;
POINT CursorPos;
switch (message)
{
|
The first messages handled is WM_CREATE, the code for this message initialized the application and establishes a timer to animate the application every 1/50th of a second. The Window for the screen saver has already been established by the operating system so the dimensions of the desktop Window are read to see how large the Window is. The game objects are then initialized ready for the first timer message to be processed.
REF: 2.3
|
case WM_CREATE:
{
GetWindowRect(GetDesktopWindow(), &Desktop);
SetTimer(hwnd, 1, 50, NULL);
srand(GetTickCount());
GameOver.SetLocation(hwnd,
(Desktop.right-Desktop.left)/2 - GAMEOVER_XOFFSET,
(Desktop.bottom-Desktop.top)/2 - GAMEOVER_YOFFSET,
5, 200, FALSE, "GAME OVER");
InsertCoin.SetLocation(hwnd,
(Desktop.right-Desktop.left)/2 - INSERTCOIN_XOFFSET,
(Desktop.bottom-Desktop.top)/2 - INSERTCOIN_YOFFSET,
5, 15, TRUE,"INSERT COIN");
HiScore.SetLocation(hwnd,
(Desktop.right-Desktop.left)/2 - HISCORE_XOFFSET,
HISCORE_YOFFSET, HISCORE_SCALE);
Ship.SetArea(hwnd, &Desktop);
UFO.SetArea(hwnd, &Desktop);
srand(GetTickCount());
FirstRock = 4;
NextRock = FirstRock;
for (Count = 0; Count < FirstRock; ++Count)
Rock[Count].SetArea(hwnd, &Desktop);
break;
}
|
When a WM_PAINT message is received, the application must draw the content of the Window. First a graphics context is required from the operating system to be used when drawing graphics. A check is made to make sure the Window isn't minimised, and if not each of the game objects are drawn. It is up to the object to decide if it should be drawn or not and to draw itself appropratly. The graphics context is then released.
REF: 2.4
|
case WM_PAINT:
{
hdc = GetDC(hwnd);
if (IsIconic(hwnd) == FALSE)
{
SetBkColor(hdc, RGB(0x00, 0x00, 0x00));
InsertCoin.Draw(hdc);
GameOver.Draw(hdc);
HiScore.Draw(hdc);
Ship.Draw(hdc);
UFO.Draw(hdc);
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count].Draw(hdc);
}
ReleaseDC(hwnd, hdc);
break;
}
|
When a left mouse button is clicked, tell the ship object to shoot. The ship object decides if it is capable of shooting at this time. Then return false from this message handler, this is very important as it will stop the operating system treating the left click as a wake-up for the screen saver.
REF: 2.5
|
case WM_LBUTTONDOWN:
{
Ship.Shoot();
return FALSE;
}
|
When a right mouse button is pressed, remember that the mouse button has been pressed, as the right mouse button will thrust the ship for as long as the button is held down. The thrust will be handled later on. Then return false from this message handler, this is very important as it will stop the operating system treating the right click as a wake-up for the screen saver.
REF: 2.6
|
case WM_RBUTTONDOWN:
{
MouseRightDown = TRUE;
return FALSE;
}
|
When the right mouse button is released, clear the right mouse button flag, this will stop the ship thrusting. Then return false from this message handler, this is very important as it will stop the operating system treating the right click as a wake-up for the screen saver.
REF: 2.7
|
case WM_RBUTTONUP:
{
MouseRightDown = FALSE;
return FALSE;
}
|
When the mouse it moved left or right, rotate the ship anti-clockwise or clockwise respectivly. Then place the mouse cursor position back in the center of the display, the mouse cursor is not visible when a screen saver is active. Then return false to prevent a mouse move waking up from the screen saver.
REF: 2.8
|
case WM_MOUSEMOVE:
{
if (LOWORD(lParam) < MouseX)
Ship.IncAngle(FALSE);
else if (LOWORD(lParam) > MouseX)
Ship.IncAngle(TRUE);
MouseX = LOWORD(lParam);
GetCursorPos(&CursorPos);
if (CursorPos.x > (Desktop.right-Desktop.left)/2 + 50
|| CursorPos.y > (Desktop.bottom-Desktop.top)/2 + 20)
{
SetCursorPos((Desktop.right-Desktop.left)/2 - 50,
(Desktop.bottom-Desktop.top)/2);
Ship.IncAngle(TRUE);
}
if (CursorPos.x < (Desktop.right-Desktop.left)/2 - 50
|| CursorPos.y < (Desktop.bottom-Desktop.top)/2 - 20)
{
SetCursorPos((Desktop.right-Desktop.left)/2 + 50,
(Desktop.bottom-Desktop.top)/2);
Ship.IncAngle(FALSE);
}
return FALSE;
}
|
There are a few key presses which have an operation in the screen saver. The space bar makes the ship hyperspace. And the F2 key starts a new game. When starting a new game, if the current score is more than the high score, the high score is updated, and then all of the game objects are reset. If a key is handled, false is returned to prevent the screen saver from waking up, any other key will wake up from the screen saver.
REF: 2.9
|
case WM_KEYDOWN:
{
if (wParam == 32)
{
Ship.Hyperspace();
}
else if (wParam == 113)
{
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(hwnd, &Desktop);
}
}
else
break;
return FALSE;
}
|
A timer message is received every 1/50th of a second, this generates an animation rate of 50Hz. Each WM_TIMER message represents one frame of animation. If the right mouse button is currently flagged as being held down, thrust the ship. Move each game object by the required distance, each game object keeps track of how fast it is moving and will know how far it must move in an animation frame.
When handling the rock objects, if a valid rock object is found a flag is set, this is used to decide when all of the rock objects have been shot and a new wave needs to start with additional rocks.
Next collision checks are made, and I have spotted an error in my code, the collision checks for the Ship with the UFO, the Ship with a UFO Shot and the Ship Shot with a UFO should be done outside of the Rock loop, as what I have done here is inefficient. When a collision is detected between two object, an appropriate action is taken for the objects which are colliding. When a shot collides with a rock, the ship scores according to the size of the rock, the shot object is destroyed and the rock splits in to two smaller rock objects.
Finally a game over message is displayed when there are no more player ships available. And then an insert coin message is displayed when the game over message has timed out.
A call to InvalidateRect tells the Windows operating system to redraw the updated Window.
REF: 2.10
|
case WM_TIMER:
{
if (MouseRightDown == TRUE)
Ship.Thrust();
Ship.Move();
UFO.Move();
RockFound = FALSE;
for (Count = 0; Count < MAX_ROCKS; ++Count)
{
if (Rock[Count].GetSize() != AstroRock::INACTIVE)
RockFound = TRUE;
if (Ship.GetCrash() == FALSE
&& UFO.Collide(Ship.GetXOffset(),
Ship.GetYOffset(),
Ship.GetWidth(),
Ship.GetHeight()))
Ship.SetCrash(TRUE);
if (UFO.GetShot().Active() == TRUE
&& Ship.Collide(UFO.GetShot().GetXOffset(),
UFO.GetShot().GetYOffset(),
2, 2))
Ship.SetCrash(TRUE);
if (Ship.GetCrash() == FALSE
&& Rock[Count].Collide(Ship.GetXOffset(),
Ship.GetYOffset(),
Ship.GetWidth(),
Ship.GetHeight()))
{
Ship.SetCrash(TRUE);
Rock[++NextRock].SetArea(hwnd,
&Desktop,
Ship.GetXOffset(),
Ship.GetYOffset(),
Rock[Count].GetSize());
}
for (ShotCount = 0; ShotCount < Ship.GetShotCount(); ++ShotCount)
{
if (Ship.GetShot(ShotCount).Active() != FALSE)
{
if (UFO.Collide(Ship.GetShot(ShotCount).GetXOffset(),
Ship.GetShot(ShotCount).GetYOffset(),
2, 2))
{
Ship.SetScore(Ship.GetScore() + 100);
Ship.GetShot(ShotCount).Destroy();
}
if (Rock[Count].Collide(Ship.GetShot(ShotCount).GetXOffset(),
Ship.GetShot(ShotCount).GetYOffset(),
2, 2))
{
Ship.SetScore(Ship.GetScore() + 5*Rock[Count].GetSize());
Ship.GetShot(ShotCount).Destroy();
if (NextRock+1 < MAX_ROCKS)
Rock[++NextRock].SetArea(hwnd,
&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(hwnd, &Desktop);
}
GameOver.SetVisible(Ship.GetLives() == FALSE);
InsertCoin.SetVisible(GameOver.GetVisible() == FALSE
&& Ship.GetLives() == FALSE);
InvalidateRect(hwnd, NULL, FALSE);
break;
}
|
When the WM_DESTROY message is received, the application must clean up and close.
REF: 2.11
|
case WM_DESTROY:
{
KillTimer(hwnd, 1);
PostQuitMessage(0);
break;
}
}
return DefScreenSaverProc(hwnd, message, wParam, lParam);
}
|
A screen saver has a configuration dialog which also requires a message handler of it's own. This message handler just closes the configuration dialog when an OK button is clicked. In Visual Studio, create a dialog as a resource.
REF: 2.12
|
BOOL WINAPI ScreenSaverConfigureDialog(HWND hwnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam)
{
switch (Msg)
{
case WM_INITDIALOG:
{
return TRUE;
}
case WM_COMMAND:
{
switch(LOWORD(wParam))
{
case IDOK:
{
EndDialog(hwnd, LOWORD(wParam) == IDOK);
return TRUE;
}
}
}
}
return FALSE;
}
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
return TRUE;
}
|
|
The number class draws numbers on the display simulating the way a vector CRT display would do on an 80s' Asteroids arcade machine. The class only requires a few member functions and is the simplest class in this project. There is a Draw function as all of the classes have, which draws the current numeric value onto a graphics context. SetLocation is a function used to initialize the object with required values. GetNumber gets the current value of the object and SetNumber sets the object with a new value.
REF: 3.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __NUMBER_HPP
#define __NUMBER_HPP
class Number
{
public:
enum
{
DIGITS = 10,
MAX_POINTS = 10,
};
Number();
~Number();
void Draw(HDC hdc);
void SetLocation(HWND NewhWnd,
short NewxOffset,
short NewyOffset,
short NewScale,
short NewWidth = 1);
long GetNumber();
void SetNumber(long NewNumber);
private:
HWND hWnd;
short xOffset;
short yOffset;
short Scale;
short Width;
long NumberValue;
POINT Decimal[DIGITS][MAX_POINTS+1];
POINT DisplayFrame[DIGITS][MAX_POINTS+1];
POINT OldFrame[DIGITS][MAX_POINTS+1];
};
#endif
|
|
The number class draws numbers on the display simulating the way a vector CRT display would do on an 80s' Asteroids arcade machine. The class only requires a few member functions and is the simplest class in this project.
REF: 4.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include "NUMBER.HPP"
Number::Number()
{
NumberValue = 0;
xOffset = 0;
yOffset = 0;
Scale = 0;
Width = 0;
}
Number::~Number()
{
}
|
Each of the game objects has a draw function which draws the current state of the object onto a Windows graphics context using Windows GDI calls.
REF: 4.1
|
void Number::Draw(HDC hdc)
{
HPEN ColourPen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
short Digit;
short Count;
div_t Divide;
long TempNumber;
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = CreatePen(PS_SOLID, Width, RGB(0x55, 0xDD, 0x55));
BackgroundPen = CreatePen(PS_SOLID, Width, GetBkColor(hdc));
OldPen = SelectObject(hdc, BackgroundPen);
/*****************************/
/* Plot score current value. */
/*****************************/
TempNumber = NumberValue;
for (Digit = 0; Digit < 10; ++Digit)
{
Divide = div(TempNumber, 10);
TempNumber = Divide.quot;
for (Count = 0; Count < Decimal[Divide.rem][MAX_POINTS].x; ++Count)
{
DisplayFrame[Digit][Count].x = Decimal[Divide.rem][Count].x
+ xOffset + (10 - Digit) * 3*Scale;
DisplayFrame[Digit][Count].y = Decimal[Divide.rem][Count].y + yOffset;
}
DisplayFrame[Digit][MAX_POINTS].x = Decimal[Divide.rem][MAX_POINTS].x;
/*************************/
/* Erase previous score. */
/*************************/
SelectObject(hdc, BackgroundPen);
Polyline(hdc, OldFrame[Digit], OldFrame[Digit][MAX_POINTS].x);
/***************************/
/* Draw the current score. */
/***************************/
SelectObject(hdc, ColourPen);
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;
}
/*********************************************/
/* Restore default pen and delete used pens. */
/*********************************************/
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
}
|
The SetLocation member function re-initializes the object. It sets the objects properties passed in as arguments. When the object draws it's image to a Windows graphics context, it does so by drawing a series of lines defined by x-y co-ordinates. All of the objects possible visual representations are defined in an array of arrays of x-y co-ordinates. In the case of this class the first array represents the digits zero to nine and the second array the x-y co-ordinates which represent each digit.
REF: 4.2
|
void Number::SetLocation(HWND NewhWnd,
short NewxOffset,
short NewyOffset,
short NewScale,
short NewWidth)
{
hWnd = NewhWnd;
xOffset = NewxOffset;
yOffset = NewyOffset;
Scale = NewScale;
Width = NewWidth;
Decimal[0][MAX_POINTS].x = 6;
Decimal[0][0].x = 2*Scale;
Decimal[0][0].y = 0*Scale;
Decimal[0][1].x = 0*Scale;
Decimal[0][1].y = 0*Scale;
Decimal[0][2].x = 0*Scale;
Decimal[0][2].y = 4*Scale;
Decimal[0][3].x = 2*Scale;
Decimal[0][3].y = 4*Scale;
Decimal[0][4].x = 2*Scale;
Decimal[0][4].y = 0*Scale;
Decimal[0][5].x = 0*Scale;
Decimal[0][5].y = 4*Scale;
Decimal[1][MAX_POINTS].x = 2;
Decimal[1][0].x = 1*Scale;
Decimal[1][0].y = 0*Scale;
Decimal[1][1].x = 1*Scale;
Decimal[1][1].y = 4*Scale;
Decimal[2][MAX_POINTS].x = 6;
Decimal[2][0].x = 0*Scale;
Decimal[2][0].y = 0*Scale;
Decimal[2][1].x = 2*Scale;
Decimal[2][1].y = 0*Scale;
Decimal[2][2].x = 2*Scale;
Decimal[2][2].y = 2*Scale;
Decimal[2][3].x = 0*Scale;
Decimal[2][3].y = 2*Scale;
Decimal[2][4].x = 0*Scale;
Decimal[2][4].y = 4*Scale;
Decimal[2][5].x = 2*Scale;
Decimal[2][5].y = 4*Scale;
Decimal[3][MAX_POINTS].x = 7;
Decimal[3][0].x = 0*Scale;
Decimal[3][0].y = 0*Scale;
Decimal[3][1].x = 2*Scale;
Decimal[3][1].y = 0*Scale;
Decimal[3][2].x = 2*Scale;
Decimal[3][2].y = 2*Scale;
Decimal[3][3].x = 0*Scale;
Decimal[3][3].y = 2*Scale;
Decimal[3][4].x = 2*Scale;
Decimal[3][4].y = 2*Scale;
Decimal[3][5].x = 2*Scale;
Decimal[3][5].y = 4*Scale;
Decimal[3][6].x = 0*Scale;
Decimal[3][6].y = 4*Scale;
Decimal[4][MAX_POINTS].x = 5;
Decimal[4][0].x = 0*Scale;
Decimal[4][0].y = 0*Scale;
Decimal[4][1].x = 0*Scale;
Decimal[4][1].y = 2*Scale;
Decimal[4][2].x = 2*Scale;
Decimal[4][2].y = 2*Scale;
Decimal[4][3].x = 2*Scale;
Decimal[4][3].y = 0*Scale;
Decimal[4][4].x = 2*Scale;
Decimal[4][4].y = 4*Scale;
Decimal[5][MAX_POINTS].x = 6;
Decimal[5][0].x = 2*Scale;
Decimal[5][0].y = 0*Scale;
Decimal[5][1].x = 0*Scale;
Decimal[5][1].y = 0*Scale;
Decimal[5][2].x = 0*Scale;
Decimal[5][2].y = 2*Scale;
Decimal[5][3].x = 2*Scale;
Decimal[5][3].y = 2*Scale;
Decimal[5][4].x = 2*Scale;
Decimal[5][4].y = 4*Scale;
Decimal[5][5].x = 0*Scale;
Decimal[5][5].y = 4*Scale;
Decimal[6][MAX_POINTS].x = 6;
Decimal[6][0].x = 2*Scale;
Decimal[6][0].y = 0*Scale;
Decimal[6][1].x = 0*Scale;
Decimal[6][1].y = 0*Scale;
Decimal[6][2].x = 0*Scale;
Decimal[6][2].y = 4*Scale;
Decimal[6][3].x = 2*Scale;
Decimal[6][3].y = 4*Scale;
Decimal[6][4].x = 2*Scale;
Decimal[6][4].y = 2*Scale;
Decimal[6][5].x = 0*Scale;
Decimal[6][5].y = 2*Scale;
Decimal[7][MAX_POINTS].x = 3;
Decimal[7][0].x = 0*Scale;
Decimal[7][0].y = 0*Scale;
Decimal[7][1].x = 2*Scale;
Decimal[7][1].y = 0*Scale;
Decimal[7][2].x = 2*Scale;
Decimal[7][2].y = 4*Scale;
Decimal[8][MAX_POINTS].x = 7;
Decimal[8][0].x = 0*Scale;
Decimal[8][0].y = 0*Scale;
Decimal[8][1].x = 2*Scale;
Decimal[8][1].y = 0*Scale;
Decimal[8][2].x = 2*Scale;
Decimal[8][2].y = 4*Scale;
Decimal[8][3].x = 0*Scale;
Decimal[8][3].y = 4*Scale;
Decimal[8][4].x = 0*Scale;
Decimal[8][4].y = 0*Scale;
Decimal[8][5].x = 0*Scale;
Decimal[8][5].y = 2*Scale;
Decimal[8][6].x = 2*Scale;
Decimal[8][6].y = 2*Scale;
Decimal[9][MAX_POINTS].x = 6;
Decimal[9][0].x = 0*Scale;
Decimal[9][0].y = 4*Scale;
Decimal[9][1].x = 2*Scale;
Decimal[9][1].y = 4*Scale;
Decimal[9][2].x = 2*Scale;
Decimal[9][2].y = 0*Scale;
Decimal[9][3].x = 0*Scale;
Decimal[9][3].y = 0*Scale;
Decimal[9][4].x = 0*Scale;
Decimal[9][4].y = 2*Scale;
Decimal[9][5].x = 2*Scale;
Decimal[9][5].y = 2*Scale;
}
|
The last two member functions of this class set or retrieve the numeric value which is to be displayed by the current instance of the class.
REF: 4.3
|
long Number::GetNumber()
{
return NumberValue;
}
void Number::SetNumber(long NewNumber)
{
NumberValue = NewNumber;
}
|
|
The text class draws text strings on the display simulating the way a vector CRT display would do on an 80s' Asteroids arcade machine. The class only requires a few member functions. There is a Draw function as all of the classes have, which draws the text string onto a graphics context. SetLocation is a function used to initialize the object with required values. GetVisible checks if the current instance of the object is currently being displayed and SetVisible sets the object to be drawn or hidden.
REF: 5.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __TEXT_HPP
#define __TEXT_HPP
class Text
{
public:
enum
{
MAX_LETTERS = 58,
MAX_POINTS = 12,
MAX_TEXT = 2048,
INFINATE_FRAMES = -1
};
Text();
~Text();
void Draw(HDC hdc);
void SetLocation(HWND NewhWnd,
short NewxOffset,
short NewyOffset,
short NewScale,
short NewFrames,
short NewFlash,
char* NewText,
COLORREF NewTextColour = RGB(0x55, 0xDD, 0x55),
short NewWidth = 1);
void SetVisible(short NewVisible);
short GetVisible();
private:
HWND hWnd;
short xOffset;
short yOffset;
short Scale;
short Width;
COLORREF TextColour;
short Visible;
short LastVisible;
short FlashVisible;
short Active;
short Frames;
short FrameCount;
short Flash;
char TextString[MAX_TEXT+1];
POINT Letter[MAX_LETTERS+1][MAX_POINTS+1];
POINT DisplayFrame[MAX_TEXT+1][MAX_POINTS+1];
};
#endif
|
|
The text class draws text strings on the display simulating the way a vector CRT display would do on an 80s' Asteroids arcade machine.
REF: 6.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include "TEXT.HPP"
Text::Text()
{
TextString[0] = '\0';
xOffset = 0;
yOffset = 0;
Scale = 0;
Width = 0;
TextColour = RGB(0x55, 0xDD, 0x55);
Visible = FALSE;
LastVisible = FALSE;
FlashVisible = FALSE;
Active = FALSE;
Frames = INFINATE_FRAMES;
FrameCount = 0;
Flash = FALSE;
}
Text::~Text()
{
}
|
Each of the game objects has a draw function which draws the current state of the object onto a Windows graphics context using Windows GDI calls.
REF: 6.1
|
void Text::Draw(HDC hdc)
{
HPEN ColourPen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
short Digit;
if (Active == TRUE)
{
/********************************************/
/* Display only for given number of frames. */
/********************************************/
if (FrameCount != INFINATE_FRAMES)
--FrameCount;
if (FrameCount == FALSE && Flash == TRUE)
{
FrameCount = Frames;
FlashVisible = !FlashVisible;
}
else if (FrameCount == FALSE)
{
Active = FALSE;
}
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = CreatePen(PS_SOLID, Width, TextColour);
BackgroundPen = CreatePen(PS_SOLID, Width, GetBkColor(hdc));
OldPen = SelectObject(hdc, BackgroundPen);
/****************************/
/* Plot Text current value. */
/****************************/
for (Digit = 0; Digit < MAX_TEXT && TextString[Digit] != '\0'; ++Digit)
{
if (TextString[Digit] >= '!' && TextString[Digit] <= 'Z')
{
/************************/
/* Erase previous Text. */
/************************/
if (Active == FALSE || Visible == FALSE || FlashVisible == FALSE)
{
SelectObject(hdc, BackgroundPen);
Polyline(hdc, DisplayFrame[Digit], DisplayFrame[Digit][MAX_POINTS].x);
}
else
/**************************/
/* Draw the current Text. */
/**************************/
{
SelectObject(hdc, ColourPen);
Polyline(hdc, DisplayFrame[Digit], DisplayFrame[Digit][MAX_POINTS].x);
}
}
}
/*********************************************/
/* Restore default pen and delete used pens. */
/*********************************************/
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
}
}
|
The SetLocation member function re-initializes the object. It sets the objects properties passed in as arguments. When the object draws it's image to a Windows graphics context, it does so by drawing a series of lines defined by x-y co-ordinates. All of the objects possible visual representations are defined in an array of arrays of x-y co-ordinates. In the case of this class the first array represents the ASCII characters ! to Z and the second array the x-y co-ordinates which represent each digit.
REF: 6.2
|
void Text::SetLocation(HWND NewhWnd,
short NewxOffset,
short NewyOffset,
short NewScale,
short NewFrames,
short NewFlash,
char* NewText,
COLORREF NewTextColour,
short NewWidth)
{
short Count;
short Digit;
short xOffsetOrig;
hWnd = NewhWnd;
xOffsetOrig = NewxOffset;
xOffset = NewxOffset;
yOffset = NewyOffset;
Scale = NewScale;
Width = NewWidth;
TextColour = NewTextColour;
Frames = NewFrames;
Flash = NewFlash;
strncpy(TextString, NewText, MAX_TEXT);
strupr(TextString);
// !
Letter[0][MAX_POINTS].x = 2;
Letter[0][0].x = 2*Scale;
Letter[0][0].y = 0*Scale;
Letter[0][1].x = 2*Scale;
Letter[0][1].y = 3*Scale;
// "
Letter[1][MAX_POINTS].x = 4;
Letter[1][0].x = 1*Scale;
Letter[1][0].y = 1*Scale;
Letter[1][1].x = 1*Scale;
Letter[1][1].y = 0*Scale;
Letter[1][2].x = 2*Scale;
Letter[1][2].y = 0*Scale;
Letter[1][3].x = 2*Scale;
Letter[1][3].y = 1*Scale;
// #
Letter[2][MAX_POINTS].x = 11;
Letter[2][0].x = 1*Scale;
Letter[2][0].y = 0*Scale;
Letter[2][1].x = 1*Scale;
Letter[2][1].y = 4*Scale;
Letter[2][2].x = 1*Scale;
Letter[2][2].y = 3*Scale;
Letter[2][3].x = 0*Scale;
Letter[2][3].y = 3*Scale;
Letter[2][4].x = 3*Scale;
Letter[2][4].y = 3*Scale;
Letter[2][5].x = 2*Scale;
Letter[2][5].y = 3*Scale;
Letter[2][6].x = 2*Scale;
Letter[2][6].y = 4*Scale;
Letter[2][7].x = 2*Scale;
Letter[2][7].y = 0*Scale;
Letter[2][8].x = 2*Scale;
Letter[2][8].y = 1*Scale;
Letter[2][9].x = 3*Scale;
Letter[2][9].y = 1*Scale;
Letter[2][10].x = 0*Scale;
Letter[2][10].y = 1*Scale;
// $
Letter[3][MAX_POINTS].x = 9;
Letter[3][0].x = 3*Scale;
Letter[3][0].y = 1*Scale;
Letter[3][1].x = 1*Scale;
Letter[3][1].y = 1*Scale;
Letter[3][2].x = 0*Scale;
Letter[3][2].y = 2*Scale;
Letter[3][3].x = 3*Scale;
Letter[3][3].y = 2*Scale;
Letter[3][4].x = 2*Scale;
Letter[3][4].y = 3*Scale;
Letter[3][5].x = 0*Scale;
Letter[3][5].y = 3*Scale;
Letter[3][6].x = 1*Scale;
Letter[3][6].y = 3*Scale;
Letter[3][7].x = 0*Scale;
Letter[3][7].y = 4*Scale;
Letter[3][8].x = 3*Scale;
Letter[3][8].y = 0*Scale;
// %
Letter[4][MAX_POINTS].x = 11;
Letter[4][0].x = 0*Scale;
Letter[4][0].y = 0*Scale;
Letter[4][1].x = 0*Scale;
Letter[4][1].y = 1*Scale;
Letter[4][2].x = 1*Scale;
Letter[4][2].y = 1*Scale;
Letter[4][3].x = 1*Scale;
Letter[4][3].y = 0*Scale;
Letter[4][4].x = 0*Scale;
Letter[4][4].y = 0*Scale;
Letter[4][5].x = 3*Scale;
Letter[4][5].y = 0*Scale;
Letter[4][6].x = 0*Scale;
Letter[4][6].y = 4*Scale;
Letter[4][7].x = 3*Scale;
Letter[4][7].y = 4*Scale;
Letter[4][8].x = 3*Scale;
Letter[4][8].y = 3*Scale;
Letter[4][9].x = 2*Scale;
Letter[4][9].y = 3*Scale;
Letter[4][10].x = 2*Scale;
Letter[4][10].y = 4*Scale;
// &
Letter[5][MAX_POINTS].x = 7;
Letter[5][0].x = 3*Scale;
Letter[5][0].y = 4*Scale;
Letter[5][1].x = 0*Scale;
Letter[5][1].y = 1*Scale;
Letter[5][2].x = 1*Scale;
Letter[5][2].y = 0*Scale;
Letter[5][3].x = 2*Scale;
Letter[5][3].y = 1*Scale;
Letter[5][4].x = 0*Scale;
Letter[5][4].y = 3*Scale;
Letter[5][5].x = 1*Scale;
Letter[5][5].y = 4*Scale;
Letter[5][6].x = 3*Scale;
Letter[5][6].y = 2*Scale;
// '
Letter[6][MAX_POINTS].x = 2;
Letter[6][0].x = 2*Scale;
Letter[6][0].y = 0*Scale;
Letter[6][1].x = 1*Scale;
Letter[6][1].y = 1*Scale;
// (
Letter[7][MAX_POINTS].x = 6;
Letter[7][0].x = 2*Scale;
Letter[7][0].y = 0*Scale;
Letter[7][1].x = 1*Scale;
Letter[7][1].y = 0*Scale;
Letter[7][2].x = 0*Scale;
Letter[7][2].y = 1*Scale;
Letter[7][3].x = 0*Scale;
Letter[7][3].y = 3*Scale;
Letter[7][4].x = 1*Scale;
Letter[7][4].y = 4*Scale;
Letter[7][5].x = 2*Scale;
Letter[7][5].y = 4*Scale;
// )
Letter[8][MAX_POINTS].x = 6;
Letter[8][0].x = 1*Scale;
Letter[8][0].y = 0*Scale;
Letter[8][1].x = 2*Scale;
Letter[8][1].y = 0*Scale;
Letter[8][2].x = 3*Scale;
Letter[8][2].y = 1*Scale;
Letter[8][3].x = 3*Scale;
Letter[8][3].y = 3*Scale;
Letter[8][4].x = 2*Scale;
Letter[8][4].y = 4*Scale;
Letter[8][5].x = 1*Scale;
Letter[8][5].y = 4*Scale;
// *
Letter[9][MAX_POINTS].x = 11;
Letter[9][0].x = 0*Scale;
Letter[9][0].y = 1*Scale;
Letter[9][1].x = 2*Scale;
Letter[9][1].y = 3*Scale;
Letter[9][2].x = 1*Scale;
Letter[9][2].y = 2*Scale;
Letter[9][3].x = 0*Scale;
Letter[9][3].y = 3*Scale;
Letter[9][4].x = 2*Scale;
Letter[9][4].y = 1*Scale;
Letter[9][5].x = 1*Scale;
Letter[9][5].y = 2*Scale;
Letter[9][6].x = 0*Scale;
Letter[9][6].y = 2*Scale;
Letter[9][7].x = 2*Scale;
Letter[9][7].y = 2*Scale;
Letter[9][8].x = 1*Scale;
Letter[9][8].y = 2*Scale;
Letter[9][9].x = 1*Scale;
Letter[9][9].y = 1*Scale;
Letter[9][10].x = 1*Scale;
Letter[9][10].y = 3*Scale;
// +
Letter[10][MAX_POINTS].x = 5;
Letter[10][0].x = 1*Scale;
Letter[10][0].y = 1*Scale;
Letter[10][1].x = 1*Scale;
Letter[10][1].y = 3*Scale;
Letter[10][2].x = 1*Scale;
Letter[10][2].y = 2*Scale;
Letter[10][3].x = 0*Scale;
Letter[10][3].y = 2*Scale;
Letter[10][4].x = 2*Scale;
Letter[10][4].y = 2*Scale;
// ,
Letter[11][MAX_POINTS].x = 2;
Letter[11][0].x = 2*Scale;
Letter[11][0].y = 3*Scale;
Letter[11][1].x = 1*Scale;
Letter[11][1].y = 4*Scale;
// -
Letter[12][MAX_POINTS].x = 2;
Letter[12][0].x = 0*Scale;
Letter[12][0].y = 2*Scale;
Letter[12][1].x = 2*Scale;
Letter[12][1].y = 2*Scale;
// .
Letter[13][MAX_POINTS].x = 2;
Letter[13][0].x = 2*Scale;
Letter[13][0].y = 4*Scale;
Letter[13][1].x = 2*Scale;
Letter[13][1].y = 4*Scale;
// /
Letter[14][MAX_POINTS].x = 2;
Letter[14][0].x = 0*Scale;
Letter[14][0].y = 4*Scale;
Letter[14][1].x = 3*Scale;
Letter[14][1].y = 0*Scale;
// 0
Letter[15][MAX_POINTS].x = 9;
Letter[15][0].x = 1*Scale;
Letter[15][0].y = 0*Scale;
Letter[15][1].x = 2*Scale;
Letter[15][1].y = 0*Scale;
Letter[15][2].x = 3*Scale;
Letter[15][2].y = 1*Scale;
Letter[15][3].x = 3*Scale;
Letter[15][3].y = 3*Scale;
Letter[15][4].x = 2*Scale;
Letter[15][4].y = 4*Scale;
Letter[15][5].x = 1*Scale;
Letter[15][5].y = 4*Scale;
Letter[15][6].x = 0*Scale;
Letter[15][6].y = 3*Scale;
Letter[15][7].x = 0*Scale;
Letter[15][7].y = 1*Scale;
Letter[15][8].x = 1*Scale;
Letter[15][8].y = 0*Scale;
// 1
Letter[16][MAX_POINTS].x = 2;
Letter[16][0].x = 2*Scale;
Letter[16][0].y = 0*Scale;
Letter[16][1].x = 2*Scale;
Letter[16][1].y = 4*Scale;
// 2
Letter[17][MAX_POINTS].x = 9;
Letter[17][0].x = 0*Scale;
Letter[17][0].y = 1*Scale;
Letter[17][1].x = 1*Scale;
Letter[17][1].y = 0*Scale;
Letter[17][2].x = 2*Scale;
Letter[17][2].y = 0*Scale;
Letter[17][3].x = 3*Scale;
Letter[17][3].y = 1*Scale;
Letter[17][4].x = 2*Scale;
Letter[17][4].y = 2*Scale;
Letter[17][5].x = 1*Scale;
Letter[17][5].y = 2*Scale;
Letter[17][6].x = 0*Scale;
Letter[17][6].y = 3*Scale;
Letter[17][7].x = 0*Scale;
Letter[17][7].y = 4*Scale;
Letter[17][8].x = 3*Scale;
Letter[17][8].y = 4*Scale;
// 3
Letter[18][MAX_POINTS].x = 9;
Letter[18][0].x = 0*Scale;
Letter[18][0].y = 0*Scale;
Letter[18][1].x = 2*Scale;
Letter[18][1].y = 0*Scale;
Letter[18][2].x = 3*Scale;
Letter[18][2].y = 1*Scale;
Letter[18][3].x = 2*Scale;
Letter[18][3].y = 2*Scale;
Letter[18][4].x = 1*Scale;
Letter[18][4].y = 2*Scale;
Letter[18][5].x = 2*Scale;
Letter[18][5].y = 2*Scale;
Letter[18][6].x = 3*Scale;
Letter[18][6].y = 3*Scale;
Letter[18][7].x = 2*Scale;
Letter[18][7].y = 4*Scale;
Letter[18][8].x = 0*Scale;
Letter[18][8].y = 4*Scale;
// 4
Letter[19][MAX_POINTS].x = 4;
Letter[19][0].x = 2*Scale;
Letter[19][0].y = 4*Scale;
Letter[19][1].x = 2*Scale;
Letter[19][1].y = 0*Scale;
Letter[19][2].x = 0*Scale;
Letter[19][2].y = 3*Scale;
Letter[19][3].x = 3*Scale;
Letter[19][3].y = 3*Scale;
// 5
Letter[20][MAX_POINTS].x = 7;
Letter[20][0].x = 3*Scale;
Letter[20][0].y = 0*Scale;
Letter[20][1].x = 0*Scale;
Letter[20][1].y = 0*Scale;
Letter[20][2].x = 0*Scale;
Letter[20][2].y = 2*Scale;
Letter[20][3].x = 2*Scale;
Letter[20][3].y = 2*Scale;
Letter[20][4].x = 3*Scale;
Letter[20][4].y = 3*Scale;
Letter[20][5].x = 2*Scale;
Letter[20][5].y = 4*Scale;
Letter[20][6].x = 0*Scale;
Letter[20][6].y = 4*Scale;
// 6
Letter[21][MAX_POINTS].x = 9;
Letter[21][0].x = 3*Scale;
Letter[21][0].y = 0*Scale;
Letter[21][1].x = 1*Scale;
Letter[21][1].y = 0*Scale;
Letter[21][2].x = 0*Scale;
Letter[21][2].y = 1*Scale;
Letter[21][3].x = 0*Scale;
Letter[21][3].y = 3*Scale;
Letter[21][4].x = 1*Scale;
Letter[21][4].y = 4*Scale;
Letter[21][5].x = 2*Scale;
Letter[21][5].y = 4*Scale;
Letter[21][6].x = 3*Scale;
Letter[21][6].y = 3*Scale;
Letter[21][7].x = 3*Scale;
Letter[21][7].y = 2*Scale;
Letter[21][8].x = 0*Scale;
Letter[21][8].y = 2*Scale;
// 7
Letter[22][MAX_POINTS].x = 3;
Letter[22][0].x = 0*Scale;
Letter[22][0].y = 0*Scale;
Letter[22][1].x = 3*Scale;
Letter[22][1].y = 0*Scale;
Letter[22][2].x = 0*Scale;
Letter[22][2].y = 4*Scale;
// 8
Letter[23][MAX_POINTS].x = 9;
Letter[23][0].x = 0*Scale;
Letter[23][0].y = 1*Scale;
Letter[23][1].x = 1*Scale;
Letter[23][1].y = 0*Scale;
Letter[23][2].x = 2*Scale;
Letter[23][2].y = 0*Scale;
Letter[23][3].x = 3*Scale;
Letter[23][3].y = 1*Scale;
Letter[23][4].x = 0*Scale;
Letter[23][4].y = 3*Scale;
Letter[23][5].x = 1*Scale;
Letter[23][5].y = 4*Scale;
Letter[23][6].x = 2*Scale;
Letter[23][6].y = 4*Scale;
Letter[23][7].x = 3*Scale;
Letter[23][7].y = 3*Scale;
Letter[23][8].x = 0*Scale;
Letter[23][8].y = 1*Scale;
// 9
Letter[24][MAX_POINTS].x = 9;
Letter[24][0].x = 0*Scale;
Letter[24][0].y = 4*Scale;
Letter[24][1].x = 2*Scale;
Letter[24][1].y = 4*Scale;
Letter[24][2].x = 3*Scale;
Letter[24][2].y = 3*Scale;
Letter[24][3].x = 3*Scale;
Letter[24][3].y = 1*Scale;
Letter[24][4].x = 2*Scale;
Letter[24][4].y = 0*Scale;
Letter[24][5].x = 1*Scale;
Letter[24][5].y = 0*Scale;
Letter[24][6].x = 0*Scale;
Letter[24][6].y = 1*Scale;
Letter[24][7].x = 0*Scale;
Letter[24][7].y = 2*Scale;
Letter[24][8].x = 3*Scale;
Letter[24][8].y = 2*Scale;
// :
Letter[25][MAX_POINTS].x = 2;
Letter[25][0].x = 2*Scale;
Letter[25][0].y = 1*Scale;
Letter[25][1].x = 2*Scale;
Letter[25][1].y = 3*Scale;
// ;
Letter[26][MAX_POINTS].x = 3;
Letter[26][0].x = 2*Scale;
Letter[26][0].y = 1*Scale;
Letter[26][1].x = 2*Scale;
Letter[26][1].y = 3*Scale;
Letter[26][2].x = 1*Scale;
Letter[26][2].y = 4*Scale;
// <
Letter[27][MAX_POINTS].x = 3;
Letter[27][0].x = 3*Scale;
Letter[27][0].y = 1*Scale;
Letter[27][1].x = 0*Scale;
Letter[27][1].y = 2*Scale;
Letter[27][2].x = 3*Scale;
Letter[27][2].y = 3*Scale;
// =
Letter[28][MAX_POINTS].x = 4;
Letter[28][0].x = 3*Scale;
Letter[28][0].y = 1*Scale;
Letter[28][1].x = 0*Scale;
Letter[28][1].y = 1*Scale;
Letter[28][2].x = 0*Scale;
Letter[28][2].y = 3*Scale;
Letter[28][3].x = 3*Scale;
Letter[28][3].y = 3*Scale;
// >
Letter[29][MAX_POINTS].x = 3;
Letter[29][0].x = 0*Scale;
Letter[29][0].y = 1*Scale;
Letter[29][1].x = 3*Scale;
Letter[29][1].y = 2*Scale;
Letter[29][2].x = 0*Scale;
Letter[29][2].y = 3*Scale;
// ?
Letter[30][MAX_POINTS].x = 7;
Letter[30][0].x = 0*Scale;
Letter[30][0].y = 1*Scale;
Letter[30][1].x = 1*Scale;
Letter[30][1].y = 0*Scale;
Letter[30][2].x = 2*Scale;
Letter[30][2].y = 0*Scale;
Letter[30][3].x = 3*Scale;
Letter[30][3].y = 1*Scale;
Letter[30][4].x = 3*Scale;
Letter[30][4].y = 2*Scale;
Letter[30][5].x = 2*Scale;
Letter[30][5].y = 3*Scale;
Letter[30][6].x = 2*Scale;
Letter[30][6].y = 4*Scale;
// @
Letter[31][MAX_POINTS].x = 12;
Letter[31][0].x = 3*Scale;
Letter[31][0].y = 4*Scale;
Letter[31][1].x = 1*Scale;
Letter[31][1].y = 4*Scale;
Letter[31][2].x = 0*Scale;
Letter[31][2].y = 3*Scale;
Letter[31][3].x = 0*Scale;
Letter[31][3].y = 1*Scale;
Letter[31][4].x = 1*Scale;
Letter[31][4].y = 0*Scale;
Letter[31][5].x = 2*Scale;
Letter[31][5].y = 0*Scale;
Letter[31][6].x = 3*Scale;
Letter[31][6].y = 1*Scale;
Letter[31][7].x = 3*Scale;
Letter[31][7].y = 2*Scale;
Letter[31][8].x = 2*Scale;
Letter[31][8].y = 3*Scale;
Letter[31][9].x = 1*Scale;
Letter[31][9].y = 2*Scale;
Letter[31][10].x = 2*Scale;
Letter[31][10].y = 1*Scale;
Letter[31][11].x = 3*Scale;
Letter[31][11].y = 1*Scale;
// A
Letter[32][MAX_POINTS].x = 6;
Letter[32][0].x = 0*Scale;
Letter[32][0].y = 4*Scale;
Letter[32][1].x = 0*Scale;
Letter[32][1].y = 0*Scale;
Letter[32][2].x = 3*Scale;
Letter[32][2].y = 0*Scale;
Letter[32][3].x = 3*Scale;
Letter[32][3].y = 4*Scale;
Letter[32][4].x = 3*Scale;
Letter[32][4].y = 2*Scale;
Letter[32][5].x = 0*Scale;
Letter[32][5].y = 2*Scale;
// B
Letter[33][MAX_POINTS].x = 8;
Letter[33][0].x = 0*Scale;
Letter[33][0].y = 0*Scale;
Letter[33][1].x = 0*Scale;
Letter[33][1].y = 4*Scale;
Letter[33][2].x = 3*Scale;
Letter[33][2].y = 4*Scale;
Letter[33][3].x = 3*Scale;
Letter[33][3].y = 3*Scale;
Letter[33][4].x = 0*Scale;
Letter[33][4].y = 2*Scale;
Letter[33][5].x = 3*Scale;
Letter[33][5].y = 1*Scale;
Letter[33][6].x = 3*Scale;
Letter[33][6].y = 0*Scale;
Letter[33][7].x = 0*Scale;
Letter[33][7].y = 0*Scale;
// C
Letter[34][MAX_POINTS].x = 6;
Letter[34][0].x = 3*Scale;
Letter[34][0].y = 0*Scale;
Letter[34][1].x = 1*Scale;
Letter[34][1].y = 0*Scale;
Letter[34][2].x = 0*Scale;
Letter[34][2].y = 1*Scale;
Letter[34][3].x = 0*Scale;
Letter[34][3].y = 3*Scale;
Letter[34][4].x = 1*Scale;
Letter[34][4].y = 4*Scale;
Letter[34][5].x = 3*Scale;
Letter[34][5].y = 4*Scale;
// D
Letter[35][MAX_POINTS].x = 6;
Letter[35][0].x = 0*Scale;
Letter[35][0].y = 0*Scale;
Letter[35][1].x = 0*Scale;
Letter[35][1].y = 4*Scale;
Letter[35][2].x = 1*Scale;
Letter[35][2].y = 4*Scale;
Letter[35][3].x = 3*Scale;
Letter[35][3].y = 2*Scale;
Letter[35][4].x = 1*Scale;
Letter[35][4].y = 0*Scale;
Letter[35][5].x = 0*Scale;
Letter[35][5].y = 0*Scale;
// E
Letter[36][MAX_POINTS].x = 7;
Letter[36][0].x = 3*Scale;
Letter[36][0].y = 0*Scale;
Letter[36][1].x = 0*Scale;
Letter[36][1].y = 0*Scale;
Letter[36][2].x = 0*Scale;
Letter[36][2].y = 2*Scale;
Letter[36][3].x = 2*Scale;
Letter[36][3].y = 2*Scale;
Letter[36][4].x = 0*Scale;
Letter[36][4].y = 2*Scale;
Letter[36][5].x = 0*Scale;
Letter[36][5].y = 4*Scale;
Letter[36][6].x = 3*Scale;
Letter[36][6].y = 4*Scale;
// F
Letter[37][MAX_POINTS].x = 6;
Letter[37][0].x = 3*Scale;
Letter[37][0].y = 0*Scale;
Letter[37][1].x = 0*Scale;
Letter[37][1].y = 0*Scale;
Letter[37][2].x = 0*Scale;
Letter[37][2].y = 2*Scale;
Letter[37][3].x = 2*Scale;
Letter[37][3].y = 2*Scale;
Letter[37][4].x = 0*Scale;
Letter[37][4].y = 2*Scale;
Letter[37][5].x = 0*Scale;
Letter[37][5].y = 4*Scale;
// G
Letter[38][MAX_POINTS].x = 6;
Letter[38][0].x = 3*Scale;
Letter[38][0].y = 0*Scale;
Letter[38][1].x = 0*Scale;
Letter[38][1].y = 0*Scale;
Letter[38][2].x = 0*Scale;
Letter[38][2].y = 4*Scale;
Letter[38][3].x = 3*Scale;
Letter[38][3].y = 4*Scale;
Letter[38][4].x = 3*Scale;
Letter[38][4].y = 2*Scale;
Letter[38][5].x = 1*Scale;
Letter[38][5].y = 2*Scale;
// H
Letter[39][MAX_POINTS].x = 6;
Letter[39][0].x = 0*Scale;
Letter[39][0].y = 0*Scale;
Letter[39][1].x = 0*Scale;
Letter[39][1].y = 4*Scale;
Letter[39][2].x = 0*Scale;
Letter[39][2].y = 2*Scale;
Letter[39][3].x = 3*Scale;
Letter[39][3].y = 2*Scale;
Letter[39][4].x = 3*Scale;
Letter[39][4].y = 0*Scale;
Letter[39][5].x = 3*Scale;
Letter[39][5].y = 4*Scale;
// I
Letter[40][MAX_POINTS].x = 6;
Letter[40][0].x = 1*Scale;
Letter[40][0].y = 0*Scale;
Letter[40][1].x = 3*Scale;
Letter[40][1].y = 0*Scale;
Letter[40][2].x = 2*Scale;
Letter[40][2].y = 0*Scale;
Letter[40][3].x = 2*Scale;
Letter[40][3].y = 4*Scale;
Letter[40][4].x = 1*Scale;
Letter[40][4].y = 4*Scale;
Letter[40][5].x = 3*Scale;
Letter[40][5].y = 4*Scale;
// J
Letter[41][MAX_POINTS].x = 6;
Letter[41][0].x = 1*Scale;
Letter[41][0].y = 0*Scale;
Letter[41][1].x = 3*Scale;
Letter[41][1].y = 0*Scale;
Letter[41][2].x = 2*Scale;
Letter[41][2].y = 0*Scale;
Letter[41][3].x = 2*Scale;
Letter[41][3].y = 4*Scale;
Letter[41][4].x = 0*Scale;
Letter[41][4].y = 4*Scale;
Letter[41][5].x = 0*Scale;
Letter[41][5].y = 3*Scale;
// K
Letter[42][MAX_POINTS].x = 6;
Letter[42][0].x = 0*Scale;
Letter[42][0].y = 0*Scale;
Letter[42][1].x = 0*Scale;
Letter[42][1].y = 4*Scale;
Letter[42][2].x = 0*Scale;
Letter[42][2].y = 2*Scale;
Letter[42][3].x = 3*Scale;
Letter[42][3].y = 0*Scale;
Letter[42][4].x = 0*Scale;
Letter[42][4].y = 2*Scale;
Letter[42][5].x = 3*Scale;
Letter[42][5].y = 4*Scale;
// L
Letter[43][MAX_POINTS].x = 3;
Letter[43][0].x = 0*Scale;
Letter[43][0].y = 0*Scale;
Letter[43][1].x = 0*Scale;
Letter[43][1].y = 4*Scale;
Letter[43][2].x = 3*Scale;
Letter[43][2].y = 4*Scale;
// M
Letter[44][MAX_POINTS].x = 6;
Letter[44][0].x = 0*Scale;
Letter[44][0].y = 4*Scale;
Letter[44][1].x = 0*Scale;
Letter[44][1].y = 0*Scale;
Letter[44][2].x = 1*Scale;
Letter[44][2].y = 2*Scale;
Letter[44][3].x = 2*Scale;
Letter[44][3].y = 2*Scale;
Letter[44][4].x = 3*Scale;
Letter[44][4].y = 0*Scale;
Letter[44][5].x = 3*Scale;
Letter[44][5].y = 4*Scale;
// N
Letter[45][MAX_POINTS].x = 4;
Letter[45][0].x = 0*Scale;
Letter[45][0].y = 4*Scale;
Letter[45][1].x = 0*Scale;
Letter[45][1].y = 0*Scale;
Letter[45][2].x = 3*Scale;
Letter[45][2].y = 4*Scale;
Letter[45][3].x = 3*Scale;
Letter[45][3].y = 0*Scale;
// O
Letter[46][MAX_POINTS].x = 9;
Letter[46][0].x = 0*Scale;
Letter[46][0].y = 1*Scale;
Letter[46][1].x = 0*Scale;
Letter[46][1].y = 3*Scale;
Letter[46][2].x = 1*Scale;
Letter[46][2].y = 4*Scale;
Letter[46][3].x = 2*Scale;
Letter[46][3].y = 4*Scale;
Letter[46][4].x = 3*Scale;
Letter[46][4].y = 3*Scale;
Letter[46][5].x = 3*Scale;
Letter[46][5].y = 1*Scale;
Letter[46][6].x = 2*Scale;
Letter[46][6].y = 0*Scale;
Letter[46][7].x = 1*Scale;
Letter[46][7].y = 0*Scale;
Letter[46][8].x = 0*Scale;
Letter[46][8].y = 1*Scale;
// P
Letter[47][MAX_POINTS].x = 5;
Letter[47][0].x = 0*Scale;
Letter[47][0].y = 4*Scale;
Letter[47][1].x = 0*Scale;
Letter[47][1].y = 0*Scale;
Letter[47][2].x = 3*Scale;
Letter[47][2].y = 0*Scale;
Letter[47][3].x = 3*Scale;
Letter[47][3].y = 2*Scale;
Letter[47][4].x = 0*Scale;
Letter[47][4].y = 2*Scale;
// Q
Letter[48][MAX_POINTS].x = 6;
Letter[48][0].x = 2*Scale;
Letter[48][0].y = 3*Scale;
Letter[48][1].x = 3*Scale;
Letter[48][1].y = 4*Scale;
Letter[48][2].x = 0*Scale;
Letter[48][2].y = 4*Scale;
Letter[48][3].x = 0*Scale;
Letter[48][3].y = 0*Scale;
Letter[48][4].x = 3*Scale;
Letter[48][4].y = 0*Scale;
Letter[48][5].x = 3*Scale;
Letter[48][5].y = 4*Scale;
// R
Letter[49][MAX_POINTS].x = 6;
Letter[49][0].x = 0*Scale;
Letter[49][0].y = 4*Scale;
Letter[49][1].x = 0*Scale;
Letter[49][1].y = 0*Scale;
Letter[49][2].x = 3*Scale;
Letter[49][2].y = 0*Scale;
Letter[49][3].x = 3*Scale;
Letter[49][3].y = 2*Scale;
Letter[49][4].x = 0*Scale;
Letter[49][4].y = 2*Scale;
Letter[49][5].x = 3*Scale;
Letter[49][5].y = 4*Scale;
// S
Letter[50][MAX_POINTS].x = 8;
Letter[50][0].x = 3*Scale;
Letter[50][0].y = 0*Scale;
Letter[50][1].x = 1*Scale;
Letter[50][1].y = 0*Scale;
Letter[50][2].x = 0*Scale;
Letter[50][2].y = 1*Scale;
Letter[50][3].x = 1*Scale;
Letter[50][3].y = 2*Scale;
Letter[50][4].x = 2*Scale;
Letter[50][4].y = 2*Scale;
Letter[50][5].x = 3*Scale;
Letter[50][5].y = 3*Scale;
Letter[50][6].x = 2*Scale;
Letter[50][6].y = 4*Scale;
Letter[50][7].x = 0*Scale;
Letter[50][7].y = 4*Scale;
// T
Letter[51][MAX_POINTS].x = 4;
Letter[51][0].x = 1*Scale;
Letter[51][0].y = 0*Scale;
Letter[51][1].x = 3*Scale;
Letter[51][1].y = 0*Scale;
Letter[51][2].x = 2*Scale;
Letter[51][2].y = 0*Scale;
Letter[51][3].x = 2*Scale;
Letter[51][3].y = 4*Scale;
// U
Letter[52][MAX_POINTS].x = 6;
Letter[52][0].x = 0*Scale;
Letter[52][0].y = 0*Scale;
Letter[52][1].x = 0*Scale;
Letter[52][1].y = 3*Scale;
Letter[52][2].x = 1*Scale;
Letter[52][2].y = 4*Scale;
Letter[52][3].x = 2*Scale;
Letter[52][3].y = 4*Scale;
Letter[52][4].x = 3*Scale;
Letter[52][4].y = 3*Scale;
Letter[52][5].x = 3*Scale;
Letter[52][5].y = 0*Scale;
// V
Letter[53][MAX_POINTS].x = 4;
Letter[53][0].x = 0*Scale;
Letter[53][0].y = 0*Scale;
Letter[53][1].x = 1*Scale;
Letter[53][1].y = 4*Scale;
Letter[53][2].x = 2*Scale;
Letter[53][2].y = 4*Scale;
Letter[53][3].x = 3*Scale;
Letter[53][3].y = 0*Scale;
// W
Letter[54][MAX_POINTS].x = 6;
Letter[54][0].x = 0*Scale;
Letter[54][0].y = 0*Scale;
Letter[54][1].x = 0*Scale;
Letter[54][1].y = 4*Scale;
Letter[54][2].x = 1*Scale;
Letter[54][2].y = 3*Scale;
Letter[54][3].x = 2*Scale;
Letter[54][3].y = 3*Scale;
Letter[54][4].x = 3*Scale;
Letter[54][4].y = 4*Scale;
Letter[54][5].x = 3*Scale;
Letter[54][5].y = 0*Scale;
// X
Letter[55][MAX_POINTS].x = 7;
Letter[55][0].x = 1*Scale;
Letter[55][0].y = 0*Scale;
Letter[55][1].x = 2*Scale;
Letter[55][1].y = 2*Scale;
Letter[55][2].x = 3*Scale;
Letter[55][2].y = 0*Scale;
Letter[55][3].x = 2*Scale;
Letter[55][3].y = 2*Scale;
Letter[55][4].x = 1*Scale;
Letter[55][4].y = 4*Scale;
Letter[55][5].x = 2*Scale;
Letter[55][5].y = 2*Scale;
Letter[55][6].x = 3*Scale;
Letter[55][6].y = 4*Scale;
// Y
Letter[56][MAX_POINTS].x = 5;
Letter[56][0].x = 1*Scale;
Letter[56][0].y = 0*Scale;
Letter[56][1].x = 2*Scale;
Letter[56][1].y = 2*Scale;
Letter[56][2].x = 3*Scale;
Letter[56][2].y = 0*Scale;
Letter[56][3].x = 2*Scale;
Letter[56][3].y = 2*Scale;
Letter[56][4].x = 2*Scale;
Letter[56][4].y = 4*Scale;
// Z
Letter[57][MAX_POINTS].x = 4;
Letter[57][0].x = 0*Scale;
Letter[57][0].y = 0*Scale;
Letter[57][1].x = 3*Scale;
Letter[57][1].y = 0*Scale;
Letter[57][2].x = 0*Scale;
Letter[57][2].y = 4*Scale;
Letter[57][3].x = 3*Scale;
Letter[57][3].y = 4*Scale;
for (Digit = 0;
Digit < MAX_TEXT && TextString[Digit] != '\0';
++Digit)
{
if (TextString[Digit] == '\n')
{
xOffset = xOffsetOrig;
yOffset += 5*Scale + 2;
}
else if (TextString[Digit] >= '!'
&& TextString[Digit] <= 'Z')
{
for (Count = 0;
Count < Letter[TextString[Digit]-'!'][MAX_POINTS].x;
++Count)
{
DisplayFrame[Digit][Count].x = Letter[TextString[Digit]-'!'][Count].x
+ xOffset;
DisplayFrame[Digit][Count].y = Letter[TextString[Digit]-'!'][Count].y
+ yOffset;
}
DisplayFrame[Digit][MAX_POINTS].x = Letter[TextString[Digit]-'!'][MAX_POINTS].x;
xOffset += 4*Scale;
}
else
xOffset += 4*Scale;
}
}
|
The text string in an instance of this class can be made visible or hidden at any time by calling one of the function SetVisible. And the current visible state of the instance of this class can be checked by calling the member function GetVisible.
REF: 6.3
|
void Text::SetVisible(short NewVisible)
{
if (NewVisible != LastVisible)
{
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = TRUE;
FrameCount = Frames;
}
}
short Text::GetVisible()
{
return Active;
}
|
|
Many instances of the AstroRock class are active at the same time, however this class is not particually complex. The rock object just does what other objects tell it to do.
REF: 7.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __ASTROROCK_HPP
#define __ASTROROCK_HPP
class AstroRock
{
public:
enum
{
FRAMES = 3,
FRAME_POINTS = 9,
ROCK_WIDTH = 36,
ROCK_HEIGHT = 36,
ERASE = 3,
INACTIVE = 4,
NEW_POSITION = -1,
HYPERSPACE = -500,
};
AstroRock();
~AstroRock();
void Draw(HDC hdc);
void Move();
void SetArea(HWND NewhWnd,
RECT* ClientRect,
short NewxOffset = NEW_POSITION,
short NewyOffset = NEW_POSITION,
short NewSize = NEW_POSITION);
short Collide(short xPos, short yPos, short Width, short Height);
short GetSize();
void Destroy();
short GetXOffset();
short GetYOffset();
private:
HWND hWnd;
short xMax;
short yMax;
short Size;
short xOffset;
short yOffset;
short xVelocity;
short yVelocity;
POINT Frame[FRAMES][FRAME_POINTS];
POINT DisplayFrame[FRAME_POINTS];
POINT OldFrame[FRAME_POINTS];
};
#endif
|
|
Many instances of the AstroRock class are active at the same time, however this class is not particually complex. The rock object just does what other objects tell it to do. The drawing data, arrays of x-y co-ordinates are defined in the class constructor. The drawing data consists of an array of three sizes of rock. Each instance of the class is set to inactive by default.
REF: 8.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include "ASTROROCK.HPP"
AstroRock::AstroRock()
{
hWnd = NULL;
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = 0;
yVelocity = 0;
for (Size = 0; Size < FRAMES; ++Size)
{
Frame[Size][0].x = -30 / (Size*Size+1);
Frame[Size][0].y = -22 / (Size*Size+1);
Frame[Size][1].x = -5 / (Size*Size+1);
Frame[Size][1].y = -32 / (Size*Size+1);
Frame[Size][2].x = +35 / (Size*Size+1);
Frame[Size][2].y = -17 / (Size*Size+1);
Frame[Size][3].x = +25 / (Size*Size+1);
Frame[Size][3].y = +28 / (Size*Size+1);
Frame[Size][4].x = +12 / (Size*Size+1);
Frame[Size][4].y = -2 / (Size*Size+1);
Frame[Size][5].x = +10 / (Size*Size+1);
Frame[Size][5].y = +28 / (Size*Size+1);
Frame[Size][6].x = -20 / (Size*Size+1);
Frame[Size][6].y = +33 / (Size*Size+1);
Frame[Size][7].x = -37 / (Size*Size+1);
Frame[Size][7].y = +5 / (Size*Size+1);
Frame[Size][8].x = -30 / (Size*Size+1);
Frame[Size][8].y = -22 / (Size*Size+1);
}
Size = INACTIVE;
}
AstroRock::~AstroRock()
{
}
|
Each of the game objects has a draw function which draws the current state of the object onto a Windows graphics context using Windows GDI calls. The object is only drawn if the instance of the object is flagged as active.
REF: 8.1
|
void AstroRock::Draw(HDC hdc)
{
short Count;
HPEN ColourPen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
if (Size < INACTIVE)
{
ColourPen = CreatePen(PS_SOLID, 0, RGB(0x55, 0xDD, 0x55));
BackgroundPen = CreatePen(PS_SOLID, 0, GetBkColor(hdc));
OldPen = SelectObject(hdc, BackgroundPen);
Polyline(hdc, OldFrame, FRAME_POINTS);
if (Size == ERASE)
Size = INACTIVE;
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = Frame[Size][Count].x + xOffset;
DisplayFrame[Count].y = Frame[Size][Count].y + yOffset;
}
SelectObject(hdc, ColourPen);
Polyline(hdc, DisplayFrame, FRAME_POINTS);
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
}
}
|
If the instance of the object is active, move the object by it's current velocity. When the object moves off one side of the display, move it back on to the opposite side of the display.
REF: 8.2
|
void AstroRock::Move()
{
if (Size < INACTIVE)
{
if (xOffset < 0 - ROCK_WIDTH)
xOffset = xMax + ROCK_WIDTH;
else if (xOffset > xMax + ROCK_WIDTH)
xOffset = 0 - ROCK_WIDTH;
if (yOffset < 0 - ROCK_HEIGHT)
yOffset = yMax + ROCK_HEIGHT;
else if (yOffset > yMax + ROCK_HEIGHT)
yOffset = 0 - ROCK_HEIGHT;
xOffset += xVelocity;
yOffset += yVelocity;
}
}
|
Re-initialise the object. Move the object to a specified position, or move the object to a random starting position. Set the velocity of the object to a random velocity, the smaller the object size, the faster the object can move.
REF: 8.3
|
void AstroRock::SetArea(HWND NewhWnd,
RECT* ClientRect,
short NewxOffset,
short NewyOffset,
short NewSize)
{
hWnd = NewhWnd;
xMax = (short)(ClientRect->right - ClientRect->left);
yMax = (short)(ClientRect->bottom - ClientRect->top);
if (NewxOffset == NEW_POSITION)
{
Size = 0;
if ((short)((float)rand()/RAND_MAX * 2) == FALSE)
{
xOffset = (short)((float)rand()/RAND_MAX * xMax);
yOffset = yMax * (short)((float)rand()/RAND_MAX * 2);
}
else
{
yOffset = (short)((float)rand()/RAND_MAX * yMax);
xOffset = xMax * (short)((float)rand()/RAND_MAX * 2);
}
}
else
{
Size = NewSize;
xOffset = NewxOffset;
yOffset = NewyOffset;
}
do
{
xVelocity = (short)((float)rand()/RAND_MAX*6*(Size+1) - 3*(Size+1));
yVelocity = (short)((float)rand()/RAND_MAX*6*(Size+1) - 3*(Size+1));
} while(xVelocity == 0 || yVelocity == 0);
}
|
If the object is active, check if the object has collided with a specific location. If a collision has occurred, make the object smaller and calculate it's new velocity. Return a flag if a collision occurred.
REF: 8.4
|
short AstroRock::Collide(short xPos, short yPos, short Width, short Height)
{
short Collision = FALSE;
if (Size < INACTIVE)
{
if ((Collision = xPos + Width/2 > xOffset - ROCK_WIDTH / (Size*Size+1)
&& xPos - Width/2 < xOffset + ROCK_WIDTH / (Size*Size+1)
&& yPos + Height/2 > yOffset - ROCK_HEIGHT / (Size*Size+1)
&& yPos - Height/2 < yOffset + ROCK_HEIGHT / (Size*Size+1)) == TRUE)
{
++Size;
do
{
xVelocity = (short)((float)rand()/RAND_MAX*6*(Size+1) - 3*(Size+1));
yVelocity = (short)((float)rand()/RAND_MAX*6*(Size+1) - 3*(Size+1));
} while(xVelocity == 0 || yVelocity == 0);
}
}
return Collision;
}
|
If the object is to be destroyed, move the object off of the display.
REF: 8.5
|
void AstroRock::Destroy()
{
Size = ERASE;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
Return various information about the object if requested.
REF: 8.6
|
short AstroRock::GetSize()
{
return Size;
}
short AstroRock::GetXOffset()
{
return xOffset;
}
short AstroRock::GetYOffset()
{
return yOffset;
}
|
|
This is the most complex object in the application. As it is controlled by the player it requires a lot of manipulation. It also owns other game objects such as AstroShot, which represents the number of shots which the player can fire at any one time. And a number object for keeping track of the players score.
REF: 9.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __ASTROSHIP_HPP
#define __ASTROSHIP_HPP
class AstroShip
{
public:
enum
{
FRAMES = 63,
ERASE_FRAME = FRAMES+1,
FRAME_POINTS = 5,
THRUST_POINTS = 8,
SHIP_WIDTH = 25,
SHIP_HEIGHT = 25,
SHIP_START_ANGLE = 31,
MAX_EXPLODE_FRAME = 40,
LIFE_XGAP = 30,
LIFE_XOFFSET = 150,
LIFE_YOFFSET = 35,
LIVES_HEIGHT = 34,
LIVES_WIDTH = 100,
MAX_LIVES = 3,
SCORE_XOFFSET = 20,
SCORE_YOFFSET = 20,
SCORE_SCALE = 5,
MAX_SHOTS = 10,
HYPERSPACE = -500,
HYPER_FRAMES = 20,
};
AstroShip();
~AstroShip();
void Draw(HDC hdc);
void IncAngle(short Direction);
void Thrust();
void Shoot();
void Move();
void Reset();
void Hyperspace();
void SetArea(HWND NewhWnd, RECT* ClientRect);
short Collide(short xPos, short yPos, short Width, short Height);
void SetCrash(short NewCrash);
short GetCrash();
short GetXOffset();
short GetYOffset();
short GetWidth();
short GetHeight();
long GetScore();
void SetScore(long NewScore);
short GetLives();
AstroShot& GetShot(short ShotCount);
short GetShotCount();
private:
double OneDegree;
double FrameStep;
HWND hWnd;
short Lives;
short Crash;
short ThrustFlag;
short Fade;
short xMax;
short yMax;
short Angle;
short xOffset;
short yOffset;
short ShotIndex;
float xVelocity;
float yVelocity;
short ExplodeFrame;
short HyperCount;
Number PlayerScore;
AstroShot Shots[MAX_SHOTS];
POINT LifeFrame[FRAME_POINTS];
POINT LifeDisplayFrame[FRAME_POINTS];
POINT Frame[FRAMES][FRAME_POINTS];
POINT DisplayFrame[FRAME_POINTS*2];
POINT OldFrame[FRAME_POINTS*2];
POINT ExplodeDirection[FRAME_POINTS*2];
POINT ThrustTrail[THRUST_POINTS];
};
#endif
|
|
This is the most complex object in the application. As it is controlled by the player it requires a lot of manipulation. It also owns other game objects such as AstroShot, which represents the number of shots which the player can fire at any one time. And a number object for keeping track of the players score. The drawing data, arrays of x-y co-ordinates are defined in the class constructor. The drawing data consists of an array of sixty three angles of rotation for the ship. The ship's rotation is performed by moving from one index of the array to the next.
REF: 10.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include <math.h>
#include <mmsystem.h>
#include "NUMBER.HPP"
#include "ASTROSHOT.HPP"
#include "ASTROSHIP.HPP"
AstroShip::AstroShip()
{
OneDegree = (double)6.3 / (double)360;
FrameStep = (double)0.1;
hWnd = NULL;
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = (short)0;
yVelocity = (short)0;
Crash = FALSE;
ThrustFlag = FALSE;
Fade = 0;
Lives = MAX_LIVES;
ExplodeFrame = 0;
ShotIndex = 0;
HyperCount = FALSE;
Angle = SHIP_START_ANGLE;
LifeFrame[0].x = (long)(19 * sin(FrameStep*Angle + OneDegree*0));
LifeFrame[0].y = (long)(19 * cos(FrameStep*Angle + OneDegree*0));
LifeFrame[1].x = (long)(16 * sin(FrameStep*Angle + OneDegree*140));
LifeFrame[1].y = (long)(16 * cos(FrameStep*Angle + OneDegree*140));
LifeFrame[2].x = (long)(8 * sin(FrameStep*Angle + OneDegree*180));
LifeFrame[2].y = (long)(8 * cos(FrameStep*Angle + OneDegree*180));
LifeFrame[3].x = (long)(16 * sin(FrameStep*Angle + OneDegree*220));
LifeFrame[3].y = (long)(16 * cos(FrameStep*Angle + OneDegree*220));
LifeFrame[4].x = (long)(19 * sin(FrameStep*Angle + OneDegree*0));
LifeFrame[4].y = (long)(19 * cos(FrameStep*Angle + OneDegree*0));
for (Angle = 0; Angle < FRAMES; ++Angle)
{
Frame[Angle][0].x = (long)(16 * sin(FrameStep*Angle + OneDegree*0));
Frame[Angle][0].y = (long)(16 * cos(FrameStep*Angle + OneDegree*0));
Frame[Angle][1].x = (long)(13 * sin(FrameStep*Angle + OneDegree*140));
Frame[Angle][1].y = (long)(13 * cos(FrameStep*Angle + OneDegree*140));
Frame[Angle][2].x = (long)(5 * sin(FrameStep*Angle + OneDegree*180));
Frame[Angle][2].y = (long)(5 * cos(FrameStep*Angle + OneDegree*180));
Frame[Angle][3].x = (long)(13 * sin(FrameStep*Angle + OneDegree*220));
Frame[Angle][3].y = (long)(13 * cos(FrameStep*Angle + OneDegree*220));
Frame[Angle][4].x = (long)(16 * sin(FrameStep*Angle + OneDegree*0));
Frame[Angle][4].y = (long)(16 * cos(FrameStep*Angle + OneDegree*0));
}
Angle = SHIP_START_ANGLE;
}
AstroShip::~AstroShip()
{
}
|
The draw function for the ship is quite complex. It must draw the ship under usual circumstances. It must also draw a thrust trail when the thrust is active. If a life is lost the draw function splits the ship into pieces and fades the pieces of ship out. In addition the function draws the number of ships remaining and the player score.
REF: 10.1
|
void AstroShip::Draw(HDC hdc)
{
short Count;
short LifeCount;
HPEN ColourPen;
HPEN FadePen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
for (Count = 0; Count < MAX_SHOTS; ++Count)
Shots[Count].Draw(hdc);
/***********************/
/* Create pens to use. */
/***********************/
ColourPen = CreatePen(PS_SOLID, 0, RGB(0x55, 0xDD, 0x55));
FadePen = CreatePen(PS_SOLID, 0, RGB(0x55 - Fade, 0xDD - 2*Fade, 0x55 - Fade));
BackgroundPen = CreatePen(PS_SOLID, 0, GetBkColor(hdc));
OldPen = SelectObject(hdc, BackgroundPen);
if (Lives != FALSE || ExplodeFrame != MAX_EXPLODE_FRAME)
{
/*********************/
/* Draw intact ship. */
/*********************/
if (Crash == FALSE)
{
/********************************/
/* Plot ships current position. */
/********************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = Frame[Angle][Count].x + xOffset;
DisplayFrame[Count].y = Frame[Angle][Count].y + yOffset;
}
SelectObject(hdc, BackgroundPen);
if (ExplodeFrame >= ERASE_FRAME)
{
ExplodeFrame = FALSE;
/************************************/
/* Erase previous position of ship. */
/************************************/
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
MoveToEx(hdc, OldFrame[Count].x, OldFrame[Count].y, NULL);
LineTo(hdc, OldFrame[Count+1].x, OldFrame[Count+1].y);
}
}
/************************************/
/* Erase previous position of ship. */
/************************************/
Polyline(hdc, OldFrame, FRAME_POINTS);
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
SelectObject(hdc, ColourPen);
Polyline(hdc, DisplayFrame, FRAME_POINTS);
/******************/
/* Remove thrust. */
/******************/
SelectObject(hdc, BackgroundPen);
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
MoveToEx(hdc, ThrustTrail[Count].x, ThrustTrail[Count].y, NULL);
LineTo(hdc, ThrustTrail[Count].x + 1, ThrustTrail[Count].y + 1);
}
/*****************************************/
/* Add thrust point if currently active. */
/*****************************************/
if (ThrustFlag == TRUE)
{
SelectObject(hdc, ColourPen);
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
ThrustTrail[Count].x = xOffset
+ (short)((float)rand()/RAND_MAX * 7)-3
+ (long)(15 * sin(FrameStep*Angle + OneDegree*180));
ThrustTrail[Count].y = yOffset
+ (short)((float)rand()/RAND_MAX * 7)-3
+ (long)(15 * cos(FrameStep*Angle + OneDegree*180));
MoveToEx(hdc, ThrustTrail[Count].x, ThrustTrail[Count].y, NULL);
LineTo(hdc, 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 == FALSE)
{
--Lives;
/************************************/
/* Erase previous position of ship. */
/************************************/
SelectObject(hdc, BackgroundPen);
Polyline(hdc, OldFrame, FRAME_POINTS);
/******************/
/* Remove thrust. */
/******************/
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
MoveToEx(hdc, ThrustTrail[Count].x, ThrustTrail[Count].y, NULL);
LineTo(hdc, 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)((float)rand()/RAND_MAX * 3)-1;
} while (ExplodeDirection[Count].x == 0);
do
{
ExplodeDirection[Count].y = (short)((float)rand()/RAND_MAX * 3)-1;
} 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 = Frame[Angle][FRAME_POINTS-1].x + xOffset;
DisplayFrame[0].y = Frame[Angle][FRAME_POINTS-1].y + yOffset;
OldFrame[0].x = Frame[Angle][FRAME_POINTS-1].x + xOffset;
OldFrame[0].y = Frame[Angle][FRAME_POINTS-1].y + yOffset;
DisplayFrame[FRAME_POINTS*2-1].x = Frame[Angle][FRAME_POINTS-1].x + xOffset;
DisplayFrame[FRAME_POINTS*2-1].y = Frame[Angle][FRAME_POINTS-1].y + yOffset;
OldFrame[FRAME_POINTS*2-1].x = Frame[Angle][FRAME_POINTS-1].x + xOffset;
OldFrame[FRAME_POINTS*2-1].y = Frame[Angle][FRAME_POINTS-1].y + yOffset;
for (Count = 0; Count < FRAME_POINTS-1; ++Count)
{
DisplayFrame[Count*2+1].x = Frame[Angle][Count].x + xOffset;
DisplayFrame[Count*2+1].y = Frame[Angle][Count].y + yOffset;
DisplayFrame[Count*2+2].x = Frame[Angle][Count].x + xOffset;
DisplayFrame[Count*2+2].y = Frame[Angle][Count].y + yOffset;
OldFrame[Count*2+1].x = Frame[Angle][Count].x + xOffset;
OldFrame[Count*2+1].y = Frame[Angle][Count].y + yOffset;
OldFrame[Count*2+2].x = Frame[Angle][Count].x + xOffset;
OldFrame[Count*2+2].y = Frame[Angle][Count].y + yOffset;
}
}
/************************************/
/* Erase previous position of ship. */
/************************************/
SelectObject(hdc, BackgroundPen);
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
MoveToEx(hdc, OldFrame[Count].x, OldFrame[Count].y, NULL);
LineTo(hdc, 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;
SelectObject(hdc, 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;
MoveToEx(hdc, DisplayFrame[Count].x, DisplayFrame[Count].y, NULL);
LineTo(hdc, 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 != FALSE && ExplodeFrame == MAX_EXPLODE_FRAME)
{
ExplodeFrame = FALSE;
Crash = FALSE;
ThrustFlag = FALSE;
Fade = 0;
Angle = SHIP_START_ANGLE;
xOffset = xMax/2;
yOffset = 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 = LifeFrame[Count].x
+ (xMax - LIFE_XOFFSET)
+ (LifeCount+1)*LIFE_XGAP;
LifeDisplayFrame[Count].y = LifeFrame[Count].y
+ LIFE_YOFFSET;
}
/************************************/
/* Erase previous position of ship. */
/************************************/
SelectObject(hdc, BackgroundPen);
Polyline(hdc, LifeDisplayFrame, FRAME_POINTS);
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
if (Lives > LifeCount)
{
SelectObject(hdc, ColourPen);
Polyline(hdc, LifeDisplayFrame, FRAME_POINTS);
}
}
}
/*********************************************/
/* Restore default pen and delete used pens. */
/*********************************************/
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
DeleteObject(FadePen);
/******************/
/* Redraw scores. */
/******************/
PlayerScore.Draw(hdc);
}
|
The IncAngle member function allows the ship to be rotated clockwise or anti-clockwise.
REF: 10.2
|
void AstroShip::IncAngle(short Direction)
{
if (Crash == FALSE)
{
if (Direction == FALSE)
{
++Angle;
if (Angle >= FRAMES)
Angle = 0;
}
else
{
--Angle;
if (Angle < 0)
Angle = FRAMES-1;
}
}
}
|
The thrust member function increases the velocity of this ship in the direction it is pointing. To slow the ship down the player has to turn the ship in the opposite direction and thrust.
REF: 10.3
|
void AstroShip::Thrust()
{
ThrustFlag = TRUE;
xVelocity += (float)sin(FrameStep*Angle + OneDegree*0);
yVelocity += (float)cos(FrameStep*Angle + OneDegree*0);
}
|
The Shoot member function allows a player to fire a shot from the ship. There are an array of instances of the shot object which can be fired simultaneously.
REF: 10.4
|
void AstroShip::Shoot()
{
if (Crash == FALSE)
{
Shots[ShotIndex].SetArea(hWnd,
xMax,
yMax,
xOffset,
yOffset,
xVelocity + 10*(float)sin(FrameStep*Angle + OneDegree*0),
yVelocity + 10*(float)cos(FrameStep*Angle + OneDegree*0));
if (++ShotIndex == MAX_SHOTS)
ShotIndex = 0;
}
}
|
The ship moves like other objects. However the ship must also take care of moving its shots and handle when the player moves the ship into hyperspace. When hyperspace is activated, the ship disappears for a few seconds and then reappears at a random location.
REF: 10.5
|
void AstroShip::Move()
{
short Count;
if (HyperCount != FALSE)
{
--HyperCount;
if (HyperCount == FALSE)
{
xOffset = (short)((float)rand()/RAND_MAX * (xMax - 2*SHIP_WIDTH));
yOffset = (short)((float)rand()/RAND_MAX * (yMax - 2*SHIP_HEIGHT));
}
}
for (Count = 0; Count < MAX_SHOTS; ++Count)
Shots[Count].Move();
if (Crash == FALSE)
{
if (xOffset < 0 - SHIP_WIDTH)
xOffset = xMax + SHIP_WIDTH;
else if (xOffset > xMax + SHIP_WIDTH)
xOffset = 0 - SHIP_WIDTH;
if (yOffset < 0 - SHIP_HEIGHT)
yOffset = yMax + SHIP_HEIGHT;
else if (yOffset > yMax + SHIP_HEIGHT)
yOffset = 0 - SHIP_HEIGHT;
xOffset += (short)xVelocity;
yOffset += (short)yVelocity;
}
}
|
The Reset member function takes care of re-initialising the ship at the start of a new game.
REF: 10.6
|
void AstroShip::Reset()
{
if (Lives == FALSE)
{
ExplodeFrame = ERASE_FRAME;
Crash = FALSE;
ThrustFlag = FALSE;
Fade = 0;
Angle = SHIP_START_ANGLE;
xOffset = xMax/2;
yOffset = yMax/2;
xVelocity = (short)0;
yVelocity = (short)0;
Lives = MAX_LIVES;
PlayerScore.SetNumber(0);
}
}
|
The SetArea member function allows an instance of this class to be initialized when the application starts up.
REF: 10.7
|
void AstroShip::SetArea(HWND NewhWnd, RECT* ClientRect)
{
hWnd = NewhWnd;
xMax = (short)(ClientRect->right - ClientRect->left);
yMax = (short)(ClientRect->bottom - ClientRect->top);
xOffset = xMax/2;
yOffset = yMax/2;
PlayerScore.SetLocation(hWnd, SCORE_XOFFSET, SCORE_YOFFSET, SCORE_SCALE);
}
|
The Hyperspace member function is used to initiate a player activating the ship's hyperspace mode.
REF: 10.8
|
void AstroShip::Hyperspace()
{
if (Crash == FALSE && HyperCount == FALSE)
{
HyperCount = HYPER_FRAMES;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = (float)0;
yVelocity = (float)0;
}
}
|
The Collide member function checks to see if the ship has collided with a specific area.
REF: 10.9
|
short AstroShip::Collide(short xPos, short yPos, short Width, short Height)
{
short Collision = FALSE;
if (Crash == FALSE)
if ((Collision = 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)
Crash = TRUE;
return Collision;
}
|
The remaining member functions allow properties of an instance of the ship object to be set and read.
REF: 10.10
|
void AstroShip::SetCrash(short NewCrash)
{
Crash = NewCrash;
}
short AstroShip::GetCrash()
{
return Crash;
}
short AstroShip::GetXOffset()
{
return xOffset;
}
short AstroShip::GetYOffset()
{
return yOffset;
}
short AstroShip::GetWidth()
{
return SHIP_WIDTH;
}
short AstroShip::GetHeight()
{
return SHIP_HEIGHT;
}
long AstroShip::GetScore()
{
return PlayerScore.GetNumber();
}
void AstroShip::SetScore(long NewScore)
{
PlayerScore.SetNumber(NewScore);
}
short AstroShip::GetLives()
{
return Lives;
}
AstroShot& AstroShip::GetShot(short ShotCount)
{
return Shots[ShotCount];
}
short AstroShip::GetShotCount()
{
return MAX_SHOTS;
}
|
|
The AstroShot ojbect is used by two other object, the Ship object to allow the player to shoot and the UFO object to allow the UFO to shoot at the player's ship.
REF: 11.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __ASTROSHOT_HPP
#define __ASTROSHOT_HPP
class AstroShot
{
public:
enum
{
SMALL_SHOT = 0,
LARGE_SHOT = 1,
SMALL_SHOT_FRAMES = 40,
LARGE_SHOT_FRAMES = 20,
ERASE_FRAME = 1,
HYPERSPACE = -500,
};
AstroShot();
~AstroShot();
void Draw(HDC hdc);
void Move();
void SetArea(HWND NewhWnd,
short NewxMax,
short NewyMax,
short NewxOffset,
short NewyOffset,
float NewxVelocity,
float NewyVelocity,
short Size = SMALL_SHOT);
short GetXOffset();
short GetYOffset();
void Destroy();
short Active();
private:
HWND hWnd;
short xMax;
short yMax;
short xOffset;
short yOffset;
short OldxOffset;
short OldyOffset;
float xVelocity;
float yVelocity;
short Size;
short FrameCount;
};
#endif
|
|
The AstroShot ojbect is used by two other object, the Ship object to allow the player to shoot and the UFO object to allow the UFO to shoot at the player's ship.
REF: 12.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include "ASTROSHOT.HPP"
AstroShot::AstroShot()
{
hWnd = NULL;
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
OldxOffset = HYPERSPACE;
OldyOffset = HYPERSPACE;
xVelocity = (float)0;
yVelocity = (float)0;
Size = SMALL_SHOT;
FrameCount = 0;
}
AstroShot::~AstroShot()
{
}
|
The object can be drawn as a small shot for the players ship and a larger shot for the UFO shot.
REF: 12.1
|
void AstroShot::Draw(HDC hdc)
{
HPEN ColourPen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
if (FrameCount != FALSE)
{
if (FrameCount == ERASE_FRAME)
FrameCount = FALSE;
BackgroundPen = CreatePen(PS_SOLID, 0, GetBkColor(hdc));
if (Size == SMALL_SHOT)
{
ColourPen = CreatePen(PS_SOLID, 0, RGB(0x55, 0xDD, 0x55));
OldPen = SelectObject(hdc, BackgroundPen);
MoveToEx(hdc, OldxOffset, OldyOffset, NULL);
LineTo(hdc, OldxOffset+1, OldyOffset);
MoveToEx(hdc, OldxOffset, OldyOffset+1, NULL);
LineTo(hdc, OldxOffset+1, OldyOffset+1);
if (FrameCount != FALSE)
{
SelectObject(hdc, ColourPen);
MoveToEx(hdc, xOffset, yOffset, NULL);
LineTo(hdc, xOffset+1, yOffset);
MoveToEx(hdc, xOffset, yOffset+1, NULL);
LineTo(hdc, xOffset+1, yOffset+1);
OldxOffset = xOffset;
OldyOffset = yOffset;
}
}
else
{
ColourPen = CreatePen(PS_SOLID, 0, RGB(0x77, 0xFF, 0x77));
OldPen = SelectObject(hdc, BackgroundPen);
MoveToEx(hdc, OldxOffset, OldyOffset, NULL);
LineTo(hdc, OldxOffset+2, OldyOffset);
MoveToEx(hdc, OldxOffset, OldyOffset+1, NULL);
LineTo(hdc, OldxOffset+2, OldyOffset+1);
MoveToEx(hdc, OldxOffset, OldyOffset+2, NULL);
LineTo(hdc, OldxOffset+2, OldyOffset+2);
if (FrameCount != FALSE)
{
SelectObject(hdc, ColourPen);
MoveToEx(hdc, xOffset, yOffset, NULL);
LineTo(hdc, xOffset+2, yOffset);
MoveToEx(hdc, xOffset, yOffset+1, NULL);
LineTo(hdc, xOffset+2, yOffset+1);
MoveToEx(hdc, xOffset, yOffset+2, NULL);
LineTo(hdc, xOffset+2, yOffset+2);
OldxOffset = xOffset;
OldyOffset = yOffset;
}
}
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
}
}
|
The shot moves in a simple fashion and when it moves off of one side of the display, it moves back on to the opposite side of the display.
REF: 12.2
|
void AstroShot::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;
}
}
|
The SetArea member function is used to initiate an instance of a shot.
REF: 12.3
|
void AstroShot::SetArea(HWND NewhWnd,
short NewxMax,
short NewyMax,
short NewxOffset,
short NewyOffset,
float NewxVelocity,
float NewyVelocity,
short NewSize)
{
hWnd = NewhWnd;
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;
}
|
Some properties of the object can be read with member functions.
REF: 12.4
|
short AstroShot::GetXOffset()
{
return xOffset;
}
short AstroShot::GetYOffset()
{
return yOffset;
}
short AstroShot::Active()
{
return (FrameCount != FALSE);
}
|
When a shot is destroyed it is removed from the display area.
REF: 12.5
|
void AstroShot::Destroy()
{
FrameCount = ERASE_FRAME;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
|
A UFO can appear at any random time during a game and can be a small or large version. The UFO will continually shoot a single shot in random directions, making the play area a very hazardous place.
REF: 13.0
|
// Asteroids Clone Screen Saver
// 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/>.
#ifndef __ASTRO_UFO_HPP
#define __ASTRO_UFO_HPP
class AstroUFO
{
public:
enum
{
FRAMES = 2,
FRAME_POINTS = 12,
UFO_WIDTH = 16,
UFO_HEIGHT = 6,
INACTIVE = 3,
ERASE = 4,
HYPERSPACE = -500,
};
AstroUFO();
~AstroUFO();
void Draw(HDC hdc);
void Move();
void SetArea(HWND NewhWnd, RECT* ClientRect);
short Collide(short xPos, short yPos, short Width, short Height);
short GetSize();
void Destroy();
short GetXOffset();
short GetYOffset();
AstroShot& GetShot();
private:
HWND hWnd;
short xMax;
short yMax;
short Size;
short xOffset;
short yOffset;
short xVelocity;
short yVelocity;
AstroShot Shot;
POINT Frame[FRAMES][FRAME_POINTS];
POINT DisplayFrame[FRAME_POINTS];
POINT OldFrame[FRAME_POINTS];
};
#endif
|
|
A UFO can appear at any random time during a game and can be a small or large version. The UFO will continually shoot a single shot in random directions, making the play area a very hazardous place.
REF: 14.0
|
// Asteroids Clone Screen Saver
// 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/>.
#include <windows.h>
#include "ASTROSHOT.HPP"
#include "ASTRO_UFO.HPP"
AstroUFO::AstroUFO()
{
hWnd = NULL;
xMax = 0;
yMax = 0;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = 0;
yVelocity = 0;
for (Size = 0; Size < FRAMES; ++Size)
{
Frame[Size][0].x = -(8 + (Size+1)*3);
Frame[Size][0].y = -(0 + (Size+1));
Frame[Size][1].x = -(0 + (Size+1));
Frame[Size][1].y = -(3 + (Size+1)*3);
Frame[Size][2].x = +(0 + (Size+1));
Frame[Size][2].y = -(3 + (Size+1)*3);
Frame[Size][3].x = +(8 + (Size+1)*3);
Frame[Size][3].y = -(0 + (Size+1));
Frame[Size][4].x = -(8 + (Size+1)*3);
Frame[Size][4].y = -(0 + (Size+1));
Frame[Size][5].x = -(8 + (Size+1)*3);
Frame[Size][5].y = +(0 + (Size+1));
Frame[Size][6].x = +(8 + (Size+1)*3);
Frame[Size][6].y = +(0 + (Size+1));
Frame[Size][7].x = +(8 + (Size+1)*3);
Frame[Size][7].y = -(0 + (Size+1));
Frame[Size][8].x = +(8 + (Size+1)*3);
Frame[Size][8].y = +(0 + (Size+1));
Frame[Size][9].x = +(0 + (Size+1));
Frame[Size][9].y = +(3 + (Size+1)*3);
Frame[Size][10].x = -(0 + (Size+1));
Frame[Size][10].y = +(3 + (Size+1)*3);
Frame[Size][11].x = -(8 + (Size+1)*3);
Frame[Size][11].y = +(0 + (Size+1));
}
Size = INACTIVE;
}
AstroUFO::~AstroUFO()
{
}
|
Drawing an instance of a UFO is a simple process.
REF: 14.1
|
void AstroUFO::Draw(HDC hdc)
{
short Count;
HPEN ColourPen;
HPEN BackgroundPen;
HGDIOBJ OldPen;
Shot.Draw(hdc);
if (Size != INACTIVE)
{
ColourPen = CreatePen(PS_SOLID, 0, RGB(0x77, 0xFF, 0x77));
BackgroundPen = CreatePen(PS_SOLID, 0, GetBkColor(hdc));
OldPen = SelectObject(hdc, BackgroundPen);
Polyline(hdc, OldFrame, FRAME_POINTS);
if (Size == ERASE)
Size = INACTIVE;
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
DisplayFrame[Count].x = Frame[Size][Count].x + xOffset;
DisplayFrame[Count].y = Frame[Size][Count].y + yOffset;
}
SelectObject(hdc, ColourPen);
Polyline(hdc, DisplayFrame, FRAME_POINTS);
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
OldFrame[Count].x = DisplayFrame[Count].x;
OldFrame[Count].y = DisplayFrame[Count].y;
}
}
SelectObject(hdc, OldPen);
DeleteObject(BackgroundPen);
DeleteObject(ColourPen);
}
}
|
As an instance of a UFO moves, it randomly changes direction to a new random direction making it unpredictable. A UFO can appear at any time on the left or right of the display and then move to the opposite side of the display before disappearing.
REF: 14.2
|
void AstroUFO::Move()
{
short ShotDirection;
if (Shot.Active() == TRUE)
Shot.Move();
if (Size != INACTIVE)
{
if (Shot.Active() == FALSE)
{
ShotDirection = (short)((float)rand()/RAND_MAX * 4);
switch (ShotDirection)
{
case 0:
{
Shot.SetArea(hWnd,
xMax,
yMax,
xOffset,
yOffset,
(float)-8,
(float)-8,
AstroShot::LARGE_SHOT);
break;
}
case 1:
{
Shot.SetArea(hWnd,
xMax,
yMax,
xOffset,
yOffset,
(float)-8,
(float)+8,
AstroShot::LARGE_SHOT);
break;
}
case 2:
{
Shot.SetArea(hWnd,
xMax,
yMax,
xOffset,
yOffset,
(float)+8,
(float)-8,
AstroShot::LARGE_SHOT);
break;
}
case 3:
{
Shot.SetArea(hWnd,
xMax,
yMax,
xOffset,
yOffset,
(float)+8,
(float)+8,
AstroShot::LARGE_SHOT);
break;
}
}
}
if ((short)((float)rand()/RAND_MAX * 10) == FALSE)
yVelocity = (short)((float)rand()/RAND_MAX * ((Size+2)*10)) - ((Size+2)*5);
if (xOffset < 0 - UFO_WIDTH)
Size = INACTIVE;
else if (xOffset > xMax + UFO_WIDTH)
Size = INACTIVE;
if (yOffset < 0)
yOffset = 0;
else if (yOffset > yMax)
yOffset = yMax;
xOffset += xVelocity;
yOffset += yVelocity;
}
else if ((short)((float)rand()/RAND_MAX * 1000) == FALSE)
{
Size = (short)((float)rand()/RAND_MAX * FRAMES);
yOffset = (short)((float)rand()/RAND_MAX * yMax);
if ((short)((float)rand()/RAND_MAX * 2) == FALSE)
{
xOffset = 0 - UFO_WIDTH;
xVelocity = 3 * (2 - Size+1);
}
else
{
xOffset = xMax + UFO_WIDTH;
xVelocity = -3 * (2 - Size+1);
}
yVelocity = (short)((float)rand()/RAND_MAX * 5) - 3;
}
}
|
Initialize an instance of a UFO at the start-up of the application.
REF: 14.3
|
void AstroUFO::SetArea(HWND NewhWnd, RECT* ClientRect)
{
hWnd = NewhWnd;
xMax = (short)(ClientRect->right - ClientRect->left);
yMax = (short)(ClientRect->bottom - ClientRect->top);
}
|
A check can be made to see if an instance of a UFO has collided with a specific area.
REF: 14.4
|
short AstroUFO::Collide(short xPos, short yPos, short Width, short Height)
{
short Collision = FALSE;
if (Size < INACTIVE)
if ((Collision = 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)) == TRUE)
Destroy();
return Collision;
}
|
When a UFO is destroyed, remove it from the display.
REF: 14.5
|
void AstroUFO::Destroy()
{
Size = ERASE;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
Various properties of a UFO can be read.
REF: 14.6
|
short AstroUFO::GetSize()
{
return Size;
}
short AstroUFO::GetXOffset()
{
return xOffset;
}
short AstroUFO::GetYOffset()
{
return yOffset;
}
AstroShot& AstroUFO::GetShot()
{
return Shot;
}
|
|
|