Overview
|
Asteroids.dsw
|
Asteroids.dsp
|
Asteroids.def
|
Asteroids.rc
|
Asteroids.hpp
|
Asteriods.cpp
|
AstroShot.hpp
|
AstroShot.cpp
|
AstroShip.hpp
|
AstroShip.cpp
|
AstroRock.hpp
|
AstroRock.cpp
|
Astro_UFO.hpp
|
Astro_UFO.cpp
|
DirectDraw.lib
|
DirectDraw.dsw
|
DirectDraw.dsp
|
DirectDraw.hpp
|
DirectDraw.cpp
|
DirectSound.hpp
|
DirectSound.cpp
|
PolygonNumber.hpp
|
PolygonNumber.cpp
|
PolygonText.hpp
|
PolygonText.cpp
|
GNU License
|
|
Coding a DirectX Game
2012-04-11 18:30 By Jason Birch
Fourth in a series of how to code articles. Demonstrating coding an Asteroids Clone game with various technologies. This example using DirectX, implementing as a native Microsoft Windows game.
In this article I have converted my Asteroids Clone code into a Windows DirectX. 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.
The code for the DirectX version of this application has some additional features. Support for a two player game has been added, and simulates a cocktial style game where the display rotates 180 degees for player two, whom would be sitting on the opposite side of the cocktail table. The game also has an asteroid belt count down, during play when the countdown reaches zero, a belt of small asteroids appear. This is to prevent the player getting to the end of a level and then sitting and waiting for UFOs to get a high score. The game can also be paulsed using the Pause key.
The keys to play are:
5 - Add a game credit, 1 - Start one player game, 2 - Start two player game, Pause - Pause. A - About.
Player 1: Cursor left - Rotate left, Cursor right - Rotate right, Ctrl - Fire, Alt - Thrust, ' ' - Hyperspace.
Player 2: - Rotate left, - Rotate right, - Fire, - Thrust, - Hyperspace.
A compiled version of the game is available here, it is just 324KB in size.
Graphic and audio files can be downloaded here:

Screen Shot Of Two Player DirectX Conversion
Required Environment
To run a DirectX game, a Windows operating system is required.
To develop a DirectX game, 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 onto the Windows desktop.
Running Application
The application is run by double clicking on the application icon.
|
Visual Studio project workspace file.
REF: 1.0
|
<!--
// Asteroids Clone DirectX
// 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/>.
-->
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "DirectX Asteroids Non Screen Saver"=
".\DirectX Asteroids Non Screen Saver.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
|
|
Visual Studio application project file.
REF: 2.0
|
// Asteroids Clone DirectX
// 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/>.
# Microsoft Developer Studio Project File - Name="DirectX Asteroids Non Screen Saver"
# - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Application" 0x0101
CFG=DirectX Asteroids Non Screen Saver - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "Asteroids.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "Asteroids.mak" CFG=
!MESSAGE "DirectX Asteroids Non Screen Saver - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "DirectX Asteroids Non Screen Saver
!MESSAGE - Win32 Release" (based on "Win32 (x86) Application")
!MESSAGE "DirectX Asteroids Non Screen Saver
!MESSAGE - Win32 Debug" (based on "Win32 (x86) Application")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "DirectX Asteroids Non Screen Saver - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x809 /d "NDEBUG"
# ADD RSC /l 0x809 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
# advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
# odbc32.lib odbccp32.lib
# /nologo /subsystem:windows /machine:I386
# ADD LINK32 DirectDraw.lib kernel32.lib user32.lib gdi32.lib winspool.lib
# comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib
# uuid.lib odbc32.lib odbccp32.lib
# /nologo /subsystem:windows /machine:I386
!ELSEIF "$(CFG)" == "DirectX Asteroids Non Screen Saver - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG"
# /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG"
# /D "_WINDOWS" /YX /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32
# ADD BASE RSC /l 0x809 /d "_DEBUG"
# ADD RSC /l 0x809 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib
# advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib
# odbc32.lib odbccp32.lib
# /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
# ADD LINK32 DirectDrawD.lib kernel32.lib user32.lib gdi32.lib winspool.lib
# comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib
# uuid.lib odbc32.lib odbccp32.lib
# /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
!ENDIF
# Begin Target
# Name "DirectX Asteroids Non Screen Saver - Win32 Release"
# Name "DirectX Asteroids Non Screen Saver - Win32 Debug"
# Begin Source File
SOURCE=.\Asteriods.cpp
# End Source File
# Begin Source File
SOURCE=.\Asteroids.bmp
# End Source File
# Begin Source File
SOURCE=.\res\Asteroids.ico
# End Source File
# Begin Source File
SOURCE=.\Asteroids.rc
# End Source File
# Begin Source File
SOURCE=.\Astro_UFO.cpp
# End Source File
# Begin Source File
SOURCE=.\AstroRock.cpp
# End Source File
# Begin Source File
SOURCE=.\AstroShip.cpp
# End Source File
# Begin Source File
SOURCE=.\AstroShot.cpp
# End Source File
# Begin Source File
SOURCE=.\Background.bmp
# End Source File
# Begin Source File
SOURCE=.\Belt.WAV
# End Source File
# Begin Source File
SOURCE=.\Credit.wav
# End Source File
# Begin Source File
SOURCE=.\HyperSpace.wav
# End Source File
# Begin Source File
SOURCE=.\Rock.wav
# End Source File
# Begin Source File
SOURCE=.\Shot.WAV
# End Source File
# Begin Source File
SOURCE=.\Thrust.wav
# End Source File
# Begin Source File
SOURCE=.\UFO.wav
# End Source File
# Begin Source File
SOURCE=.\UFOShot.wav
# End Source File
# End Target
# End Project
|
|
Application definition file, this is a remnant of the original screen saver project.
REF: 3.0
|
// Asteroids Clone DirectX
// 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/>.
NAME ASTEROIDS.EXE
DESCRIPTION 'Asteroids DirectX'
CODE MOVEABLE
DATA MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 4096
EXPORTS
|
|
Visual Studio resource file.
REF: 4.0
|
// Asteroids Clone DirectX
// 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/>.
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_ABOUTBOX DIALOG DISCARDABLE 0, 0, 217, 55
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "About Asteroids"
FONT 8, "MS Sans Serif"
BEGIN
ICON ICON_ASTEROIDS,IDC_STATIC,11,17,21,20
LTEXT "Asteroids DirectX Version 2.0 - Freeware",IDC_STATIC,40,
0,135,8,SS_NOPREFIX
LTEXT "Copyright © 1997, 2004 - Jason Birch",IDC_STATIC,40,8,
119,8
DEFPUSHBUTTON "OK",IDOK,178,7,32,14,WS_GROUP
LTEXT "5 - Credit",IDC_STATIC,40,38,53,8,SS_NOPREFIX
LTEXT "1 - One Player Game",IDC_STATIC,40,22,53,8,SS_NOPREFIX
LTEXT "2 - Two Player Game",IDC_STATIC,40,30,53,8,SS_NOPREFIX
LTEXT "Left Arrow - Rotate Left",IDC_STATIC,95,18,90,8,
SS_NOPREFIX
LTEXT "Right Arrow - Rotate Right",IDC_STATIC,95,26,95,8,
SS_NOPREFIX
LTEXT "Down Arrow - Thrust",IDC_STATIC,95,34,98,8,SS_NOPREFIX
LTEXT "Up Arrow - Hyperspace",IDC_STATIC,95,42,98,8,
SS_NOPREFIX
END
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "ASTEROIDS MFC Application\0"
VALUE "FileVersion", "1, 0, 0, 1\0"
VALUE "InternalName", "ASTEROIDS\0"
VALUE "LegalCopyright", "Copyright © 1996\0"
VALUE "LegalTrademarks", "\0"
VALUE "OriginalFilename", "ASTEROIDS.EXE\0"
VALUE "ProductName", "ASTEROIDS Application\0"
VALUE "ProductVersion", "1, 0, 0, 1\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_ABOUTBOX, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 210
TOPMARGIN, 7
BOTTOMMARGIN, 48
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_ABOUTBOX "&About Asteroids..."
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// English (U.K.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"#define _AFX_NO_SPLITTER_RESOURCES\r\n"
"#define _AFX_NO_OLE_RESOURCES\r\n"
"#define _AFX_NO_TRACKER_RESOURCES\r\n"
"#define _AFX_NO_PROPERTY_RESOURCES\r\n"
"\r\n"
"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
"#ifdef _WIN32\r\n"
"LANGUAGE 9, 1\r\n"
"#pragma code_page(1252)\r\n"
"#endif\r\n"
"#include ""res\\Asteroids.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
"#include ""afxres.rc"" // Standard components\r\n"
"#endif\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Icon
//
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
ICON_ASTEROIDS ICON DISCARDABLE "res\\Asteroids.ico"
/////////////////////////////////////////////////////////////////////////////
//
// Bitmap
//
ASTEROIDS BITMAP DISCARDABLE "Asteroids.bmp"
BACKGROUND BITMAP DISCARDABLE "Background.bmp"
/////////////////////////////////////////////////////////////////////////////
//
// WAVE
//
ROCK WAVE DISCARDABLE "Rock.wav"
SHOT WAVE DISCARDABLE "Shot.WAV"
UFO_SHOT WAVE DISCARDABLE "UFOShot.wav"
HYPERSPACE WAVE DISCARDABLE "HyperSpace.wav"
THRUST WAVE DISCARDABLE "Thrust.wav"
CREDIT WAVE DISCARDABLE "Credit.wav"
UFO WAVE DISCARDABLE "UFO.WAV"
BELT WAVE DISCARDABLE "Belt.WAV"
#endif // English (U.K.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#define _AFX_NO_SPLITTER_RESOURCES
#define _AFX_NO_OLE_RESOURCES
#define _AFX_NO_TRACKER_RESOURCES
#define _AFX_NO_PROPERTY_RESOURCES
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif
#include "res\Asteroids.rc2" // non-Microsoft Visual C++ edited resources
#include "afxres.rc" // Standard components
#endif
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED
|
|
Main application definition file, defining general parameter values for the application. Such as static object display locations and sound object IDs.
REF: 5.0
|
// Asteroids Clone DirectX
// 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
{
BUFF_SIZE = 255,
MAX_X = 640,
MAX_Y = 480,
START_ROCKS = 4,
MAX_ROCKS = 100,
MAX_BELT_COUNT = 256,
MAX_SWAP_COUNT = 10,
REFRSH_XOFFSET = 0,
REFRESH_YOFFSET = 465,
REFRESH_SCALE = 3,
HISCORE_XOFFSET = 35,
HISCORE_YOFFSET = 20,
HISCORE_SCALE = 3,
GAMEOVER_XOFFSET = 90,
GAMEOVER_YOFFSET = 20,
INSERTCOIN_XOFFSET = 110,
INSERTCOIN_YOFFSET = 20,
CREDITS_XOFFSET = 110,
CREDITS_YOFFSET = 20,
BELTCOUNT_XOFFSET = 50,
BELTCOUNT_YOFFSET = 20,
BELTCOUNT_SCALE = 2,
ABOUT_X = 160,
ABOUT_Y = 160,
MAX_SOUNDS = 8,
SOUND_SHOT = 0,
SOUND_UFO_SHOT = 1,
SOUND_ROCK = 2,
SOUND_HYPERSPACE = 3,
SOUND_THRUST = 4,
SOUND_CREDIT = 5,
SOUND_UFO = 6,
SOUND_BELT = 7
};
LRESULT APIENTRY WndFunc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
#endif
|
|
The main application code requires standard, Windows, DirectX and the application header files to be included. A DirectDraw class is used to perform all DirectX related operations.
REF: 6.0
|
// Asteroids Clone DirectX
// 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/>.
#define WIN32_LEAN_AND_MEAN
#define CINTERFACE
#include <stdio.h>
#include <windows.h>
#include <scrnsave.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <ddraw.h>
#include <dsound.h>
#include "RESOURCE.H"
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
#include "ASTROSHOT.HPP"
#include "ASTROSHIP.HPP"
#include "ASTRO_UFO.HPP"
#include "ASTROROCK.HPP"
#include "ASTEROIDS.HPP"
DirectDraw Draw;
DirectSound Sound;
BOOL bActive = FALSE; // is application active?
|
The application uses a standard Windows entry point function. There are player one and player two variables defined, and then a third variable which is a pointer to the currently active players variable, so the same code can be used for both players.
REF: 6.1
|
int WINAPI WinMain(HINSTANCE hThisInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
FILE* File;
HWND hWnd;
WNDCLASS wndclass;
MSG msg;
short Count;
short ShotCount;
short LastSwap;
short SwapCount;
short PlayerCount;
short Orientation;
short RockFound;
short FirstRock;
short FirstRockTwo;
short* CurrentFirstRock;
short NextRock;
short NextRockTwo;
short* CurrentNextRock;
short BeltCount;
short BeltCountTwo;
short* CurrentBeltCount;
short BeltRocks;
short BeltRocksTwo;
short* CurrentBeltRocks;
short ShotKey = 0;
short Debounce = FALSE;
short LastShotKey;
unsigned long TickCount;
unsigned long ShipTimer;
unsigned long ShotTimer;
unsigned long LowPriorityTimer;
RECT AboutFrames;
long Temp;
|
Create a standard Window for the application.
REF: 6.2
|
/************************************************************/
/* Define and register a window class for this application. */
/************************************************************/
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WndFunc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hThisInstance;
wndclass.hIcon = LoadIcon(hThisInstance, MAKEINTRESOURCE(ICON_ASTEROIDS));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "DirectX Asteroids";
RegisterClass(&wndclass);
/******************************************************************/
/* Create and display a window using the registered window class. */
/******************************************************************/
hWnd = CreateWindowEx(0,
"DirectX Asteroids",
"DirectX Asteroids",
WS_POPUP /*| WS_SYSMENU*/,
0,
0,
MAX_X,
MAX_Y,
NULL,
NULL,
hThisInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
ShowCursor(FALSE);
|
Initialize variables and set a random seed.
REF: 6.3
|
ShipTimer = 0;
ShotTimer = 0;
LowPriorityTimer = 0;
SwapCount = FALSE;
LastSwap = FALSE;
Orientation = FALSE;
/**************/
/* Randomise. */
/**************/
srand(GetTickCount());
/***************************************/
/* Define areas of the bitmap serface. */
/* x and y must be multiples of 32. */
/**************************************/
AboutFrames.left = 0;
AboutFrames.top = 0;
AboutFrames.right = 333;
AboutFrames.bottom = 115;
|
Initialize the DirectDraw class to use the application Window. Create text and number objects for the application to use. Read the last saved high score from disk. Then initialize game objects.
REF: 6.4
|
/***************************************/
/* Initialise the DirectDraw surfaces. */
/***************************************/
Draw.Initialise(hWnd);
Draw.LoadBitmapSurface("ASTEROIDS");
Draw.LoadBackgroundSurface("BACKGROUND");
PolygonNumber HiScore(&Draw, &Sound, MAX_X / 2 - HISCORE_XOFFSET,
HISCORE_YOFFSET, MAX_X, MAX_Y, HISCORE_SCALE,
PolygonNumber::INFINATE_FRAMES, FALSE, 6, TRUE);
PolygonText GameOver(&Draw, &Sound, MAX_X / 2 - GAMEOVER_XOFFSET,
MAX_Y / 2 - GAMEOVER_YOFFSET, MAX_X, MAX_Y, 5, 20,
FALSE, "GAME OVER");
PolygonText InsertCoin(&Draw, &Sound, MAX_X / 2 - INSERTCOIN_XOFFSET,
MAX_Y / 2 - INSERTCOIN_YOFFSET, MAX_X, MAX_Y, 5, 5,
TRUE, "INSERT COIN");
PolygonNumber Credits(&Draw, &Sound, (MAX_X / 2 - CREDITS_XOFFSET) + 160,
MAX_Y / 2 - CREDITS_YOFFSET, MAX_X, MAX_Y, 5,
PolygonNumber::INFINATE_FRAMES, FALSE, 2, FALSE);
PolygonText Belt(&Draw, &Sound, MAX_X - BELTCOUNT_XOFFSET - 110,
MAX_Y - BELTCOUNT_YOFFSET, MAX_X, MAX_Y, BELTCOUNT_SCALE,
PolygonText::INFINATE_FRAMES, FALSE, "ASTEROID BELT", TRUE);
PolygonNumber BeltNumber(&Draw, &Sound, MAX_X - BELTCOUNT_XOFFSET,
MAX_Y - BELTCOUNT_YOFFSET, MAX_X, MAX_Y, BELTCOUNT_SCALE,
PolygonNumber::INFINATE_FRAMES, FALSE, 3, TRUE);
if ((File = fopen("Asteroids.DAT", "rt")) != NULL)
{
fscanf(File, "%lu", &Temp);
HiScore.SetNumber(Temp);
fclose(File);
}
/**********************/
/* Player one objects */
/**********************/
BeltCount = MAX_BELT_COUNT;
BeltRocks = 5;
AstroShip Ship(&Draw, &Sound, MAX_X, MAX_Y, 20, 120);
AstroUFO UFO(&Draw, &Sound, MAX_X, MAX_Y);
AstroRock Rock[MAX_ROCKS];
FirstRock = START_ROCKS;
NextRock = FirstRock;
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count].SetArea(&Draw, &Sound, MAX_X, MAX_Y);
for (Count = START_ROCKS - 1; Count < MAX_ROCKS; ++Count)
Rock[Count].Destroy(Orientation);
/**********************/
/* Player two objects */
/**********************/
BeltCountTwo = MAX_BELT_COUNT;
BeltRocksTwo = 5;
AstroShip ShipTwo(&Draw, &Sound, MAX_X, MAX_Y, 500, 400);
AstroUFO UFOTwo(&Draw, &Sound, MAX_X, MAX_Y);
AstroRock RockTwo[MAX_ROCKS];
FirstRockTwo = START_ROCKS;
NextRockTwo = FirstRock;
for (Count = 0; Count < MAX_ROCKS; ++Count)
RockTwo[Count].SetArea(&Draw, &Sound, MAX_X, MAX_Y);
for (Count = START_ROCKS - 1; Count < MAX_ROCKS; ++Count)
RockTwo[Count].Destroy(Orientation);
/*******************************/
/* Current Player one pointers */
/*******************************/
AstroShip* CurrentShip = &Ship;
AstroRock* CurrentRock = &Rock[0];
AstroUFO* CurrentUFO = &UFO;
CurrentBeltCount = &BeltCount;
CurrentFirstRock = &FirstRock;
CurrentNextRock = &NextRock;
CurrentBeltCount = &BeltCount;
CurrentBeltRocks = &BeltRocks;
|
Load the sound resources into memory.
REF: 6.5
|
/***************************************/
/* Initialise the DirectSound objects. */
/***************************************/
Sound.Initialise(hWnd, MAX_SOUNDS);
Sound.CreateObject("SHOT", 2);
Sound.CreateObject("UFO_SHOT", 2);
Sound.CreateObject("ROCK", 10);
Sound.CreateObject("HYPERSPACE", 2);
Sound.CreateObject("THRUST", 1);
Sound.CreateObject("CREDIT", 1);
Sound.CreateObject("UFO", 1);
Sound.CreateObject("BELT", 1);
|
Recognise if keys have been pressed after this point.
REF: 6.6
|
/********************/
/* Clear key flags. */
/********************/
GetAsyncKeyState(VK_LEFT);
GetAsyncKeyState(VK_RIGHT);
GetAsyncKeyState(VK_UP);
GetAsyncKeyState(VK_DOWN);
GetAsyncKeyState(VK_CONTROL);
GetAsyncKeyState(VK_F2);
GetAsyncKeyState(VK_PAUSE);
|
Standard Windows message loop to dispatch messages for the application Window.
REF: 6.7
|
/**********************************************************/
/* Message loop for processing the applications messages. */
/**********************************************************/
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if(!GetMessage(&msg, NULL, 0, 0))
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
|
Only process the application if the application Window is active and the application is not currently in a paused state. Throttle the application to a maximum frame rate.
REF: 6.8
|
else if(bActive)
{
if (!Draw.DoPause())
{
TickCount = GetTickCount();
// Draw.DoRefreshRate();
if (LowPriorityTimer < TickCount)
{
|
When the asteroid belt countdown reaches zero, add five additional small rocks to the play field. Draw the belt count down and high score on the display.
REF: 6.9
|
/******************/
/* Asteroid belt. */
/******************/
--(*CurrentBeltCount);
BeltNumber.SetNumber(*CurrentBeltCount);
if (*CurrentBeltCount == FALSE)
{
Sound.Play(SOUND_BELT, 0);
(*CurrentBeltRocks) += 5;
if ((*CurrentBeltRocks) > 50)
(*CurrentBeltRocks) = 50;
for (Count = MAX_ROCKS - (*CurrentBeltRocks);
Count < MAX_ROCKS;
++Count)
{
if (CurrentRock[Count].GetXOffset() == AstroRock::HYPERSPACE)
CurrentRock[Count].SetArea(&Draw, &Sound,
MAX_X, MAX_Y, 0, 0, 2);
}
(*CurrentBeltCount) = MAX_BELT_COUNT;
}
Belt.Draw();
BeltNumber.Draw(Orientation);
HiScore.Draw(Orientation);
|
Swap players when required. Set the current player objects to the other player and display the player change message for a period before the other player takes control of the game.
REF: 6.10
|
/**********************************/
/* Check if Player swap required. */
/**********************************/
if (CurrentShip->GetPlayerSwap() != FALSE)
{
if (LastSwap ==TRUE && Ship.GetLives() == FALSE
&& ShipTwo.GetLives() == FALSE)
{
SwapCount = MAX_SWAP_COUNT;
LastSwap = FALSE;
}
else if (SwapCount == FALSE
&& (Ship.GetLives() != FALSE
|| ShipTwo.GetLives() != FALSE))
SwapCount = MAX_SWAP_COUNT;
else if (SwapCount > 0)
--SwapCount;
if (CurrentShip == &Ship && ShipTwo.GetLives() > 0)
{
if (SwapCount == MAX_SWAP_COUNT)
{
Orientation = TRUE;
Belt.SetText("ASTEROID BELT", Orientation);
InsertCoin.SetVisible(FALSE);
InsertCoin.SetText("PLAYER TWO", Orientation);
InsertCoin.SetFlash(FALSE);
InsertCoin.SetFrames(PolygonText::INFINATE_FRAMES);
InsertCoin.SetVisible(TRUE);
Draw.RestoreSurfaces();
CurrentUFO = &UFOTwo;
CurrentFirstRock = &FirstRockTwo;
CurrentNextRock = &NextRockTwo;
CurrentBeltCount = &BeltCountTwo;
CurrentBeltRocks = &BeltRocksTwo;
CurrentRock = RockTwo;
}
else if (SwapCount == FALSE)
{
InsertCoin.SetVisible(FALSE);
CurrentShip = &ShipTwo;
CurrentShip->SetPlayerSwap();
}
}
else
{
if (SwapCount == MAX_SWAP_COUNT)
{
Orientation = FALSE;
Belt.SetText("ASTEROID BELT", Orientation);
if (Ship.GetLives() > 0)
{
InsertCoin.SetVisible(FALSE);
InsertCoin.SetText("PLAYER ONE", Orientation);
InsertCoin.SetFlash(FALSE);
InsertCoin.SetFrames(PolygonText::INFINATE_FRAMES);
InsertCoin.SetVisible(TRUE);
}
Draw.RestoreSurfaces();
CurrentUFO = &UFO;
CurrentFirstRock = &FirstRock;
CurrentNextRock = &NextRock;
CurrentBeltCount = &BeltCount;
CurrentBeltRocks = &BeltRocks;
CurrentRock = Rock;
}
else if (SwapCount == FALSE && Ship.GetLives() > 0)
{
InsertCoin.SetVisible(FALSE);
CurrentShip = &Ship;
CurrentShip->SetPlayerSwap();
}
}
/*****************************/
/* Draw player swap message. */
/*****************************/
InsertCoin.Draw();
}
|
Start a new game if a game is not currently in progress and enough credits are available for the type of game requested. Otherwise display "Insert Coin", number of credits or "Game Over" message as appropriate.
REF: 6.11
|
/********************************************************/
/* One or Two Player game start if no game in progress. */
/********************************************************/
if (Ship.GetLives() == FALSE && ShipTwo.GetLives() == FALSE)
{
if (Ship.GetScore() > HiScore.GetNumber())
HiScore.SetNumber(Ship.GetScore());
if (ShipTwo.GetScore() > HiScore.GetNumber())
HiScore.SetNumber(ShipTwo.GetScore());
if (GetAsyncKeyState('1') && Credits.GetNumber() != FALSE)
PlayerCount = 1;
else if (GetAsyncKeyState('2') && Credits.GetNumber() > 1)
PlayerCount = 2;
else
PlayerCount = FALSE;
if (PlayerCount != FALSE)
{
LastSwap = TRUE;
UFO.Destroy(Orientation);
UFO.GetShot()->Destroy();
UFOTwo.Destroy(Orientation);
UFOTwo.GetShot()->Destroy();
FirstRock = START_ROCKS - 1;
FirstRockTwo = START_ROCKS - 1;
NextRock = FirstRock;
NextRockTwo = FirstRock;
BeltRocks = 5;
BeltRocksTwo = 5;
for (Count = 0; Count < MAX_ROCKS; ++Count)
Rock[Count].Destroy(Orientation);
for (Count = 0; Count < MAX_ROCKS; ++Count)
RockTwo[Count].Destroy(Orientation);
ShipTwo.SetScore(0);
CurrentShip = &ShipTwo;
Credits.SetNumber(Credits.GetNumber() - 1);
Ship.Reset();
if (PlayerCount == 2 && Credits.GetNumber() != FALSE)
{
Credits.SetNumber(Credits.GetNumber() - 1);
ShipTwo.Reset();
}
}
if (Credits.GetNumber() == FALSE)
{
if (strcmp(InsertCoin.GetText(), "INSERT COIN"))
{
InsertCoin.SetVisible(FALSE);
InsertCoin.SetText("INSERT COIN", FALSE);
InsertCoin.SetFlash(TRUE);
InsertCoin.SetFrames(5);
InsertCoin.SetVisible(TRUE);
}
}
else if (strcmp(InsertCoin.GetText(), "CREDITS"))
{
InsertCoin.SetVisible(FALSE);
InsertCoin.SetText("CREDITS", FALSE);
InsertCoin.SetFlash(FALSE);
InsertCoin.SetFrames(PolygonText::INFINATE_FRAMES);
InsertCoin.SetVisible(TRUE);
}
GameOver.SetVisible(Ship.GetLives() == FALSE
&& ShipTwo.GetLives() == FALSE);
InsertCoin.SetVisible(GameOver.GetVisible() == FALSE
&& Ship.GetLives() == FALSE
&& ShipTwo.GetLives() == FALSE);
Credits.SetVisible(Credits.GetNumber()
&& GameOver.GetVisible() == FALSE
&& Ship.GetLives() == FALSE
&& ShipTwo.GetLives() == FALSE);
InsertCoin.Draw();
Credits.Draw(Orientation);
GameOver.Draw();
}
|
If '5' is pressed, add a game credit.
REF: 6.12
|
/****************/
/* Add Credits. */
/****************/
if (GetAsyncKeyState('5'))
{
if (Debounce == FALSE)
{
Debounce = TRUE;
Sound.Play(SOUND_CREDIT, 0);
Credits.SetNumber(Credits.GetNumber() + 1);
}
}
else
Debounce = FALSE;
LowPriorityTimer = TickCount + 250;
}
|
Handle game play key presses for each player.
REF: 6.13
|
/*********************/
/* Handle user keys. */
/*********************/
if (CurrentShip == &Ship)
{
if (GetAsyncKeyState(VK_RIGHT))
CurrentShip->IncAngle(TRUE);
else if (GetAsyncKeyState(VK_LEFT))
CurrentShip->IncAngle(FALSE);
if (GetAsyncKeyState(VK_MENU) && CurrentShip->GetLives() != FALSE
&& CurrentShip->GetCrash() == FALSE)
{
if (ShipTimer < TickCount)
{
CurrentShip->Thrust(TRUE);
ShipTimer = TickCount + 50;
}
else
CurrentShip->Thrust(FALSE);
}
else
Sound.Stop(SOUND_THRUST);
if (GetAsyncKeyState(' '))
CurrentShip->Hyperspace();
LastShotKey = ShotKey;
if (ShotTimer < TickCount && (ShotKey = GetAsyncKeyState(VK_CONTROL))
&& !LastShotKey)
{
CurrentShip->Shoot();
ShotTimer = TickCount + 100;
}
}
else
{
if (GetAsyncKeyState('L'))
CurrentShip->IncAngle(TRUE);
else if (GetAsyncKeyState('J'))
CurrentShip->IncAngle(FALSE);
if (GetAsyncKeyState('K') && CurrentShip->GetLives() != FALSE
&& CurrentShip->GetCrash() == FALSE)
{
if (ShipTimer < TickCount)
{
CurrentShip->Thrust(TRUE);
ShipTimer = TickCount + 50;
}
else
CurrentShip->Thrust(FALSE);
}
else
Sound.Stop(SOUND_THRUST);
if (GetAsyncKeyState('I'))
CurrentShip->Hyperspace();
LastShotKey = ShotKey;
if (ShotTimer < TickCount
&& (ShotKey = GetAsyncKeyState('S')) && !LastShotKey)
{
CurrentShip->Shoot();
ShotTimer = TickCount + 100;
}
}
|
Check for game objects colliding.
REF: 6.14
|
/*****************************/
/* Check for ship collision. */
/*****************************/
if (CurrentShip->GetCrash() == FALSE
&& CurrentUFO->Collide(CurrentShip->GetXOffset(),
CurrentShip->GetYOffset(),
CurrentShip->GetWidth(),
CurrentShip->GetHeight(),
Orientation))
CurrentShip->SetCrash(TRUE);
if (CurrentUFO->GetShot()->Active() == TRUE
&& CurrentShip->Collide(CurrentUFO->GetShot()->GetXOffset(),
CurrentUFO->GetShot()->GetYOffset(), 2, 2))
CurrentShip->SetCrash(TRUE);
RockFound = FALSE;
for (Count = 0; Count < MAX_ROCKS; ++Count)
{
if (Count < CurrentShip->GetShotCount())
{
if (CurrentShip->GetShot(Count)->Active() != FALSE)
{
if (CurrentUFO->Collide(
CurrentShip->GetShot(Count)->GetXOffset(),
CurrentShip->GetShot(Count)->GetYOffset(),
2, 2, Orientation))
{
CurrentShip->SetScore(CurrentShip->GetScore() + 100);
CurrentShip->GetShot(Count)->Destroy();
}
}
}
if (CurrentRock[Count].GetXOffset() != AstroRock::HYPERSPACE)
{
RockFound = TRUE;
CurrentRock[Count].Move();
CurrentRock[Count].Draw(Orientation);
/*****************************/
/* Check for ship collision. */
/*****************************/
if (CurrentShip->GetCrash() == FALSE
&& CurrentRock[Count].Collide(CurrentShip->GetXOffset(),
CurrentShip->GetYOffset(),
CurrentShip->GetWidth(),
CurrentShip->GetHeight(),
Orientation))
{
CurrentShip->SetCrash(TRUE);
CurrentRock[++(*CurrentNextRock)].SetArea(&Draw,
&Sound,
MAX_X, MAX_Y,
CurrentShip->GetXOffset(),
CurrentShip->GetYOffset(),
CurrentRock[Count].GetSize());
}
/*************************/
/* Check for shot rocks. */
/*************************/
for (ShotCount = 0;
ShotCount < CurrentShip->GetShotCount();
++ShotCount)
{
if (CurrentShip->GetShot(ShotCount)->Active() != FALSE)
{
if (CurrentRock[Count].Collide(
CurrentShip->GetShot(ShotCount)->GetXOffset(),
CurrentShip->GetShot(ShotCount)->GetYOffset(),
2, 2, Orientation))
{
CurrentShip->SetScore(CurrentShip->GetScore()
+ 5*CurrentRock[Count].GetSize());
CurrentShip->GetShot(ShotCount)->Destroy();
if ((*CurrentNextRock) + 1 < MAX_ROCKS)
CurrentRock[++(*CurrentNextRock)].SetArea(
&Draw, &Sound, MAX_X, MAX_Y,
CurrentRock[Count].GetXOffset(),
CurrentRock[Count].GetYOffset(),
CurrentRock[Count].GetSize());
}
}
}
}
}
|
When there are no more asteroids, start a new game level.
REF: 6.15
|
/************************************************/
/* Start next level if all rocks are destroyed. */
/************************************************/
if (RockFound == FALSE)
{
(*CurrentBeltCount) = MAX_BELT_COUNT;
++(*CurrentFirstRock);
(*CurrentNextRock) = (*CurrentFirstRock);
for (Count = 0; Count < (*CurrentFirstRock); ++Count)
CurrentRock[Count].SetArea(&Draw, &Sound, MAX_X, MAX_Y);
}
|
Animate one frame of game play.
REF: 6.16
|
/*****************/
/* Move objects. */
/*****************/
CurrentShip->Move();
Ship.Draw(Orientation);
ShipTwo.Draw(Orientation);
CurrentUFO->Move(Orientation);
CurrentUFO->Draw(Orientation);
|
Display about Window when 'A' is pressed. Display the DirectX surface which has been drawn for this frame of animation. And loop for the next fame of animation.
REF: 6.17
|
/**************************************************/
/* Display about box when the 'A' key is presses. */
/**************************************************/
if (GetAsyncKeyState('A'))
Draw.FastBlit(ABOUT_X, ABOUT_Y, AboutFrames.left,
AboutFrames.top, AboutFrames.right, AboutFrames.bottom);
/*********************************************/
/* Flip surfaces and resotre the background. */
/*********************************************/
Draw.FlipSurfaces();
Draw.FastRestore(0, 0, Draw.GetScreenWidth(), Draw.GetScreenHeight());
}
}
else
{
WaitMessage();
}
};
|
When unloading the application. Check if a DirectX error occurred, Close the application Window, save the current high score to disk and exit the application.
REF: 6.18
|
if (Draw.GetResult() != DD_OK)
MessageBox(hWnd, "DirectDraw Fail", "Here", MB_OK);
DestroyWindow(hWnd);
RedrawWindow(NULL, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
if ((File = fopen("Asteroids.DAT", "wt")) != NULL)
{
fprintf(File, "%u", HiScore.GetNumber());
fclose(File);
}
return msg.wParam;
}
|
Process Windows messages for the application.
REF: 6.19
|
/*****************************/
/* Window callback function. */
/*****************************/
LRESULT APIENTRY WndFunc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
Draw.SethWnd(hWnd);
switch (message)
{
case WM_ACTIVATEAPP:
{
bActive = wParam;
break;
}
case WM_SETCURSOR:
{
SetCursor(NULL);
return TRUE;
}
case WM_PALETTECHANGED:
{
if ((HWND)wParam == hWnd)
break;
}
// fall through to WM_QUERYNEWPALETTE
case WM_QUERYNEWPALETTE:
{
// install our palette here
Draw.ResetPalette();
break;
}
case WM_KEYDOWN:
{
if (wParam == VK_ESCAPE)
PostMessage(hWnd, WM_CLOSE, 0, 0);
return FALSE;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return FALSE;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
|
|
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: 7.0
|
// Asteroids Clone DirectX
// 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 = 80,
LARGE_SHOT_FRAMES = 60,
ERASE_FRAME = 1,
HYPERSPACE = -500,
};
AstroShot(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height);
~AstroShot();
void Draw(short Orientation = FALSE);
void Move();
void SetArea(short NewxOffset, short NewyOffset, float NewxVelocity,
float NewyVelocity, short Size = SMALL_SHOT);
short GetXOffset();
short GetYOffset();
void Destroy();
short Active();
private:
DirectDraw* DrawX;
DirectSound* SoundX;
short xMax;
short yMax;
float xOffset;
float yOffset;
float OldxOffset;
float 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: 8.0
|
// Asteroids Clone DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
#include "ASTROSHOT.HPP"
AstroShot::AstroShot(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height)
{
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
xMax = Width;
yMax = Height;
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: 8.1
|
void AstroShot::Draw(short Orientation)
{
if (FrameCount != FALSE)
{
if (FrameCount == ERASE_FRAME)
FrameCount = FALSE;
if (Size == SMALL_SHOT)
{
if (Orientation == FALSE)
{
DrawX->DrawLine((long)OldxOffset, (long)OldyOffset,
(long)OldxOffset+1, (long)OldyOffset, 1);
DrawX->DrawLine((long)OldxOffset, (long)OldyOffset+1,
(long)OldxOffset+1, (long)OldyOffset+1, 1);
}
else
{
DrawX->DrawLine(xMax - (long)OldxOffset, yMax - (long)OldyOffset,
xMax - (long)OldxOffset+1, yMax - (long)OldyOffset, 1);
DrawX->DrawLine(xMax - (long)OldxOffset, yMax - (long)OldyOffset+1,
xMax - (long)OldxOffset+1,yMax - (long)OldyOffset+1, 1);
}
if (FrameCount != FALSE)
{
if (Orientation == FALSE)
{
DrawX->DrawLine((long)xOffset, (long)yOffset,
(long)xOffset+1, (long)yOffset, 2);
DrawX->DrawLine((long)xOffset, (long)yOffset+1,
(long)xOffset+1, (long)yOffset+1, 2);
}
else
{
DrawX->DrawLine(xMax - (long)xOffset, yMax - (long)yOffset,
xMax - (long)xOffset+1, yMax - (long)yOffset, 2);
DrawX->DrawLine(xMax - (long)xOffset, yMax - (long)yOffset+1,
xMax - (long)xOffset+1, yMax - (long)yOffset+1, 2);
}
OldxOffset = xOffset;
OldyOffset = yOffset;
}
}
else
{
if (Orientation == FALSE)
{
DrawX->DrawLine((long)OldxOffset, (long)OldyOffset,
(long)OldxOffset+2, (long)OldyOffset, 1);
DrawX->DrawLine((long)OldxOffset, (long)OldyOffset+1,
(long)OldxOffset+2, (long)OldyOffset+1, 1);
DrawX->DrawLine((long)OldxOffset, (long)OldyOffset+2,
(long)OldxOffset+2, (long)OldyOffset+2, 1);
}
else
{
DrawX->DrawLine(xMax - (long)OldxOffset,yMax - (long)OldyOffset,
xMax - (long)OldxOffset+2, yMax - (long)OldyOffset, 1);
DrawX->DrawLine(xMax - (long)OldxOffset, yMax - (long)OldyOffset+1,
xMax - (long)OldxOffset+2, yMax - (long)OldyOffset+1, 1);
DrawX->DrawLine(xMax - (long)OldxOffset, yMax - (long)OldyOffset+2,
xMax - (long)OldxOffset+2, yMax - (long)OldyOffset+2, 1);
}
if (FrameCount != FALSE)
{
if (Orientation == FALSE)
{
DrawX->DrawLine((long)xOffset, (long)yOffset,
(long)xOffset+2, (long)yOffset, 2);
DrawX->DrawLine((long)xOffset, (long)yOffset+1,
(long)xOffset+2, (long)yOffset+1, 2);
DrawX->DrawLine((long)xOffset, (long)yOffset+2,
(long)xOffset+2, (long)yOffset+2, 3);
}
else
{
DrawX->DrawLine(xMax - (long)xOffset,
yMax - (long)yOffset,
xMax - (long)xOffset+2,
yMax - (long)yOffset, 2);
DrawX->DrawLine(xMax - (long)xOffset, yMax - (long)yOffset+1,
xMax - (long)xOffset+2, yMax - (long)yOffset+1, 2);
DrawX->DrawLine(xMax - (long)xOffset, yMax - (long)yOffset+2,
xMax - (long)xOffset+2, yMax - (long)yOffset+2, 3);
}
OldxOffset = xOffset;
OldyOffset = yOffset;
}
}
}
}
|
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: 8.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: 8.3
|
void AstroShot::SetArea(short NewxOffset, short NewyOffset, float NewxVelocity,
float NewyVelocity, short NewSize)
{
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: 8.4
|
short AstroShot::GetXOffset()
{
return (short)xOffset;
}
short AstroShot::GetYOffset()
{
return (short)yOffset;
}
short AstroShot::Active()
{
return (FrameCount != FALSE);
}
|
When a shot is destroyed it is removed from the display area.
REF: 8.5
|
void AstroShot::Destroy()
{
FrameCount = ERASE_FRAME;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
|
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 DirectX
// 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 = 80,
LIFE_XGAP = 30,
LIFE_YOFFSET = 35,
LIVES_HEIGHT = 34,
LIVES_WIDTH = 100,
MAX_LIVES = 3,
SCORE_YOFFSET = 20,
SCORE_SCALE = 5,
MAX_SHOTS = 10,
HYPERSPACE = -500,
HYPER_FRAMES = 50,
MAX_VELOCITY = 6,
SOUND_SHOT = 0,
SOUND_CRASH = 2,
SOUND_HYPERSPACE = 3,
SOUND_THRUST = 4,
};
struct PosType
{
float x;
float y;
};
AstroShip(DirectDraw* NewDrawX, DirectSound* NewSoundX, short Width,
short Height, short NewScoreX, short NewLifeX);
~AstroShip();
void Draw(short Orientation = FALSE);
void IncAngle(short Direction);
void Thrust(const short Accelorate);
void Shoot();
void Move();
void Reset();
void Hyperspace();
short Collide(short xPos, short yPos, short Width, short Height);
void SetCrash(short NewCrash);
short GetCrash();
void SetPlayerSwap();
short GetPlayerSwap();
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;
DirectDraw* DrawX;
DirectSound* SoundX;
short ScoreX;
short LifeX;
short Lives;
short Crash;
short ThrustFlag;
short xMax;
short yMax;
short Angle;
float xOffset;
float yOffset;
short ShotIndex;
float Fade;
float xVelocity;
float yVelocity;
short ExplodeFrame;
short HyperCount;
PolygonNumber* PlayerScore;
AstroShot* Shots[MAX_SHOTS];
POINT LifeFrame[FRAME_POINTS];
POINT LifeDisplayFrame[FRAME_POINTS];
POINT Frame[FRAMES][FRAME_POINTS];
PosType DisplayFrame[FRAME_POINTS*2];
PosType OldFrame[FRAME_POINTS*2];
POINT PolygonDraw[FRAME_POINTS*2];
POINT PolygonErase[FRAME_POINTS*2];
POINT ThrustTrail[THRUST_POINTS];
PosType ExplodeDirection[FRAME_POINTS*2];
};
#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 DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include <math.h>
#include <mmsystem.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
#include "ASTROSHOT.HPP"
#include "ASTROSHIP.HPP"
AstroShip::AstroShip(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height, short NewScoreX, short NewLifeX)
{
short Count;
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
ScoreX = NewScoreX;
LifeX = NewLifeX;
OneDegree = (double)6.3 / (double)360;
FrameStep = (double)0.1;
xMax = Width;
yMax = Height;
xOffset = (float)xMax/2;
yOffset = (float)yMax/2;
xVelocity = 0;
yVelocity = 0;
Crash = TRUE;
ThrustFlag = FALSE;
Fade = 2;
Lives = 0;
ExplodeFrame = MAX_EXPLODE_FRAME;
ShotIndex = 0;
HyperCount = FALSE;
PlayerScore = new PolygonNumber(DrawX, SoundX, NewScoreX, SCORE_YOFFSET,
xMax, yMax, SCORE_SCALE,
PolygonNumber::INFINATE_FRAMES,
FALSE, 6, TRUE);
for (Count = 0; Count < MAX_SHOTS; ++Count)
Shots[Count] = new AstroShot(DrawX, SoundX, xMax, yMax);
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()
{
short Count;
delete PlayerScore;
for (Count = 0; Count < MAX_SHOTS; ++Count)
delete Shots[Count];
}
|
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.0
|
void AstroShip::Draw(short Orientation)
{
short Count;
short LifeCount;
for (Count = 0; Count < MAX_SHOTS; ++Count)
Shots[Count]->Draw(Orientation);
if (Lives != FALSE || ExplodeFrame != MAX_EXPLODE_FRAME)
{
/*********************/
/* Draw intact ship. */
/*********************/
if (Crash == FALSE)
{
if (ExplodeFrame >= ERASE_FRAME)
{
ExplodeFrame = FALSE;
/************************************/
/* Erase previous position of ship. */
/************************************/
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
DrawX->DrawLine((long)OldFrame[Count].x,
(long)OldFrame[Count].y,
(long)OldFrame[Count+1].x,
(long)OldFrame[Count+1].y, 1);
}
/******************************************/
/* Plot ships current position. */
/* Erase previous position of ship. */
/* Draw the ship in the 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;
if (Orientation == FALSE)
{
PolygonErase[Count].x = (long)OldFrame[Count].x;
PolygonErase[Count].y = (long)OldFrame[Count].y;
PolygonDraw[Count].x = (long)DisplayFrame[Count].x;
PolygonDraw[Count].y = (long)DisplayFrame[Count].y;
}
else
{
PolygonErase[Count].x = xMax - (long)OldFrame[Count].x;
PolygonErase[Count].y = yMax - (long)OldFrame[Count].y;
PolygonDraw[Count].x = xMax - (long)DisplayFrame[Count].x;
PolygonDraw[Count].y = yMax - (long)DisplayFrame[Count].y;
}
}
DrawX->DrawPolygon(PolygonErase, FRAME_POINTS, 1);
DrawX->DrawPolygon(PolygonDraw, FRAME_POINTS, 2);
/******************/
/* Remove thrust. */
/******************/
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
if (Orientation == FALSE)
DrawX->PlotPoint(ThrustTrail[Count].x, ThrustTrail[Count].y, 1);
else
DrawX->PlotPoint(xMax - ThrustTrail[Count].x,
yMax - ThrustTrail[Count].y, 1);
}
/*****************************************/
/* Add thrust point if currently active. */
/*****************************************/
if (ThrustFlag == TRUE)
{
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
ThrustTrail[Count].x = (long)((xOffset + (float)rand()/RAND_MAX * 7)-3
+ (15 * sin(FrameStep*Angle + OneDegree*180)));
ThrustTrail[Count].y = (long)((yOffset + (float)rand()/RAND_MAX * 7)-3
+ (15 * cos(FrameStep*Angle + OneDegree*180)));
if (Orientation == FALSE)
DrawX->PlotPoint(ThrustTrail[Count].x, ThrustTrail[Count].y, 2);
else
DrawX->PlotPoint(xMax - ThrustTrail[Count].x,
yMax - ThrustTrail[Count].y, 2);
}
ThrustFlag = FALSE;
}
/******************************************/
/* Plot ships current position, */
/* next time it will be the old position. */
/******************************************/
memcpy(OldFrame, DisplayFrame, FRAME_POINTS * sizeof(PosType));
}
else
{
if (ExplodeFrame == FALSE)
{
--Lives;
/************************************/
/* Erase previous position of ship. */
/************************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
if (Orientation == FALSE)
{
PolygonErase[Count].x = (long)DisplayFrame[Count].x;
PolygonErase[Count].y = (long)DisplayFrame[Count].y;
}
else
{
PolygonErase[Count].x = xMax - (long)DisplayFrame[Count].x;
PolygonErase[Count].y = yMax - (long)DisplayFrame[Count].y;
}
}
DrawX->DrawPolygon(PolygonErase, FRAME_POINTS, 1);
/******************/
/* Remove thrust. */
/******************/
for (Count = 0; Count < THRUST_POINTS; ++Count)
{
if (Orientation == FALSE)
DrawX->PlotPoint(ThrustTrail[Count].x, ThrustTrail[Count].y, 1);
else
DrawX->PlotPoint(xMax - ThrustTrail[Count].x,
yMax - 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 = ((float)rand()/RAND_MAX * 3)-1;
} while (ExplodeDirection[Count].x == 0);
do
{
ExplodeDirection[Count].y = ((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. */
/************************************/
for (Count = 0; Count < FRAME_POINTS*2; Count += 2)
{
if (Orientation == FALSE)
DrawX->DrawLine((long)OldFrame[Count].x,
(long)OldFrame[Count].y,
(long)OldFrame[Count+1].x,
(long)OldFrame[Count+1].y, 1);
else
DrawX->DrawLine(xMax - (long)OldFrame[Count].x,
yMax - (long)OldFrame[Count].y,
xMax - (long)OldFrame[Count+1].x,
yMax - (long)OldFrame[Count+1].y, 1);
}
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
if (ExplodeFrame < MAX_EXPLODE_FRAME -1)
{
Fade += 10/(float)MAX_EXPLODE_FRAME;
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;
if (Orientation == FALSE)
DrawX->DrawLine((long)DisplayFrame[Count].x,
(long)DisplayFrame[Count].y,
(long)DisplayFrame[Count+1].x,
(long)DisplayFrame[Count+1].y, (char)Fade);
else
DrawX->DrawLine(xMax - (long)DisplayFrame[Count].x,
yMax - (long)DisplayFrame[Count].y,
xMax - (long)DisplayFrame[Count+1].x,
yMax - (long)DisplayFrame[Count+1].y, (char)Fade);
}
/******************************************/
/* Plot ships current position, */
/* next time it will be the old position. */
/******************************************/
memcpy(OldFrame, DisplayFrame, FRAME_POINTS * 2 * sizeof(PosType));
}
/************************/
/* Reset for next life. */
/************************/
if (ExplodeFrame < MAX_EXPLODE_FRAME)
++ExplodeFrame;
if (Lives != FALSE && ExplodeFrame == MAX_EXPLODE_FRAME)
{
ThrustFlag = FALSE;
Fade = 2;
Angle = SHIP_START_ANGLE;
xOffset = (float)xMax/2;
yOffset = (float)yMax/2;
xVelocity = 0;
yVelocity = 0;
}
}
/****************************/
/* Display remaining lives. */
/****************************/
for (LifeCount = 0; LifeCount < MAX_LIVES; ++LifeCount)
{
/********************************/
/* Plot ships current position. */
/********************************/
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
if (Orientation == FALSE)
{
LifeDisplayFrame[Count].x = LifeFrame[Count].x
+ LifeX + (LifeCount+1)*LIFE_XGAP;
LifeDisplayFrame[Count].y = LifeFrame[Count].y + LIFE_YOFFSET;
}
else
{
LifeDisplayFrame[Count].x = xMax - (LifeFrame[Count].x
+ LifeX + (LifeCount+1)*LIFE_XGAP);
LifeDisplayFrame[Count].y = yMax - (LifeFrame[Count].y
+ LIFE_YOFFSET);
}
}
/************************************/
/* Erase previous position of ship. */
/************************************/
DrawX->DrawPolygon(LifeDisplayFrame, FRAME_POINTS, 1);
/******************************************/
/* Draw the ship in the current position. */
/******************************************/
if (Lives > LifeCount)
DrawX->DrawPolygon(LifeDisplayFrame, FRAME_POINTS, 2);
}
}
/******************/
/* Redraw scores. */
/******************/
PlayerScore->Draw(Orientation);
}
|
The IncAngle member function allows the ship to be rotated clockwise or anti-clockwise.
REF: 10.0
|
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.0
|
void AstroShip::Thrust(const short Accelorate)
{
ThrustFlag = TRUE;
if (Accelorate == TRUE)
{
if (SoundX->GetStatus(SOUND_THRUST) != DSBSTATUS_LOOPING)
SoundX->Play(SOUND_THRUST, DSBPLAY_LOOPING);
xVelocity += (float)sin(FrameStep*Angle + OneDegree*0);
yVelocity += (float)cos(FrameStep*Angle + OneDegree*0);
if (xVelocity > MAX_VELOCITY)
xVelocity = MAX_VELOCITY;
if (yVelocity > MAX_VELOCITY)
yVelocity = MAX_VELOCITY;
if (xVelocity < -MAX_VELOCITY)
xVelocity = -MAX_VELOCITY;
if (yVelocity < -MAX_VELOCITY)
yVelocity = -MAX_VELOCITY;
}
}
|
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.0
|
void AstroShip::Shoot()
{
if (Crash == FALSE)
{
Shots[ShotIndex]->SetArea((short)xOffset, (short)yOffset,
xVelocity + 4*(float)sin(FrameStep*Angle + OneDegree*0),
yVelocity + 4*(float)cos(FrameStep*Angle + OneDegree*0));
if (++ShotIndex == MAX_SHOTS)
ShotIndex = 0;
SoundX->Play(SOUND_SHOT, 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.0
|
void AstroShip::Move()
{
short Count;
if (HyperCount != FALSE)
{
--HyperCount;
if (HyperCount == FALSE)
{
xOffset = (float)rand()/RAND_MAX * (xMax - 2*SHIP_WIDTH);
yOffset = (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 = (float)xMax + SHIP_WIDTH;
else if (xOffset > xMax + SHIP_WIDTH)
xOffset = 0 - SHIP_WIDTH;
if (yOffset < 0 - SHIP_HEIGHT)
yOffset = (float)yMax + SHIP_HEIGHT;
else if (yOffset > yMax + SHIP_HEIGHT)
yOffset = 0 - SHIP_HEIGHT;
xOffset += xVelocity;
yOffset += yVelocity;
}
}
|
The Reset member function takes care of re-initialising the ship at the start of a new game.
REF: 10.0
|
void AstroShip::Reset()
{
if (Lives == FALSE)
{
ExplodeFrame = MAX_EXPLODE_FRAME;
Crash = TRUE;
ThrustFlag = FALSE;
Fade = 2;
Angle = SHIP_START_ANGLE;
xOffset = (float)xMax/2;
yOffset = (float)yMax/2;
xVelocity = 0;
yVelocity = 0;
Lives = MAX_LIVES;
PlayerScore->SetNumber(0);
}
}
|
The Hyperspace member function is used to initiate a player activating the ship's hyperspace mode.
REF: 10.0
|
void AstroShip::Hyperspace()
{
if (Crash == FALSE && HyperCount == FALSE)
{
HyperCount = HYPER_FRAMES;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = (float)0;
yVelocity = (float)0;
SoundX->Play(SOUND_HYPERSPACE, 0);
}
}
|
The Collide member function checks to see if the ship has collided with a specific area.
REF: 10.0
|
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.0
|
void AstroShip::SetCrash(short NewCrash)
{
if (Crash == FALSE && NewCrash == TRUE)
SoundX->Play(SOUND_CRASH, 0);
Crash = NewCrash;
}
short AstroShip::GetCrash()
{
return Crash;
}
void AstroShip::SetPlayerSwap()
{
ExplodeFrame = FALSE;
Crash = FALSE;
}
short AstroShip::GetPlayerSwap()
{
if (ExplodeFrame < MAX_EXPLODE_FRAME)
return FALSE;
else
return Crash;
}
short AstroShip::GetXOffset()
{
return (short)xOffset;
}
short AstroShip::GetYOffset()
{
return (short)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;
}
|
|
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: 11.0
|
// Asteroids Clone DirectX
// 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,
INACTIVE = 3,
NEW_POSITION = -1,
HYPERSPACE = -500,
};
AstroRock();
~AstroRock();
void Draw(short Orientation = FALSE);
void Move();
void SetArea(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height, short NewxOffset = NEW_POSITION,
short NewyOffset = NEW_POSITION, short NewSize = NEW_POSITION);
short Collide(short xPos, short yPos, short Width, short Height,
short Orientation = FALSE);
short GetSize();
void Destroy(short Orientation = FALSE);
short GetXOffset();
short GetYOffset();
private:
DirectDraw* DrawX;
DirectSound* SoundX;
short xMax;
short yMax;
short Size;
float xOffset;
float yOffset;
float xVelocity;
float 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: 12.0
|
// Asteroids Clone DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
#include "ASTROROCK.HPP"
AstroRock::AstroRock()
{
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 DirectX surface. The object is only drawn if the instance of the object is flagged as active.
REF: 12.1
|
void AstroRock::Draw(short Orientation)
{
short Count;
if (xOffset != HYPERSPACE)
{
DrawX->DrawPolygon(OldFrame, FRAME_POINTS, 1);
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
if (Orientation == FALSE)
{
DisplayFrame[Count].x = (long)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = (long)(Frame[Size][Count].y + yOffset);
}
else
{
DisplayFrame[Count].x = xMax - (long)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = yMax - (long)(Frame[Size][Count].y + yOffset);
}
}
DrawX->DrawPolygon(DisplayFrame, FRAME_POINTS, 2);
memcpy(OldFrame, DisplayFrame, FRAME_POINTS * sizeof(POINT));
}
}
}
|
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: 12.2
|
void AstroRock::Move()
{
if (xOffset != HYPERSPACE)
{
if (xOffset < 0 - ROCK_WIDTH)
xOffset = (float)(xMax + ROCK_WIDTH);
else if (xOffset > xMax + ROCK_WIDTH)
xOffset = 0 - ROCK_WIDTH;
if (yOffset < 0 - ROCK_HEIGHT)
yOffset = (float)(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: 12.3
|
void AstroRock::SetArea(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height,
short NewxOffset, short NewyOffset, short NewSize)
{
if (NewSize != INACTIVE)
{
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
xMax = Width;
yMax = Height;
if (NewxOffset == NEW_POSITION)
{
Size = 0;
if ((short)((float)rand()/RAND_MAX * 2) == FALSE)
{
xOffset = (float)rand()/RAND_MAX * xMax;
yOffset = 0;
}
else
{
yOffset = (float)rand()/RAND_MAX * yMax;
xOffset = 0;
}
}
else
{
Size = NewSize;
xOffset = NewxOffset;
yOffset = NewyOffset;
}
do
{
xVelocity = (float)rand()/RAND_MAX*2*(Size+1) - 1*(Size+1);
yVelocity = (float)rand()/RAND_MAX*2*(Size+1) - 1*(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: 12.4
|
short AstroRock::Collide(short xPos, short yPos,
short Width, short Height, short Orientation)
{
short Collision = FALSE;
if (xOffset != HYPERSPACE)
{
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)
{
SoundX->Play(2, 0);
++Size;
if (Size == INACTIVE)
Destroy(Orientation);
else
{
do
{
xVelocity = (float)rand()/RAND_MAX*2*(Size+1) - 1*(Size+1);
yVelocity = (float)rand()/RAND_MAX*2*(Size+1) - 1*(Size+1);
} while(xVelocity == 0 || yVelocity == 0);
}
}
}
return Collision;
}
|
If the object is to be destroyed, move the object off of the display.
REF: 12.5
|
void AstroRock::Destroy(short Orientation)
{
Size = INACTIVE;
Draw(Orientation);
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
Return various information about the object if requested.
REF: 12.6
|
short AstroRock::GetSize()
{
return Size;
}
short AstroRock::GetXOffset()
{
return (short)xOffset;
}
short AstroRock::GetYOffset()
{
return (short)yOffset;
}
|
|
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 DirectX
// 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 = 2,
HYPERSPACE = -500,
SOUND_UFO_SHOT = 1,
SOUND_UFO = 6,
};
AstroUFO(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height);
~AstroUFO();
void Draw(short Orientation = FALSE);
void Move(short Orientation = FALSE);
short Collide(short xPos, short yPos,
short Width, short Height, short Orientation = FALSE);
short GetSize();
void Destroy(short Orientation = FALSE);
short GetXOffset();
short GetYOffset();
AstroShot* GetShot();
private:
DirectDraw* DrawX;
DirectSound* SoundX;
short xMax;
short yMax;
short Size;
float xOffset;
float yOffset;
float xVelocity;
float 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 DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
#include "ASTROSHOT.HPP"
#include "ASTRO_UFO.HPP"
AstroUFO::AstroUFO(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short Width, short Height)
{
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
xMax = Width;
yMax = Height;
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
xVelocity = 0;
yVelocity = 0;
Shot = new AstroShot(DrawX, SoundX, xMax, yMax);
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()
{
delete Shot;
}
|
Drawing an instance of a UFO is a simple process.
REF: 14.1
|
void AstroUFO::Draw(short Orientation)
{
short Count;
Shot->Draw(Orientation);
if (xOffset != HYPERSPACE)
{
DrawX->DrawPolygon(OldFrame, FRAME_POINTS, 1);
if (Size < INACTIVE)
{
for (Count = 0; Count < FRAME_POINTS; ++Count)
{
if (Orientation == FALSE)
{
DisplayFrame[Count].x = (long)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = (long)(Frame[Size][Count].y + yOffset);
}
else
{
DisplayFrame[Count].x = xMax - (long)(Frame[Size][Count].x + xOffset);
DisplayFrame[Count].y = yMax - (long)(Frame[Size][Count].y + yOffset);
}
}
DrawX->DrawPolygon(DisplayFrame, FRAME_POINTS, 2);
memcpy(OldFrame, DisplayFrame, FRAME_POINTS * sizeof(POINT));
}
}
}
|
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 Orientation)
{
short ShotDirection;
if (Shot->Active() == TRUE)
Shot->Move();
if (xOffset != HYPERSPACE)
{
if (Shot->Active() == FALSE)
{
ShotDirection = (short)((float)rand()/RAND_MAX * 4);
switch (ShotDirection)
{
case 0:
{
Shot->SetArea((short)xOffset, (short)yOffset, (float)-2,
(float)-2, AstroShot::LARGE_SHOT);
break;
}
case 1:
{
Shot->SetArea((short)xOffset, (short)yOffset, (float)-2,
(float)+2, AstroShot::LARGE_SHOT);
break;
}
case 2:
{
Shot->SetArea((short)xOffset, (short)yOffset, (float)+2,
(float)-2, AstroShot::LARGE_SHOT);
break;
}
case 3:
{
Shot->SetArea((short)xOffset, (short)yOffset, (float)+2,
(float)+2, AstroShot::LARGE_SHOT);
break;
}
}
SoundX->Play(SOUND_UFO_SHOT, 0);
}
if ((short)((float)rand()/RAND_MAX * 10) == FALSE)
yVelocity = ((float)rand()/RAND_MAX * (Size+2)*2) - (Size+2)*1;
if (yOffset < 0)
yOffset = 0;
else if (yOffset > yMax)
yOffset = yMax;
xOffset += xVelocity;
yOffset += yVelocity;
if (xOffset < 0 - UFO_WIDTH)
Destroy(Orientation);
else if (xOffset > xMax + UFO_WIDTH)
Destroy(Orientation);
}
else if ((short)((float)rand()/RAND_MAX * 1000) == FALSE)
{
Size = (short)((float)rand()/RAND_MAX * FRAMES);
yOffset = (float)rand()/RAND_MAX * yMax;
if ((short)((float)rand()/RAND_MAX * 2) == FALSE)
{
xOffset = 0 - UFO_WIDTH;
xVelocity = (float)+(2 - Size+1);
}
else
{
xOffset = (float)xMax + UFO_WIDTH;
xVelocity = (float)-(2 - Size+1);
}
yVelocity = ((float)rand()/RAND_MAX * 5 - 3)/4;
}
}
|
A check can be made to see if an instance of a UFO has collided with a specific area.
REF: 14.3
|
short AstroUFO::Collide(short xPos, short yPos,
short Width, short Height, short Orientation)
{
short Collision = FALSE;
if (xOffset != HYPERSPACE)
{
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)
{
SoundX->Play(SOUND_UFO, 0);
Destroy(Orientation);
}
}
return Collision;
}
|
When a UFO is destroyed, remove it from the display.
REF: 14.4
|
void AstroUFO::Destroy(short Orientation)
{
Size = INACTIVE;
Draw(Orientation);
xOffset = HYPERSPACE;
yOffset = HYPERSPACE;
}
|
Various properties of a UFO can be read.
REF: 14.5
|
short AstroUFO::GetSize()
{
return Size;
}
short AstroUFO::GetXOffset()
{
return (short)xOffset;
}
short AstroUFO::GetYOffset()
{
return (short)yOffset;
}
AstroShot* AstroUFO::GetShot()
{
return Shot;
}
|
|
The main code for the DirectX version of the application is very similar to the code in other conversions. DirectX requires certain pieces of additional coding in order to drive the graphics engine. The DirectX code has been placed into a dedicated library in order to encapsulate the DirectX code and make it easy to reuse the code in future projects.
REF: 15.0
|
// Asteroids Clone DirectX
// 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/>.
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "DirectDraw"=".\DirectDraw.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################
|
|
The main code for the DirectX version of the application is very similar to the code in other conversions. DirectX requires certain pieces of additional coding in order to drive the graphics engine. The DirectX code has been placed into a dedicated library in order to encapsulate the DirectX code and make it easy to reuse the code in future projects.
REF: 16.0
|
// Asteroids Clone DirectX
// 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/>.
# Microsoft Developer Studio Project File - Name="DirectDraw" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Static Library" 0x0104
CFG=DirectDraw - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "DirectDraw.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "DirectDraw.mak" CFG="DirectDraw - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "DirectDraw - Win32 Release" (based on "Win32 (x86) Static Library")
!MESSAGE "DirectDraw - Win32 Debug" (based on "Win32 (x86) Static Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
RSC=rc.exe
!IF "$(CFG)" == "DirectDraw - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FR /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ELSEIF "$(CFG)" == "DirectDraw - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD CPP /nologo /W3 /GX /Z7 /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /FD /c
# ADD BASE RSC /l 0x409
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LIB32=link.exe -lib
# ADD BASE LIB32 /nologo
# ADD LIB32 /nologo
!ENDIF
# Begin Target
# Name "DirectDraw - Win32 Release"
# Name "DirectDraw - Win32 Debug"
# Begin Source File
SOURCE=.\DirectDraw.cpp
# End Source File
# Begin Source File
SOURCE=.\DirectSound.cpp
# End Source File
# Begin Source File
SOURCE=.\PolygonNumber.cpp
# End Source File
# Begin Source File
SOURCE=.\PolygonText.cpp
# End Source File
# Begin Source File
SOURCE="P:\Program Files\Microsoft Visual Studio\VC98\Lib\DDRAW.LIB"
# End Source File
# Begin Source File
SOURCE="P:\Program Files\Microsoft Visual Studio\VC98\Lib\DSOUND.LIB"
# End Source File
# End Target
# End Project
|
|
The DirectX class contains functions to allow the aplication to draw on DirectX surfaces.
REF: 17.0
|
// Asteroids Clone DirectX
// 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 __DIRECTDRAW_HPP
#define __DIRECTDRAW_HPP
class DirectDraw
{
public:
enum
{
BUFF_SIZE = 255,
CLIP_TOP = 1,
CLIP_BOTTOM = 2,
CLIP_LEFT = 4,
CLIP_RIGHT = 8,
};
DirectDraw();
~DirectDraw();
void Initialise(HWND NewhWnd, short NewScreenWidth = 640,
short NewScreenHeight = 480,
short NewScreenColours = 8);
void LoadBitmapSurface(char* Filename);
void LoadBackgroundSurface(char* Filename);
HRESULT RestoreSurfaces();
void ResetPalette();
void FlipSurfaces();
void EraseSurface(LPDIRECTDRAWSURFACE Surface);
void Cls();
void FastBlit(long xPos, long yPos,
long xOffset = 0, long yOffset = 0,
long xLen = 32, long yLen = 32);
void FastRestore(long xPos, long yPos,
long xLen = 32, long yLen = 32);
void FastBackground();
HWND GethWnd();
void SethWnd(HWND NewhWnd);
HRESULT GetResult();
long GetScreenWidth();
long GetScreenHeight();
void SetActiveWindow(long xPosStart, long yPosStart,
long xPosEnd, long yPosEnd);
RECT GetActiveWindow();
/***********************/
/* Plotting functions. */
/***********************/
void PlotPoint(long xPos, long yPos, char Colour);
void DrawLine(long xPosStart, long yPosStart,
long xPosEnd, long yPosEnd, char Colour);
void DrawPolygon(const POINT* Polygon, short PointCount, char Colour);
void SetRefreshRateColour(const char NewColour,
const char NewEraseColour = PolygonText::DEFAULT_ERASECOLOUR);
void DoRefreshRate();
short DoPause();
/*****************************/
/* Functions from DDUTIL.CPP */
/*****************************/
IDirectDrawSurface* DDLoadBitmap(IDirectDraw* pdd, LPCSTR szBitmap,
int dx, int dy);
HRESULT DDReLoadBitmap(IDirectDrawSurface* pdds, LPCSTR szBitmap);
HRESULT DDCopyBitmap(IDirectDrawSurface* pdds, HBITMAP hbm, int x, int y,
int dx, int dy);
IDirectDrawPalette* DDLoadPalette(IDirectDraw* pdd, LPCSTR szBitmap);
DWORD DDColorMatch(IDirectDrawSurface* pdds, COLORREF rgb);
HRESULT DDSetColorKey(IDirectDrawSurface* pdds, COLORREF rgb);
private:
char BitmapResource[BUFF_SIZE+1];
char BackgroundResource[BUFF_SIZE+1];
HRESULT Result;
HWND hWnd;
long ScreenWidth;
long ScreenHeight;
short ScreenColours;
RECT ActiveWindow;
LPDIRECTDRAW DirectDrawObject;
DDSURFACEDESC PrimarySurfaceDescription;
LPDIRECTDRAWSURFACE PrimarySurface;
DDSCAPS FlipSurfaceCaps;
LPDIRECTDRAWSURFACE FlipSurface;
DDSURFACEDESC OffScreenSurfaceDescription;
IDirectDrawSurface* BitmapSurface;
IDirectDrawSurface* BackgroundSurface;
LPDIRECTDRAWPALETTE Palette;
short Frames;
long RefreshTimer;
PolygonText* RefreshRateText;
PolygonNumber* RefreshRate;
short PauseFlag;
long PauseTimer;
PolygonText* PauseText;
};
#endif
|
|
The DirectX class has a constructor which initializes optional features such as a refresh rate display and pause game option. The destructor ensures all DirectX objects are released from memory.
REF: 18.0
|
// Asteroids Clone DirectX
// 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/>.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <windowsx.h>
#include <ddraw.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
DirectDraw::DirectDraw()
{
Result = DD_OK;
hWnd = NULL;
ScreenWidth = 640;
ScreenHeight = 480;
ScreenColours = 8;
DirectDrawObject = NULL;
PrimarySurface = NULL;
FlipSurface = NULL;
BitmapSurface = NULL;
BackgroundSurface = NULL;
Palette = NULL;
ActiveWindow.left = 0;
ActiveWindow.top = 0;
ActiveWindow.right = ScreenWidth - 1;
ActiveWindow.bottom = ScreenHeight - 1;
RefreshRateText = new PolygonText(this, NULL, 0, ScreenHeight-10,
(short)ScreenWidth, (short)ScreenHeight,
2, PolygonText::INFINATE_FRAMES, FALSE,
"REFRESH RATE", TRUE);
RefreshRate = new PolygonNumber(this, NULL, 100, ScreenHeight-10,
(short)ScreenWidth, (short)ScreenHeight,
2, PolygonNumber::INFINATE_FRAMES,
FALSE, 4, TRUE);
PauseFlag = FALSE;
PauseText = new PolygonText(this, NULL, ScreenWidth/2 - 240,
ScreenHeight/2 - 50,
(short)ScreenWidth,
(short)ScreenHeight, 20, 60,
TRUE, "PAUSED");
}
DirectDraw::~DirectDraw()
{
delete RefreshRateText;
delete RefreshRate;
delete PauseText;
if (DirectDrawObject != NULL)
{
if (BackgroundSurface != NULL)
{
BackgroundSurface->Release();
BackgroundSurface = NULL;
}
if (BitmapSurface != NULL)
{
BitmapSurface->Release();
BitmapSurface = NULL;
}
if (FlipSurface != NULL)
{
FlipSurface->Release();
FlipSurface = NULL;
}
if (PrimarySurface != NULL)
{
PrimarySurface->Release();
PrimarySurface = NULL;
}
if (Palette != NULL)
{
Palette->Release();
Palette = NULL;
}
DirectDrawObject->Release();
DirectDrawObject = NULL;
}
}
|
Initialize the Direct Draw surfaces and associate them with a Window handle.
REF: 18.1
|
void DirectDraw::Initialise(HWND NewhWnd, short NewScreenWidth,
short NewScreenHeight, short NewScreenColours)
{
hWnd = NewhWnd;
ScreenWidth = NewScreenWidth;
ScreenHeight = NewScreenHeight;
ScreenColours = NewScreenColours;
/*************************************/
/* Initialise the DirectDraw object. */
/*************************************/
Result = DirectDrawCreate(NULL, &DirectDrawObject, NULL);
if (Result == DD_OK)
Result = DirectDrawObject->SetCooperativeLevel(hWnd,
DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
if (Result == DD_OK)
Result = DirectDrawObject->SetDisplayMode(ScreenWidth,
NewScreenHeight, ScreenColours);
/**********************************************/
/* Initialise the DirectDraw primary surface. */
/**********************************************/
if (Result == DD_OK)
{
memset(&PrimarySurfaceDescription, 0,
sizeof(PrimarySurfaceDescription));
PrimarySurfaceDescription.dwSize = sizeof(PrimarySurfaceDescription);
PrimarySurfaceDescription.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
PrimarySurfaceDescription.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE
| DDSCAPS_FLIP
| DDSCAPS_COMPLEX;
PrimarySurfaceDescription.dwBackBufferCount = 1;
Result = DirectDrawObject->CreateSurface(&PrimarySurfaceDescription,
&PrimarySurface, NULL);
}
if (Result == DD_OK)
Result = DDSetColorKey(PrimarySurface, RGB(0, 0, 0));
if (Result == DD_OK)
EraseSurface(PrimarySurface);
/********************************/
/* Get the back buffer surface. */
/********************************/
if (Result == DD_OK)
{
FlipSurfaceCaps.dwCaps = DDSCAPS_BACKBUFFER;
Result = PrimarySurface->GetAttachedSurface(&FlipSurfaceCaps,
&FlipSurface);
}
if (Result == DD_OK)
Result = DDSetColorKey(FlipSurface, RGB(0, 0, 0));
if (Result == DD_OK)
EraseSurface(FlipSurface);
}
|
Load an image resource to be used as a background.
REF: 18.2
|
void DirectDraw::LoadBackgroundSurface(char* NewBackgroundResource)
{
if (Result == DD_OK)
strncpy(BackgroundResource, NewBackgroundResource, BUFF_SIZE);
if (Result == DD_OK)
if ((BackgroundSurface = DDLoadBitmap(DirectDrawObject,
NewBackgroundResource, 0, 0)) == NULL)
Result = DDERR_GENERIC;
if (Result == DD_OK)
FastBackground();
if (Result == DD_OK)
Result = DDSetColorKey(BackgroundSurface, RGB(0, 0, 0));
}
|
Load an image resource to be used for graphics in game objects.
REF: 18.3
|
void DirectDraw::LoadBitmapSurface(char* NewBitmapResource)
{
if (Result == DD_OK)
{
strncpy(BitmapResource, NewBitmapResource, BUFF_SIZE);
/***************************************************/
/* Create an offscreen surface from a bitmap file. */
/***************************************************/
Palette = DDLoadPalette(DirectDrawObject, NewBitmapResource);
}
if (Palette != NULL)
{
PrimarySurface->SetPalette(Palette);
FlipSurface->SetPalette(Palette);
}
if (Result == DD_OK)
if ((BitmapSurface = DDLoadBitmap(DirectDrawObject,
NewBitmapResource, 0, 0)) == NULL)
Result = DDERR_GENERIC;
if (Result == DD_OK)
Result = DDSetColorKey(BitmapSurface, RGB(0, 0, 0));
}
|
Restore image resources for next frame of animation.
REF: 18.4
|
HRESULT DirectDraw::RestoreSurfaces()
{
if ((Result = PrimarySurface->Restore()) == DD_OK)
{
if ((Result = FlipSurface->Restore()) == DD_OK)
{
if ((Result = BitmapSurface->Restore()) == DD_OK)
{
Result = DDReLoadBitmap(BitmapSurface, BitmapResource);
if ((Result = BackgroundSurface->Restore()) == DD_OK)
Result = DDReLoadBitmap(BackgroundSurface, BackgroundResource);
}
}
}
return Result;
}
|
Restore the game colour palette.
REF: 18.5
|
void DirectDraw::ResetPalette()
{
if (Palette)
PrimarySurface->SetPalette(Palette);
DDReLoadBitmap(BitmapSurface, BitmapResource);
}
|
Flip drawn frame to the display frame in order to animate a frame.
REF: 18.6
|
void DirectDraw::FlipSurfaces()
{
do
{
if ((Result = PrimarySurface->Flip(NULL, 0)) == DD_OK)
break;
if (Result == DDERR_SURFACELOST)
if ((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
}
|
Clear all drawn items from a Direct Draw surface.
REF: 18.7
|
void DirectDraw::EraseSurface(LPDIRECTDRAWSURFACE Surface)
{
DDBLTFX BlitFX;
BlitFX.dwSize = sizeof(BlitFX);
BlitFX.dwFillColor = 0;
do
{
if ((Result = Surface->Blt(NULL, NULL, NULL,
DDBLT_COLORFILL, &BlitFX)) == DD_OK)
break;
if (Result == DDERR_SURFACELOST)
if ((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
}
|
Clear all drawn items from all game surfaces.
REF: 18.8
|
void DirectDraw::Cls()
{
EraseSurface(BackgroundSurface);
EraseSurface(PrimarySurface);
EraseSurface(FlipSurface);
}
|
Use a fast method of drawing a game objects image part from the graphics bitmap surface to the next frame of animation to be displayed.
REF: 18.9
|
void DirectDraw::FastBlit(long xPos, long yPos,
long xOffset, long yOffset,
long xLen, long yLen)
{
RECT BitMapRect;
BitMapRect.left = xOffset;
BitMapRect.top = yOffset;
BitMapRect.right = xOffset + xLen;
BitMapRect.bottom = yOffset + yLen;
do
{
if((Result = FlipSurface->BltFast(xPos, yPos,
BitmapSurface, &BitMapRect,
DDBLTFAST_SRCCOLORKEY)) == DD_OK)
break;
if(Result == DDERR_SURFACELOST)
if((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
}
|
Use a fast method of restoring from the background surface, the area used by a game objects image, to the next frame of animation to be displayed.
REF: 18.10
|
void DirectDraw::FastRestore(long xPos, long yPos, long xLen, long yLen)
{
RECT BitMapRect;
BitMapRect.left = xPos;
BitMapRect.top = yPos;
BitMapRect.right = xPos + xLen;
BitMapRect.bottom = yPos + yLen;
do
{
if((Result = FlipSurface->BltFast(xPos, yPos,
BackgroundSurface, &BitMapRect,
DDBLTFAST_SRCCOLORKEY)) == DD_OK)
break;
if(Result == DDERR_SURFACELOST)
if((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
}
|
Prepare a new frame of animation by starting with an unaltered version of the background image.
REF: 18.11
|
void DirectDraw::FastBackground()
{
RECT BitMapRect;
BitMapRect.left = 0;
BitMapRect.top = 0;
BitMapRect.right = ScreenWidth;
BitMapRect.bottom = ScreenHeight;
do
{
if((Result = PrimarySurface->BltFast(0, 0,
BackgroundSurface,
&BitMapRect,
DDBLTFAST_NOCOLORKEY)) == DD_OK)
break;
if(Result == DDERR_SURFACELOST)
if((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
do
{
if((Result = FlipSurface->BltFast(0, 0,
BackgroundSurface,
&BitMapRect,
DDBLTFAST_NOCOLORKEY)) == DD_OK)
break;
if(Result == DDERR_SURFACELOST)
if((Result = RestoreSurfaces()) != DD_OK)
break;
} while (Result == DDERR_WASSTILLDRAWING);
}
|
Get and set class values.
REF: 18.12
|
HWND DirectDraw::GethWnd()
{
return hWnd;
}
void DirectDraw::SethWnd(HWND NewhWnd)
{
hWnd = NewhWnd;
}
HRESULT DirectDraw::GetResult()
{
return Result;
}
long DirectDraw::GetScreenWidth()
{
return ScreenWidth;
}
long DirectDraw::GetScreenHeight()
{
return ScreenHeight;
}
|
Set the properties of the game Window.
REF: 18.13
|
void DirectDraw::SetActiveWindow(long xPosStart, long yPosStart,
long xPosEnd, long yPosEnd)
{
ActiveWindow.left = xPosStart;
ActiveWindow.top = yPosStart;
ActiveWindow.right = xPosEnd;
ActiveWindow.bottom = yPosEnd;
}
RECT DirectDraw::GetActiveWindow()
{
return ActiveWindow;
}
|
Load an image from a resource or a file if the resource does not exist, and place it on a Direct Draw surface.
REF: 18.14
|
IDirectDrawSurface* DirectDraw::DDLoadBitmap(IDirectDraw* pdd,
LPCSTR szBitmap,
int dx, int dy)
{
HBITMAP hbm;
BITMAP bm;
DDSURFACEDESC ddsd;
IDirectDrawSurface *pdds;
hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap,
IMAGE_BITMAP, dx, dy,
LR_CREATEDIBSECTION);
if (hbm == NULL)
hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP,
dx, dy,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
if (hbm == NULL)
return NULL;
GetObject(hbm, sizeof(bm), &bm);
ZeroMemory(&ddsd, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;
ddsd.dwWidth = bm.bmWidth;
ddsd.dwHeight = bm.bmHeight;
if (pdd->CreateSurface(&ddsd, &pdds, NULL) != DD_OK)
return NULL;
DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
DeleteObject(hbm);
return pdds;
}
|
Reload an image from a resource or a file if the resource does not exist, and place it on a Direct Draw surface.
REF: 18.15
|
HRESULT DirectDraw::DDReLoadBitmap(IDirectDrawSurface* pdds, LPCSTR szBitmap)
{
HBITMAP hbm;
HRESULT hr;
hbm = (HBITMAP)LoadImage(GetModuleHandle(NULL), szBitmap, IMAGE_BITMAP,
0, 0, LR_CREATEDIBSECTION);
if (hbm == NULL)
hbm = (HBITMAP)LoadImage(NULL, szBitmap, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);
if (hbm == NULL)
{
OutputDebugString("handle is null\n");
return E_FAIL;
}
hr = DDCopyBitmap(pdds, hbm, 0, 0, 0, 0);
if (hr != DD_OK)
{
OutputDebugString("ddcopybitmap failed\n");
}
DeleteObject(hbm);
return hr;
}
|
Copy a bitmap resource to a location on a Direct Draw surface and stretch the image if required.
REF: 18.16
|
HRESULT DirectDraw::DDCopyBitmap(IDirectDrawSurface* pdds, HBITMAP hbm,
int x, int y, int dx, int dy)
{
HDC hdcImage;
HDC hdc;
BITMAP bm;
DDSURFACEDESC ddsd;
HRESULT hr;
if (hbm == NULL || pdds == NULL)
return E_FAIL;
pdds->Restore();
hdcImage = CreateCompatibleDC(NULL);
if (!hdcImage)
OutputDebugString("createcompatible dc failed\n");
SelectObject(hdcImage, hbm);
GetObject(hbm, sizeof(bm), &bm);
dx = dx == 0 ? bm.bmWidth : dx;
dy = dy == 0 ? bm.bmHeight : dy;
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_HEIGHT | DDSD_WIDTH;
pdds->GetSurfaceDesc(&ddsd);
if ((hr = pdds->GetDC(&hdc)) == DD_OK)
{
StretchBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, hdcImage,
x, y, dx, dy, SRCCOPY);
pdds->ReleaseDC(hdc);
}
DeleteDC(hdcImage);
return hr;
}
|
Create a DirectDraw palette object from a bitmap resoure. If the resource does not exist or NULL is passed create a default 332 palette.
REF: 18.17
|
IDirectDrawPalette* DirectDraw::DDLoadPalette(IDirectDraw* pdd, LPCSTR szBitmap)
{
IDirectDrawPalette* ddpal;
int i;
int n;
int fh;
HRSRC h;
LPBITMAPINFOHEADER lpbi;
PALETTEENTRY ape[256];
RGBQUAD * prgb;
for (i=0; i<256; i++)
{
ape[i].peRed = (BYTE)(((i >> 5) & 0x07) * 255 / 7);
ape[i].peGreen = (BYTE)(((i >> 2) & 0x07) * 255 / 7);
ape[i].peBlue = (BYTE)(((i >> 0) & 0x03) * 255 / 3);
ape[i].peFlags = (BYTE)0;
}
if (szBitmap && (h = FindResource(NULL, szBitmap, RT_BITMAP)))
{
lpbi = (LPBITMAPINFOHEADER)LockResource(LoadResource(NULL, h));
if (!lpbi)
OutputDebugString("lock resource failed\n");
prgb = (RGBQUAD*)((BYTE*)lpbi + lpbi->biSize);
if (lpbi == NULL || lpbi->biSize < sizeof(BITMAPINFOHEADER))
n = 0;
else if (lpbi->biBitCount > 8)
n = 0;
else if (lpbi->biClrUsed == 0)
n = 1 << lpbi->biBitCount;
else
n = lpbi->biClrUsed;
for(i=0; i 8)
n = 0;
else if (bi.biClrUsed == 0)
n = 1 << bi.biBitCount;
else
n = bi.biClrUsed;
for(i=0; iCreatePalette(DDPCAPS_8BIT, ape, &ddpal, NULL);
return ddpal;
}
|
Convert a RGB color to a pysical color. We do this by leting GDI SetPixel() do the color matching then we lock the memory and see what it got mapped to.
REF: 18.18
|
DWORD DirectDraw::DDColorMatch(IDirectDrawSurface* pdds, COLORREF rgb)
{
COLORREF rgbT;
HDC hdc;
DWORD dw = CLR_INVALID;
DDSURFACEDESC ddsd;
HRESULT hres;
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
{
rgbT = GetPixel(hdc, 0, 0);
SetPixel(hdc, 0, 0, rgb);
pdds->ReleaseDC(hdc);
}
ddsd.dwSize = sizeof(ddsd);
while ((hres = pdds->Lock(NULL, &ddsd, 0, NULL)) == DDERR_WASSTILLDRAWING)
;
if (hres == DD_OK)
{
dw = *(DWORD *)ddsd.lpSurface;
dw &= (1 << ddsd.ddpfPixelFormat.dwRGBBitCount)-1;
pdds->Unlock(NULL);
}
if (rgb != CLR_INVALID && pdds->GetDC(&hdc) == DD_OK)
{
SetPixel(hdc, 0, 0, rgbT);
pdds->ReleaseDC(hdc);
}
return dw;
}
|
Set a color key for a surface, given a RGB. If you pass CLR_INVALID as the color key, the pixel in the upper-left corner will be used.
REF: 18.19
|
HRESULT DirectDraw::DDSetColorKey(IDirectDrawSurface* pdds, COLORREF rgb)
{
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = DDColorMatch(pdds, rgb);
ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
return pdds->SetColorKey(DDCKEY_SRCBLT, &ddck);
}
|
Plot a single point on the Direct Draw frame surface.
REF: 18.20
|
void DirectDraw::PlotPoint(long xPos, long yPos, char Colour)
{
DDSURFACEDESC BackgroundSurfaceDesc;
/*********************************************/
/* Polt point relative to the active window. */
/*********************************************/
xPos += ActiveWindow.left;
yPos += ActiveWindow.top;
if (xPos >= ActiveWindow.left && xPos <= ActiveWindow.right
&& yPos >= ActiveWindow.top && yPos <= ActiveWindow.bottom)
{
/**************************************/
/* Drawing on the background surface. */
/**************************************/
BackgroundSurfaceDesc.dwSize = sizeof(BackgroundSurfaceDesc);
/********************************/
/* Lock the background surface. */
/********************************/
do
{
Result = BackgroundSurface->Lock(NULL, &BackgroundSurfaceDesc, 0, NULL);
} while(Result == DDERR_WASSTILLDRAWING);
/*************************************/
/* If the background surface locked. */
/*************************************/
if (Result == DD_OK)
{
/*******************/
/* Plot the point. */
/*******************/
((LPSTR)BackgroundSurfaceDesc.lpSurface)[ScreenWidth * yPos + xPos] = Colour;
/**********************************/
/* Unlock the background surface. */
/**********************************/
BackgroundSurface->Unlock(NULL);
}
}
}
|
Draw a single line on the Direct Draw frame surface.
REF: 18.21
|
void DirectDraw::DrawLine(long xPosStart, long yPosStart,
long xPosEnd, long yPosEnd, char Colour)
{
long dx;
long dy;
long Temp;
long Step;
long k1;
long k2;
long ErrorValue;
short Try;
short Display;
long StartCode;
long EndCode;
long xPosStartOriginal;
long yPosStartOriginal;
double Slope;
DDSURFACEDESC BackgroundSurfaceDesc;
/*********************************************/
/* Polt point relative to the active window. */
/*********************************************/
xPosStart += ActiveWindow.left;
yPosStart += ActiveWindow.top;
xPosEnd += ActiveWindow.left;
yPosEnd += ActiveWindow.top;
/*********************************/
/* Check if line needs clipping. */
/*********************************/
Try = 0;
Display = FALSE;
do
{
/**********************************************/
/* Find clipping regions for the start point. */
/**********************************************/
StartCode = FALSE;
if (xPosStart < ActiveWindow.left)
StartCode |= CLIP_LEFT;
if (xPosStart > ActiveWindow.right)
StartCode |= CLIP_RIGHT;
if (yPosStart < ActiveWindow.top)
StartCode |= CLIP_TOP;
if (yPosStart > ActiveWindow.bottom)
StartCode |= CLIP_BOTTOM;
/********************************************/
/* Find clipping regions for the end point. */
/********************************************/
EndCode = FALSE;
if (xPosEnd < ActiveWindow.left)
EndCode |= CLIP_LEFT;
if (xPosEnd > ActiveWindow.right)
EndCode |= CLIP_RIGHT;
if (yPosEnd < ActiveWindow.top)
EndCode |= CLIP_TOP;
if (yPosEnd > ActiveWindow.bottom)
EndCode |= CLIP_BOTTOM;
/***********************************************************/
/* Check if the line is totaly within the cilpping region. */
/***********************************************************/
if ((StartCode | EndCode) == FALSE)
{
Display = TRUE;
break;
}
else if (StartCode & EndCode)
break;
else
{
/**************************************************************/
/* Swap points if required to clip the other end of the line. */
/**************************************************************/
if (StartCode == FALSE)
{
Temp = xPosStart;
xPosStart = xPosEnd;
xPosEnd = Temp;
Temp = yPosStart;
yPosStart = yPosEnd;
yPosEnd = Temp;
/**********************************************/
/* Find clipping regions for the start point. */
/**********************************************/
StartCode = FALSE;
if (xPosStart < ActiveWindow.left)
StartCode |= CLIP_LEFT;
if (xPosStart > ActiveWindow.right)
StartCode |= CLIP_RIGHT;
if (yPosStart < ActiveWindow.top)
StartCode |= CLIP_TOP;
if (yPosStart > ActiveWindow.bottom)
StartCode |= CLIP_BOTTOM;
}
/************************************/
/* Calculate the slope of the line. */
/************************************/
Slope = (yPosEnd - yPosStart) / (double)(xPosEnd - xPosStart);
/*********************/
/* Do line clipping. */
/*********************/
xPosStartOriginal = xPosStart;
yPosStartOriginal = yPosStart;
if (StartCode & CLIP_LEFT)
{
xPosStart = ActiveWindow.left;
yPosStart = (long)(yPosStartOriginal
+ (ActiveWindow.left - xPosStartOriginal) * Slope);
}
if (StartCode & CLIP_RIGHT)
{
xPosStart = ActiveWindow.right;
yPosStart = (long)(yPosStartOriginal
+ (ActiveWindow.right - xPosStartOriginal) * Slope);
}
if (StartCode & CLIP_BOTTOM)
{
xPosStart = (long)(xPosStartOriginal
+ (ActiveWindow.bottom - yPosStartOriginal) / Slope);
yPosStart = ActiveWindow.bottom;
}
if (StartCode & CLIP_TOP)
{
xPosStart = (long)(xPosStartOriginal
+ (ActiveWindow.top - yPosStartOriginal) / Slope);
yPosStart = ActiveWindow.top;
}
}
} while(++Try < 2);
if (Display == TRUE)
{
/**************************************/
/* Drawing on the background surface. */
/**************************************/
BackgroundSurfaceDesc.dwSize = sizeof(BackgroundSurfaceDesc);
/********************************/
/* Lock the background surface. */
/********************************/
do
{
Result = BackgroundSurface->Lock(NULL, &BackgroundSurfaceDesc, 0, NULL);
} while(Result == DDERR_WASSTILLDRAWING);
/*************************************/
/* If the background surface locked. */
/*************************************/
if (Result == DD_OK)
{
/*********************************/
/* Draw line from bottom to top. */
/*********************************/
if (yPosStart > yPosEnd)
{
Temp = xPosStart;
xPosStart = xPosEnd;
xPosEnd = Temp;
Temp = yPosStart;
yPosStart = yPosEnd;
yPosEnd = Temp;
}
/****************************************/
/* Decide which direction to draw line. */
/****************************************/
dx = xPosEnd - xPosStart;
dy = yPosEnd - yPosStart;
if (dx > 0)
Step = 1;
else
{
Step = -1;
dx = -dx;
}
/************************************/
/* Decide which axis to plot along. */
/************************************/
if (dx > dy)
{
k1 = dy << 1;
k2 = k1 - (dx << 1);
ErrorValue = k1 - dx;
++dx;
do
{
/*******************/
/* Plot the point. */
/*******************/
((LPSTR)BackgroundSurfaceDesc.lpSurface)[ScreenWidth
* yPosStart + xPosStart] = Colour;
if (ErrorValue >= 0)
{
++yPosStart;
ErrorValue += k2;
}
else
ErrorValue += k1;
xPosStart += Step;
} while(--dx);
}
else
{
k1 = dx << 1;
k2 = k1 - (dy << 1);
ErrorValue = k1 - dy;
++dy;
do
{
/*******************/
/* Plot the point. */
/*******************/
((LPSTR)BackgroundSurfaceDesc.lpSurface)[ScreenWidth
* yPosStart + xPosStart] = Colour;
if (ErrorValue >= 0)
{
xPosStart += Step;
ErrorValue += k2;
}
else
ErrorValue += k1;
++yPosStart;
} while(--dy);
}
/**********************************/
/* Unlock the background surface. */
/**********************************/
BackgroundSurface->Unlock(NULL);
}
}
}
|
Draw a polygon on the Direct Draw frame surface.
REF: 18.22
|
void DirectDraw::DrawPolygon(const POINT* Polygon, short PointCount, char Colour)
{
short Count;
long xPosStart;
long yPosStart;
long xPosEnd;
long yPosEnd;
long dx;
long dy;
long Temp;
long Step;
long k1;
long k2;
long ErrorValue;
short Try;
short Display;
long StartCode;
long EndCode;
long xPosStartOriginal;
long yPosStartOriginal;
double Slope;
DDSURFACEDESC BackgroundSurfaceDesc;
/**************************************/
/* Drawing on the background surface. */
/**************************************/
BackgroundSurfaceDesc.dwSize = sizeof(BackgroundSurfaceDesc);
/********************************/
/* Lock the background surface. */
/********************************/
do
{
Result = BackgroundSurface->Lock(NULL, &BackgroundSurfaceDesc, 0, NULL);
} while(Result == DDERR_WASSTILLDRAWING);
/*************************************/
/* If the background surface locked. */
/*************************************/
if (Result == DD_OK)
{
for (Count = 0; Count < PointCount - 1; ++Count)
{
/*********************************************/
/* Polt point relative to the active window. */
/*********************************************/
xPosStart = Polygon[Count].x + ActiveWindow.left;
yPosStart = Polygon[Count].y + ActiveWindow.top;
xPosEnd = Polygon[Count+1].x + ActiveWindow.left;
yPosEnd = Polygon[Count+1].y + ActiveWindow.top;
/*********************************/
/* Check if line needs clipping. */
/*********************************/
Try = 0;
Display = FALSE;
do
{
/**********************************************/
/* Find clipping regions for the start point. */
/**********************************************/
StartCode = FALSE;
if (xPosStart < ActiveWindow.left)
StartCode |= CLIP_LEFT;
if (xPosStart > ActiveWindow.right)
StartCode |= CLIP_RIGHT;
if (yPosStart < ActiveWindow.top)
StartCode |= CLIP_TOP;
if (yPosStart > ActiveWindow.bottom)
StartCode |= CLIP_BOTTOM;
/********************************************/
/* Find clipping regions for the end point. */
/********************************************/
EndCode = FALSE;
if (xPosEnd < ActiveWindow.left)
EndCode |= CLIP_LEFT;
if (xPosEnd > ActiveWindow.right)
EndCode |= CLIP_RIGHT;
if (yPosEnd < ActiveWindow.top)
EndCode |= CLIP_TOP;
if (yPosEnd > ActiveWindow.bottom)
EndCode |= CLIP_BOTTOM;
/***********************************************************/
/* Check if the line is totaly within the cilpping region. */
/***********************************************************/
if ((StartCode | EndCode) == FALSE)
{
Display = TRUE;
break;
}
else if (StartCode & EndCode)
break;
else
{
/**************************************************************/
/* Swap points if required to clip the other end of the line. */
/**************************************************************/
if (StartCode == FALSE)
{
Temp = xPosStart;
xPosStart = xPosEnd;
xPosEnd = Temp;
Temp = yPosStart;
yPosStart = yPosEnd;
yPosEnd = Temp;
/**********************************************/
/* Find clipping regions for the start point. */
/**********************************************/
StartCode = FALSE;
if (xPosStart < ActiveWindow.left)
StartCode |= CLIP_LEFT;
if (xPosStart > ActiveWindow.right)
StartCode |= CLIP_RIGHT;
if (yPosStart < ActiveWindow.top)
StartCode |= CLIP_TOP;
if (yPosStart > ActiveWindow.bottom)
StartCode |= CLIP_BOTTOM;
}
/************************************/
/* Calculate the slope of the line. */
/************************************/
Slope = (yPosEnd - yPosStart) / (double)(xPosEnd - xPosStart);
/*********************/
/* Do line clipping. */
/*********************/
xPosStartOriginal = xPosStart;
yPosStartOriginal = yPosStart;
if (StartCode & CLIP_LEFT)
{
xPosStart = ActiveWindow.left;
yPosStart = (long)(yPosStartOriginal
+ (ActiveWindow.left - xPosStartOriginal) * Slope);
}
if (StartCode & CLIP_RIGHT)
{
xPosStart = ActiveWindow.right;
yPosStart = (long)(yPosStartOriginal
+ (ActiveWindow.right - xPosStartOriginal) * Slope);
}
if (StartCode & CLIP_BOTTOM)
{
xPosStart = (long)(xPosStartOriginal
+ (ActiveWindow.bottom - yPosStartOriginal) / Slope);
yPosStart = ActiveWindow.bottom;
}
if (StartCode & CLIP_TOP)
{
xPosStart = (long)(xPosStartOriginal
+ (ActiveWindow.top - yPosStartOriginal) / Slope);
yPosStart = ActiveWindow.top;
}
}
} while(++Try < 2);
if (Display == TRUE)
{
/*********************************/
/* Draw line from bottom to top. */
/*********************************/
if (yPosStart > yPosEnd)
{
Temp = xPosStart;
xPosStart = xPosEnd;
xPosEnd = Temp;
Temp = yPosStart;
yPosStart = yPosEnd;
yPosEnd = Temp;
}
/****************************************/
/* Decide which direction to draw line. */
/****************************************/
dx = xPosEnd - xPosStart;
dy = yPosEnd - yPosStart;
if (dx > 0)
Step = 1;
else
{
Step = -1;
dx = -dx;
}
/************************************/
/* Decide which axis to plot along. */
/************************************/
if (dx > dy)
{
k1 = dy << 1;
k2 = k1 - (dx << 1);
ErrorValue = k1 - dx;
++dx;
do
{
/*******************/
/* Plot the point. */
/*******************/
((LPSTR)BackgroundSurfaceDesc.lpSurface)[ScreenWidth
* yPosStart + xPosStart] = Colour;
if (ErrorValue >= 0)
{
++yPosStart;
ErrorValue += k2;
}
else
ErrorValue += k1;
xPosStart += Step;
} while(--dx);
}
else
{
k1 = dx << 1;
k2 = k1 - (dy << 1);
ErrorValue = k1 - dy;
++dy;
do
{
/*******************/
/* Plot the point. */
/*******************/
((LPSTR)BackgroundSurfaceDesc.lpSurface)[ScreenWidth
* yPosStart + xPosStart] = Colour;
if (ErrorValue >= 0)
{
xPosStart += Step;
ErrorValue += k2;
}
else
ErrorValue += k1;
++yPosStart;
} while(--dy);
}
}
}
/**********************************/
/* Unlock the background surface. */
/**********************************/
BackgroundSurface->Unlock(NULL);
}
}
|
Set the colour to use when displaying the game refresh rate. Update and draw the refresh rate on the Direct Draw game surface.
REF: 18.23
|
void DirectDraw::SetRefreshRateColour(const char NewColour, const char NewEraseColour)
{
RefreshRateText->SetColour(NewColour, NewEraseColour);
RefreshRate->SetColour(NewColour, NewEraseColour);
PauseText->SetColour(NewColour, NewEraseColour);
}
void DirectDraw::DoRefreshRate()
{
long TickCount;
TickCount = GetTickCount();
++Frames;
if (RefreshTimer < TickCount)
{
RefreshRate->SetNumber(Frames);
Frames = 0;
RefreshTimer = TickCount + 1000;
}
RefreshRateText->Draw();
RefreshRate->Draw();
}
|
Pause and un-pause the game.
REF: 18.24
|
short DirectDraw::DoPause()
{
long TickCount;
/******************************/
/* Check for pause key press. */
/******************************/
if (GetAsyncKeyState(VK_PAUSE))
{
/***************************/
/* Debounce the pause key. */
/***************************/
TickCount = GetTickCount();
if (PauseTimer < TickCount)
{
PauseFlag = !PauseFlag;
PauseText->SetVisible(PauseFlag);
PauseText->Draw();
PauseTimer = TickCount + 500;
}
}
/**************************************************/
/* The the word pause on the display when paused. */
/**************************************************/
if (PauseFlag == TRUE)
{
PauseText->Draw();
/*********************************************/
/* Flip surfaces and resotre the background. */
/*********************************************/
FlipSurfaces();
FastRestore(0, 0, ScreenWidth, ScreenHeight);
}
return PauseFlag;
}
|
|
Provide audio support for DirectX games.
REF: 19.0
|
// Asteroids Clone DirectX
// 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 __DIRECTSOUND_HPP
#define __DIRECTSOUND_HPP
typedef struct
{
BYTE *pbWaveData;
DWORD cbWaveSize;
int iAlloc;
int iCurrent;
IDirectSoundBuffer* Buffers[1];
} SNDOBJ, *HSNDOBJ;
class DirectSound
{
public:
DirectSound();
~DirectSound();
void Initialise(HWND hWnd, short Buffers);
void CreateObject(LPCTSTR lpName, int iConcurrent);
void Play(short Object, DWORD dwPlayFlags);
void Stop(short Object);
HRESULT GetStatus(short Object);
BOOL DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName);
private:
void SndObjDestroy(SNDOBJ *pSO);
IDirectSoundBuffer *DSLoadSoundBuffer(IDirectSound *pDS, LPCTSTR lpName);
BOOL DSGetWaveResource(HMODULE hModule, LPCTSTR lpName,
WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData,
DWORD *pcbWaveSize);
IDirectSoundBuffer* SndObjGetFreeBuffer(SNDOBJ *pSO);
BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData,
DWORD cbWaveSize);
BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader,
BYTE **ppbWaveData,DWORD *pcbWaveSize);
long Result;
short Objects;
short NextObject;
LPDIRECTSOUND DirectSoundObject;
SNDOBJ** SoundObjects;
char** Filename;
};
#endif
|
|
When destroying the class, ensure all DirectX resources are freed.
REF: 20.0
|
// Asteroids Clone DirectX
// 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/>.
#define WIN32_LEAN_AND_MEAN
#define CINTERFACE
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <dsound.h>
#include "DIRECTSOUND.HPP"
DirectSound::DirectSound()
{
}
DirectSound::~DirectSound()
{
short Count;
for (Count = 0; Count < NextObject; ++Count)
{
SndObjDestroy(SoundObjects[Count]);
delete [] Filename[Count];
}
if (DirectSoundObject)
DirectSoundObject->lpVtbl->Release(DirectSoundObject);
delete [] SoundObjects;
delete [] Filename;
}
|
Initialize the sound class ready for the number of sound resources the game will use.
REF: 20.1
|
void DirectSound::Initialise(HWND hWnd, short NewObjects)
{
NextObject = 0;
Objects = NewObjects;
Result = DirectSoundCreate(NULL, &DirectSoundObject, NULL);
if (Result == DS_OK)
Result = DirectSoundObject->lpVtbl->SetCooperativeLevel(DirectSoundObject,
hWnd, DSSCL_NORMAL);
if (Result == DS_OK)
{
SoundObjects = new SNDOBJ*[Objects];
Filename = new char*[Objects];
}
}
|
Load a sound resource and it's properties.
REF: 20.2
|
void DirectSound::CreateObject(LPCTSTR lpName, int iConcurrent)
{
LPWAVEFORMATEX pWaveHeader;
BYTE *pbData;
DWORD cbData;
if (Result == DS_OK)
{
if (DSGetWaveResource(NULL, lpName, &pWaveHeader, &pbData, &cbData))
{
if (iConcurrent < 1)
iConcurrent = 1;
if ((SoundObjects[NextObject] = (SNDOBJ *)LocalAlloc(LPTR, sizeof(SNDOBJ)
+ (iConcurrent-1)
* sizeof(IDirectSoundBuffer *))) != NULL)
{
int i;
Filename[NextObject] = new char[strlen(lpName)+1];
strcpy(Filename[NextObject], lpName);
SoundObjects[NextObject]->iAlloc = iConcurrent;
SoundObjects[NextObject]->pbWaveData = pbData;
SoundObjects[NextObject]->cbWaveSize = cbData;
SoundObjects[NextObject]->Buffers[0]
= DSLoadSoundBuffer(DirectSoundObject, lpName);
for (i=1; iiAlloc; i++)
{
if (FAILED(IDirectSound_DuplicateSoundBuffer(DirectSoundObject,
SoundObjects[NextObject]->Buffers[0],
&SoundObjects[NextObject]->Buffers[i])))
{
SoundObjects[NextObject]->Buffers[i]
= DSLoadSoundBuffer(DirectSoundObject, lpName);
if (!SoundObjects[NextObject]->Buffers[i]) {
SndObjDestroy(SoundObjects[NextObject]);
SoundObjects[NextObject] = NULL;
break;
}
}
}
++NextObject;
}
}
}
}
|
Start a DirectX sound buffer playing.
REF: 20.3
|
void DirectSound::Play(short Object, DWORD dwPlayFlags)
{
if (Result == DS_OK)
{
if (SoundObjects[Object] == NULL)
return;
if ((!(dwPlayFlags & DSBPLAY_LOOPING) || (SoundObjects[Object]->iAlloc == 1)))
{
IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(SoundObjects[Object]);
if (pDSB != NULL) {
if (IDirectSoundBuffer_Play(pDSB, 0, 0, dwPlayFlags)
== DSERR_BUFFERLOST)
if (IDirectSoundBuffer_Restore(pDSB) != DS_OK)
DSReloadSoundBuffer(pDSB, Filename[Object]);
}
}
}
}
|
Stop a DirectX sound buffer if it is currently playing.
REF: 20.4
|
void DirectSound::Stop(short Object)
{
int i;
if (Result == DS_OK)
{
if (SoundObjects[Object] == NULL)
return;
for (i = 0; i < SoundObjects[Object]->iAlloc; i++)
{
IDirectSoundBuffer_Stop(SoundObjects[Object]->Buffers[i]);
IDirectSoundBuffer_SetCurrentPosition(SoundObjects[Object]->Buffers[i], 0);
}
}
}
|
Check if a DirectX sound buffer is currently playing.
REF: 20.5
|
HRESULT DirectSound::GetStatus(short Object)
{
int i;
HRESULT Status;
Status = DS_OK;
if (Result == DS_OK)
{
if (SoundObjects[Object] != NULL)
{
for (i = 0; i < SoundObjects[Object]->iAlloc; i++)
{
Status = IDirectSoundBuffer_GetStatus(SoundObjects[Object]->Buffers[i],
0);
if (Status == DSBSTATUS_LOOPING || Status == DSBSTATUS_PLAYING)
break;
}
}
}
return Status;
}
|
Load a sound resource into a DirectX sound buffer.
REF: 20.6
|
IDirectSoundBuffer *DirectSound::DSLoadSoundBuffer(IDirectSound *pDS, LPCTSTR lpName)
{
IDirectSoundBuffer *pDSB = NULL;
DSBUFFERDESC dsBD = {0};
BYTE *pbWaveData;
if (DSGetWaveResource(NULL, lpName, &dsBD.lpwfxFormat,
&pbWaveData, &dsBD.dwBufferBytes))
{
dsBD.dwSize = sizeof(dsBD);
dsBD.dwFlags = DSBCAPS_STATIC
| DSBCAPS_CTRLDEFAULT
| DSBCAPS_GETCURRENTPOSITION2;
if (SUCCEEDED(IDirectSound_CreateSoundBuffer(pDS, &dsBD, &pDSB, NULL)))
{
if (!DSFillSoundBuffer(pDSB, pbWaveData, dsBD.dwBufferBytes))
{
IDirectSoundBuffer_Release(pDSB);
pDSB = NULL;
}
}
else
{
pDSB = NULL;
}
}
return pDSB;
}
|
Reload a sound resource into a DirectX sound buffer.
REF: 20.7
|
BOOL DirectSound::DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName)
{
BOOL result=FALSE;
BYTE *pbWaveData;
DWORD cbWaveSize;
if (DSGetWaveResource(NULL, lpName, NULL, &pbWaveData, &cbWaveSize))
{
if (SUCCEEDED(IDirectSoundBuffer_Restore(pDSB)) &&
DSFillSoundBuffer(pDSB, pbWaveData, cbWaveSize))
{
result = TRUE;
}
}
return result;
}
|
Load a sound resource.
REF: 20.8
|
BOOL DirectSound::DSGetWaveResource(HMODULE hModule, LPCTSTR lpName,
WAVEFORMATEX **ppWaveHeader,
BYTE **ppbWaveData, DWORD *pcbWaveSize)
{
HRSRC hResInfo;
HGLOBAL hResData;
void *pvRes;
if (((hResInfo = FindResource(hModule, lpName, "WAVE")) != NULL) &&
((hResData = LoadResource(hModule, hResInfo)) != NULL) &&
((pvRes = LockResource(hResData)) != NULL) &&
DSParseWaveResource(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize))
{
return TRUE;
}
return FALSE;
}
|
Release a DirectX sound buffer.
REF: 20.9
|
void DirectSound::SndObjDestroy(SNDOBJ *pSO)
{
if (pSO)
{
int i;
for (i=0; iiAlloc; i++)
{
if (pSO->Buffers[i])
{
IDirectSoundBuffer_Release(pSO->Buffers[i]);
pSO->Buffers[i] = NULL;
}
}
LocalFree((HANDLE)pSO);
}
}
|
Find a DirectX sound buffer which is not currently playing a sound.
REF: 20.10
|
IDirectSoundBuffer* DirectSound::SndObjGetFreeBuffer(SNDOBJ *pSO)
{
IDirectSoundBuffer *pDSB;
if (pSO == NULL)
return NULL;
if (pDSB = pSO->Buffers[pSO->iCurrent])
{
HRESULT hres;
DWORD dwStatus;
hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus);
if (FAILED(hres))
dwStatus = 0;
if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
if (pSO->iAlloc > 1)
{
if (++pSO->iCurrent >= pSO->iAlloc)
pSO->iCurrent = 0;
pDSB = pSO->Buffers[pSO->iCurrent];
hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus);
if (SUCCEEDED(hres)
&& (dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
{
IDirectSoundBuffer_Stop(pDSB);
IDirectSoundBuffer_SetCurrentPosition(pDSB, 0);
}
}
else
{
pDSB = NULL;
}
}
if (pDSB && (dwStatus & DSBSTATUS_BUFFERLOST))
{
if (FAILED(IDirectSoundBuffer_Restore(pDSB)) ||
!DSFillSoundBuffer(pDSB, pSO->pbWaveData, pSO->cbWaveSize))
{
pDSB = NULL;
}
}
}
return pDSB;
}
|
Copy sound data into a DirectX sound buffer.
REF: 20.11
|
BOOL DirectSound::DSFillSoundBuffer(IDirectSoundBuffer *pDSB,
BYTE *pbWaveData, DWORD cbWaveSize)
{
if (pDSB && pbWaveData && cbWaveSize)
{
LPVOID pMem1, pMem2;
DWORD dwSize1, dwSize2;
if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize,
&pMem1, &dwSize1, &pMem2, &dwSize2, 0)))
{
CopyMemory(pMem1, pbWaveData, dwSize1);
if ( 0 != dwSize2 )
CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2);
IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2);
return TRUE;
}
}
return FALSE;
}
|
Get the properties of sound data by parsing the data.
REF: 20.12
|
BOOL DirectSound::DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader,
BYTE **ppbWaveData,DWORD *pcbWaveSize)
{
DWORD *pdw;
DWORD *pdwEnd;
DWORD dwRiff;
DWORD dwType;
DWORD dwLength;
if (ppWaveHeader)
*ppWaveHeader = NULL;
if (ppbWaveData)
*ppbWaveData = NULL;
if (pcbWaveSize)
*pcbWaveSize = 0;
pdw = (DWORD *)pvRes;
dwRiff = *pdw++;
dwLength = *pdw++;
dwType = *pdw++;
if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
goto exit;
if (dwType != mmioFOURCC('W', 'A', 'V', 'E'))
goto exit;
pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
while (pdw < pdwEnd)
{
dwType = *pdw++;
dwLength = *pdw++;
switch (dwType)
{
case mmioFOURCC('f', 'm', 't', ' '):
if (ppWaveHeader && !*ppWaveHeader)
{
if (dwLength < sizeof(WAVEFORMAT))
goto exit;
*ppWaveHeader = (WAVEFORMATEX *)pdw;
if ((!ppbWaveData || *ppbWaveData) &&
(!pcbWaveSize || *pcbWaveSize))
{
return TRUE;
}
}
break;
case mmioFOURCC('d', 'a', 't', 'a'):
if ((ppbWaveData && !*ppbWaveData) ||
(pcbWaveSize && !*pcbWaveSize))
{
if (ppbWaveData)
*ppbWaveData = (LPBYTE)pdw;
if (pcbWaveSize)
*pcbWaveSize = dwLength;
if (!ppWaveHeader || *ppWaveHeader)
return TRUE;
}
break;
}
pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
}
exit:
return FALSE;
}
|
|
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 DirectX surface. 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: 21.0
|
// Asteroids Clone DirectX
// 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 __POLYGONNUMBER_HPP
#define __POLYGONNUMBER_HPP
class DirectDraw;
class DirectSound;
class PolygonNumber
{
public:
enum
{
DIGITS = 10,
MAX_POINTS = 10,
INFINATE_FRAMES = -1,
DEFAULT_COLOUR = 2,
DEFAULT_ERASECOLOUR = 1,
};
PolygonNumber(DirectDraw* NewDrawX, DirectSound* NewSoundX, short NewxOffset,
short NewyOffset, short NewMaxX, short NewMaxY, short NewScale,
short NewFrames, short NewFlash, short NewDigits,
short NewVisible);
~PolygonNumber();
void Draw(short Orientation = FALSE);
void SetVisible(short NewVisible);
short GetVisible();
long GetNumber();
void SetNumber(long NewNumber);
void SetFlash(const unsigned short NewFlash);
void SetColour(const char NewColour,
const char NewEraseColour = DEFAULT_ERASECOLOUR);
void SetFrames(const unsigned short NewFrames);
void SetFrameCount(const unsigned short NewFrameCount);
unsigned short GetFrameCount();
private:
DirectDraw* DrawX;
DirectSound* SoundX;
short MaxX;
short MaxY;
short Digits;
short xOffset;
short yOffset;
short Scale;
short Visible;
short LastVisible;
short FlashVisible;
short Active;
short Frames;
short FrameCount;
short Flash;
long NumberValue;
char Colour;
char EraseColour;
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.
The constructor initializes the object. It sets the objects properties passed in as arguments. When the object draws it's image to a DirectX surface, 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: 22.0
|
// Asteroids Clone DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
PolygonNumber::PolygonNumber(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short NewxOffset, short NewyOffset, short NewMaxX,
short NewMaxY, short NewScale, short NewFrames,
short NewFlash, short NewDigits, short NewVisible)
{
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
MaxX = NewMaxX;
MaxY = NewMaxY;
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = Visible;
FrameCount = NewFrames;
xOffset = NewxOffset;
yOffset = NewyOffset;
Scale = NewScale;
Frames = NewFrames;
Flash = NewFlash;
Colour = DEFAULT_COLOUR;
EraseColour = DEFAULT_ERASECOLOUR;
Digits = NewDigits;
NumberValue = 0;
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;
}
PolygonNumber::~PolygonNumber()
{
}
|
Each of the game objects has a draw function which draws the current state of the object onto a DirectX surface.
REF: 22.1
|
void PolygonNumber::Draw(short Orientation)
{
short Digit;
short Count;
div_t Divide;
long TempNumber;
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;
}
/*****************************/
/* Plot score current value. */
/*****************************/
TempNumber = NumberValue;
for (Digit = 0; Digit < Digits; ++Digit)
{
Divide = div(TempNumber, 10);
TempNumber = Divide.quot;
for (Count = 0; Count < Decimal[Divide.rem][MAX_POINTS].x; ++Count)
{
if (Orientation == FALSE)
{
DisplayFrame[Digit][Count].x = Decimal[Divide.rem][Count].x
+ xOffset + (Digits - Digit) * 3*Scale;
DisplayFrame[Digit][Count].y = Decimal[Divide.rem][Count].y + yOffset;
}
else
{
DisplayFrame[Digit][Count].x = MaxX - (Decimal[Divide.rem][Count].x
+ xOffset + (Digits - Digit) * 3*Scale);
DisplayFrame[Digit][Count].y = MaxY - (Decimal[Divide.rem][Count].y
+ yOffset);
}
}
DisplayFrame[Digit][MAX_POINTS].x = Decimal[Divide.rem][MAX_POINTS].x;
/*************************/
/* Erase previous score. */
/*************************/
if (Visible == FALSE)
Active = FALSE;
if (Active == FALSE || FlashVisible == FALSE)
DrawX->DrawPolygon(OldFrame[Digit],
(short)(OldFrame[Digit][MAX_POINTS].x),
EraseColour);
else
/***************************/
/* Draw the current score. */
/***************************/
DrawX->DrawPolygon(DisplayFrame[Digit],
(short)(DisplayFrame[Digit][MAX_POINTS].x),
Colour);
}
/***************************************/
/* Plot current score, */
/* next time it will be the old score. */
/***************************************/
memcpy(OldFrame, DisplayFrame, DIGITS * MAX_POINTS * sizeof(POINT));
}
}
|
There are member functions to set and read the value member variables for the class.
REF: 22.2
|
void PolygonNumber::SetVisible(short NewVisible)
{
if (NewVisible != LastVisible)
{
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = TRUE;
FrameCount = Frames;
}
}
short PolygonNumber::GetVisible()
{
return Active;
}
long PolygonNumber::GetNumber()
{
return NumberValue;
}
void PolygonNumber::SetNumber(long NewNumber)
{
short OldVisible;
OldVisible = Visible;
Visible = FALSE;
Draw();
Active = TRUE;
Visible = OldVisible;
NumberValue = NewNumber;
}
void PolygonNumber::SetFlash(const unsigned short NewFlash)
{
Flash = NewFlash;
FrameCount = Frames;
}
void PolygonNumber::SetColour(const char NewColour, const char NewEraseColour)
{
Colour = NewColour;
EraseColour = NewEraseColour;
}
void PolygonNumber::SetFrames(const unsigned short NewFrames)
{
Frames = NewFrames;
FrameCount = Frames;
}
void PolygonNumber::SetFrameCount(const unsigned short NewFrameCount)
{
FrameCount = NewFrameCount;
}
unsigned short PolygonNumber::GetFrameCount()
{
return FrameCount;
}
|
|
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 DirectX surface. 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: 23.0
|
// Asteroids Clone DirectX
// 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 __POLYGONTEXT_HPP
#define __POLYGONTEXT_HPP
class DirectDraw;
class DirectSound;
class PolygonText
{
public:
enum
{
MAX_LETTERS = 26,
MAX_POINTS = 10,
MAX_TEXT = 255,
INFINATE_FRAMES = -1,
DEFAULT_COLOUR = 2,
DEFAULT_ERASECOLOUR = 1,
};
PolygonText(DirectDraw* NewDrawX, DirectSound* NewSoundX, short NewxOffset,
short NewyOffset, short NewMaxX, short NewMaxY, short NewScale,
short NewFrames, short NewFlash, char* NewText,
short NewVisible = FALSE);
~PolygonText();
void Draw();
void SetVisible(short NewVisible);
short GetVisible();
void SetColour(const char NewColour,
const char NewEraseColour = DEFAULT_ERASECOLOUR);
void SetText(const char* NewText, short Orientation = FALSE);
const char* GetText();
void SetFlash(const unsigned short NewFlash);
void SetFrames(const unsigned short NewFrames);
void SetFrameCount(const unsigned short NewFrameCount);
unsigned short GetFrameCount();
private:
DirectDraw* DrawX;
DirectSound* SoundX;
short MaxX;
short MaxY;
short xOffset;
short yOffset;
short Scale;
short Visible;
short LastVisible;
short FlashVisible;
short Active;
short Frames;
short FrameCount;
short Flash;
char Colour;
char EraseColour;
char TextString[MAX_TEXT+1];
POINT Letter[MAX_LETTERS][MAX_POINTS+1];
POINT DisplayFrame[MAX_TEXT][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.
Constructor initializes the object. It sets the objects properties passed in as arguments. When the object draws it's image to a DirectX surface, 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: 24.0
|
// Asteroids Clone DirectX
// 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 <ddraw.h>
#include <dsound.h>
#include "POLYGONTEXT.HPP"
#include "POLYGONNUMBER.HPP"
#include "DIRECTDRAW.HPP"
#include "DIRECTSOUND.HPP"
PolygonText::PolygonText(DirectDraw* NewDrawX, DirectSound* NewSoundX,
short NewxOffset, short NewyOffset, short NewMaxX,
short NewMaxY, short NewScale, short NewFrames,
short NewFlash, char* NewText, short NewVisible)
{
/**********************************************************/
/* Store a pointer to the DirectX Draw and Sound objects. */
/**********************************************************/
DrawX = NewDrawX;
SoundX = NewSoundX;
MaxX = NewMaxX;
MaxY = NewMaxY;
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = Visible;
FrameCount = NewFrames;
xOffset = NewxOffset;
yOffset = NewyOffset;
Scale = NewScale;
Frames = NewFrames;
Flash = NewFlash;
Colour = DEFAULT_COLOUR;
EraseColour = DEFAULT_ERASECOLOUR;
Letter[0][MAX_POINTS].x = 6;
Letter[0][0].x = 0*Scale;
Letter[0][0].y = 4*Scale;
Letter[0][1].x = 0*Scale;
Letter[0][1].y = 0*Scale;
Letter[0][2].x = 3*Scale;
Letter[0][2].y = 0*Scale;
Letter[0][3].x = 3*Scale;
Letter[0][3].y = 4*Scale;
Letter[0][4].x = 3*Scale;
Letter[0][4].y = 2*Scale;
Letter[0][5].x = 0*Scale;
Letter[0][5].y = 2*Scale;
Letter[1][MAX_POINTS].x = 8;
Letter[1][0].x = 0*Scale;
Letter[1][0].y = 0*Scale;
Letter[1][1].x = 0*Scale;
Letter[1][1].y = 4*Scale;
Letter[1][2].x = 3*Scale;
Letter[1][2].y = 4*Scale;
Letter[1][3].x = 3*Scale;
Letter[1][3].y = 3*Scale;
Letter[1][4].x = 0*Scale;
Letter[1][4].y = 2*Scale;
Letter[1][5].x = 3*Scale;
Letter[1][5].y = 1*Scale;
Letter[1][6].x = 3*Scale;
Letter[1][6].y = 0*Scale;
Letter[1][7].x = 0*Scale;
Letter[1][7].y = 0*Scale;
Letter[2][MAX_POINTS].x = 6;
Letter[2][0].x = 3*Scale;
Letter[2][0].y = 0*Scale;
Letter[2][1].x = 1*Scale;
Letter[2][1].y = 0*Scale;
Letter[2][2].x = 0*Scale;
Letter[2][2].y = 1*Scale;
Letter[2][3].x = 0*Scale;
Letter[2][3].y = 3*Scale;
Letter[2][4].x = 1*Scale;
Letter[2][4].y = 4*Scale;
Letter[2][5].x = 3*Scale;
Letter[2][5].y = 4*Scale;
Letter[3][MAX_POINTS].x = 6;
Letter[3][0].x = 0*Scale;
Letter[3][0].y = 0*Scale;
Letter[3][1].x = 0*Scale;
Letter[3][1].y = 4*Scale;
Letter[3][2].x = 1*Scale;
Letter[3][2].y = 4*Scale;
Letter[3][3].x = 3*Scale;
Letter[3][3].y = 2*Scale;
Letter[3][4].x = 1*Scale;
Letter[3][4].y = 0*Scale;
Letter[3][5].x = 0*Scale;
Letter[3][5].y = 0*Scale;
Letter[4][MAX_POINTS].x = 7;
Letter[4][0].x = 3*Scale;
Letter[4][0].y = 0*Scale;
Letter[4][1].x = 0*Scale;
Letter[4][1].y = 0*Scale;
Letter[4][2].x = 0*Scale;
Letter[4][2].y = 2*Scale;
Letter[4][3].x = 2*Scale;
Letter[4][3].y = 2*Scale;
Letter[4][4].x = 0*Scale;
Letter[4][4].y = 2*Scale;
Letter[4][5].x = 0*Scale;
Letter[4][5].y = 4*Scale;
Letter[4][6].x = 3*Scale;
Letter[4][6].y = 4*Scale;
Letter[5][MAX_POINTS].x = 6;
Letter[5][0].x = 3*Scale;
Letter[5][0].y = 0*Scale;
Letter[5][1].x = 0*Scale;
Letter[5][1].y = 0*Scale;
Letter[5][2].x = 0*Scale;
Letter[5][2].y = 2*Scale;
Letter[5][3].x = 2*Scale;
Letter[5][3].y = 2*Scale;
Letter[5][4].x = 0*Scale;
Letter[5][4].y = 2*Scale;
Letter[5][5].x = 0*Scale;
Letter[5][5].y = 4*Scale;
Letter[6][MAX_POINTS].x = 6;
Letter[6][0].x = 3*Scale;
Letter[6][0].y = 0*Scale;
Letter[6][1].x = 0*Scale;
Letter[6][1].y = 0*Scale;
Letter[6][2].x = 0*Scale;
Letter[6][2].y = 4*Scale;
Letter[6][3].x = 3*Scale;
Letter[6][3].y = 4*Scale;
Letter[6][4].x = 3*Scale;
Letter[6][4].y = 2*Scale;
Letter[6][5].x = 1*Scale;
Letter[6][5].y = 2*Scale;
Letter[7][MAX_POINTS].x = 6;
Letter[7][0].x = 0*Scale;
Letter[7][0].y = 0*Scale;
Letter[7][1].x = 0*Scale;
Letter[7][1].y = 4*Scale;
Letter[7][2].x = 0*Scale;
Letter[7][2].y = 2*Scale;
Letter[7][3].x = 3*Scale;
Letter[7][3].y = 2*Scale;
Letter[7][4].x = 3*Scale;
Letter[7][4].y = 0*Scale;
Letter[7][5].x = 3*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 = 3*Scale;
Letter[8][1].y = 0*Scale;
Letter[8][2].x = 2*Scale;
Letter[8][2].y = 0*Scale;
Letter[8][3].x = 2*Scale;
Letter[8][3].y = 4*Scale;
Letter[8][4].x = 1*Scale;
Letter[8][4].y = 4*Scale;
Letter[8][5].x = 3*Scale;
Letter[8][5].y = 4*Scale;
Letter[9][MAX_POINTS].x = 6;
Letter[9][0].x = 1*Scale;
Letter[9][0].y = 0*Scale;
Letter[9][1].x = 3*Scale;
Letter[9][1].y = 0*Scale;
Letter[9][2].x = 2*Scale;
Letter[9][2].y = 0*Scale;
Letter[9][3].x = 2*Scale;
Letter[9][3].y = 4*Scale;
Letter[9][4].x = 0*Scale;
Letter[9][4].y = 4*Scale;
Letter[9][5].x = 0*Scale;
Letter[9][5].y = 3*Scale;
Letter[10][MAX_POINTS].x = 6;
Letter[10][0].x = 0*Scale;
Letter[10][0].y = 0*Scale;
Letter[10][1].x = 0*Scale;
Letter[10][1].y = 4*Scale;
Letter[10][2].x = 0*Scale;
Letter[10][2].y = 2*Scale;
Letter[10][3].x = 3*Scale;
Letter[10][3].y = 0*Scale;
Letter[10][4].x = 0*Scale;
Letter[10][4].y = 2*Scale;
Letter[10][5].x = 3*Scale;
Letter[10][5].y = 4*Scale;
Letter[11][MAX_POINTS].x = 3;
Letter[11][0].x = 0*Scale;
Letter[11][0].y = 0*Scale;
Letter[11][1].x = 0*Scale;
Letter[11][1].y = 4*Scale;
Letter[11][2].x = 3*Scale;
Letter[11][2].y = 4*Scale;
Letter[12][MAX_POINTS].x = 6;
Letter[12][0].x = 0*Scale;
Letter[12][0].y = 4*Scale;
Letter[12][1].x = 0*Scale;
Letter[12][1].y = 0*Scale;
Letter[12][2].x = 1*Scale;
Letter[12][2].y = 2*Scale;
Letter[12][3].x = 2*Scale;
Letter[12][3].y = 2*Scale;
Letter[12][4].x = 3*Scale;
Letter[12][4].y = 0*Scale;
Letter[12][5].x = 3*Scale;
Letter[12][5].y = 4*Scale;
Letter[13][MAX_POINTS].x = 4;
Letter[13][0].x = 0*Scale;
Letter[13][0].y = 4*Scale;
Letter[13][1].x = 0*Scale;
Letter[13][1].y = 0*Scale;
Letter[13][2].x = 3*Scale;
Letter[13][2].y = 4*Scale;
Letter[13][3].x = 3*Scale;
Letter[13][3].y = 0*Scale;
Letter[14][MAX_POINTS].x = 9;
Letter[14][0].x = 0*Scale;
Letter[14][0].y = 1*Scale;
Letter[14][1].x = 0*Scale;
Letter[14][1].y = 3*Scale;
Letter[14][2].x = 1*Scale;
Letter[14][2].y = 4*Scale;
Letter[14][3].x = 2*Scale;
Letter[14][3].y = 4*Scale;
Letter[14][4].x = 3*Scale;
Letter[14][4].y = 3*Scale;
Letter[14][5].x = 3*Scale;
Letter[14][5].y = 1*Scale;
Letter[14][6].x = 2*Scale;
Letter[14][6].y = 0*Scale;
Letter[14][7].x = 1*Scale;
Letter[14][7].y = 0*Scale;
Letter[14][8].x = 0*Scale;
Letter[14][8].y = 1*Scale;
Letter[15][MAX_POINTS].x = 5;
Letter[15][0].x = 0*Scale;
Letter[15][0].y = 4*Scale;
Letter[15][1].x = 0*Scale;
Letter[15][1].y = 0*Scale;
Letter[15][2].x = 3*Scale;
Letter[15][2].y = 0*Scale;
Letter[15][3].x = 3*Scale;
Letter[15][3].y = 2*Scale;
Letter[15][4].x = 0*Scale;
Letter[15][4].y = 2*Scale;
Letter[16][MAX_POINTS].x = 6;
Letter[16][0].x = 2*Scale;
Letter[16][0].y = 3*Scale;
Letter[16][1].x = 3*Scale;
Letter[16][1].y = 4*Scale;
Letter[16][2].x = 0*Scale;
Letter[16][2].y = 4*Scale;
Letter[16][3].x = 0*Scale;
Letter[16][3].y = 0*Scale;
Letter[16][4].x = 3*Scale;
Letter[16][4].y = 0*Scale;
Letter[16][5].x = 3*Scale;
Letter[16][5].y = 4*Scale;
Letter[17][MAX_POINTS].x = 6;
Letter[17][0].x = 0*Scale;
Letter[17][0].y = 4*Scale;
Letter[17][1].x = 0*Scale;
Letter[17][1].y = 0*Scale;
Letter[17][2].x = 3*Scale;
Letter[17][2].y = 0*Scale;
Letter[17][3].x = 3*Scale;
Letter[17][3].y = 2*Scale;
Letter[17][4].x = 0*Scale;
Letter[17][4].y = 2*Scale;
Letter[17][5].x = 3*Scale;
Letter[17][5].y = 4*Scale;
Letter[18][MAX_POINTS].x = 8;
Letter[18][0].x = 3*Scale;
Letter[18][0].y = 0*Scale;
Letter[18][1].x = 1*Scale;
Letter[18][1].y = 0*Scale;
Letter[18][2].x = 0*Scale;
Letter[18][2].y = 1*Scale;
Letter[18][3].x = 1*Scale;
Letter[18][3].y = 2*Scale;
Letter[18][4].x = 2*Scale;
Letter[18][4].y = 2*Scale;
Letter[18][5].x = 3*Scale;
Letter[18][5].y = 3*Scale;
Letter[18][6].x = 2*Scale;
Letter[18][6].y = 4*Scale;
Letter[18][7].x = 0*Scale;
Letter[18][7].y = 4*Scale;
Letter[19][MAX_POINTS].x = 4;
Letter[19][0].x = 1*Scale;
Letter[19][0].y = 0*Scale;
Letter[19][1].x = 3*Scale;
Letter[19][1].y = 0*Scale;
Letter[19][2].x = 2*Scale;
Letter[19][2].y = 0*Scale;
Letter[19][3].x = 2*Scale;
Letter[19][3].y = 4*Scale;
Letter[20][MAX_POINTS].x = 6;
Letter[20][0].x = 0*Scale;
Letter[20][0].y = 0*Scale;
Letter[20][1].x = 0*Scale;
Letter[20][1].y = 3*Scale;
Letter[20][2].x = 1*Scale;
Letter[20][2].y = 4*Scale;
Letter[20][3].x = 2*Scale;
Letter[20][3].y = 4*Scale;
Letter[20][4].x = 3*Scale;
Letter[20][4].y = 3*Scale;
Letter[20][5].x = 3*Scale;
Letter[20][5].y = 0*Scale;
Letter[21][MAX_POINTS].x = 4;
Letter[21][0].x = 0*Scale;
Letter[21][0].y = 0*Scale;
Letter[21][1].x = 1*Scale;
Letter[21][1].y = 4*Scale;
Letter[21][2].x = 2*Scale;
Letter[21][2].y = 4*Scale;
Letter[21][3].x = 3*Scale;
Letter[21][3].y = 0*Scale;
Letter[22][MAX_POINTS].x = 6;
Letter[22][0].x = 0*Scale;
Letter[22][0].y = 0*Scale;
Letter[22][1].x = 0*Scale;
Letter[22][1].y = 4*Scale;
Letter[22][2].x = 1*Scale;
Letter[22][2].y = 3*Scale;
Letter[22][3].x = 2*Scale;
Letter[22][3].y = 3*Scale;
Letter[22][4].x = 3*Scale;
Letter[22][4].y = 4*Scale;
Letter[22][5].x = 3*Scale;
Letter[22][5].y = 0*Scale;
Letter[23][MAX_POINTS].x = 7;
Letter[23][0].x = 1*Scale;
Letter[23][0].y = 0*Scale;
Letter[23][1].x = 2*Scale;
Letter[23][1].y = 2*Scale;
Letter[23][2].x = 3*Scale;
Letter[23][2].y = 0*Scale;
Letter[23][3].x = 2*Scale;
Letter[23][3].y = 2*Scale;
Letter[23][4].x = 1*Scale;
Letter[23][4].y = 4*Scale;
Letter[23][5].x = 2*Scale;
Letter[23][5].y = 2*Scale;
Letter[23][6].x = 3*Scale;
Letter[23][6].y = 4*Scale;
Letter[24][MAX_POINTS].x = 5;
Letter[24][0].x = 1*Scale;
Letter[24][0].y = 0*Scale;
Letter[24][1].x = 2*Scale;
Letter[24][1].y = 2*Scale;
Letter[24][2].x = 3*Scale;
Letter[24][2].y = 0*Scale;
Letter[24][3].x = 2*Scale;
Letter[24][3].y = 2*Scale;
Letter[24][4].x = 2*Scale;
Letter[24][4].y = 4*Scale;
Letter[25][MAX_POINTS].x = 4;
Letter[25][0].x = 0*Scale;
Letter[25][0].y = 0*Scale;
Letter[25][1].x = 3*Scale;
Letter[25][1].y = 0*Scale;
Letter[25][2].x = 0*Scale;
Letter[25][2].y = 4*Scale;
Letter[25][3].x = 3*Scale;
Letter[25][3].y = 4*Scale;
SetText(NewText);
}
PolygonText::~PolygonText()
{
}
|
Each of the game objects has a draw function which draws the current state of the object onto a DirectX surface.
REF: 24.1
|
void PolygonText::Draw()
{
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;
}
/****************************/
/* Plot Text current value. */
/****************************/
for (Digit = 0; Digit < MAX_LETTERS && TextString[Digit] != '\0'; ++Digit)
{
if (TextString[Digit] != ' ')
{
/************************/
/* Erase previous Text. */
/************************/
if (Visible == FALSE)
Active = FALSE;
if (Active == FALSE || FlashVisible == FALSE)
DrawX->DrawPolygon(DisplayFrame[Digit],
(short)(DisplayFrame[Digit][MAX_POINTS].x),
EraseColour);
else
/**************************/
/* Draw the current Text. */
/**************************/
DrawX->DrawPolygon(DisplayFrame[Digit],
(short)(DisplayFrame[Digit][MAX_POINTS].x),
Colour);
}
}
}
}
|
There are member functions to set and read the value member variables for the class.
REF: 24.2
|
void PolygonText::SetVisible(short NewVisible)
{
if (NewVisible != LastVisible)
{
Visible = NewVisible;
LastVisible = Visible;
FlashVisible = Visible;
Active = TRUE;
FrameCount = Frames;
}
}
short PolygonText::GetVisible()
{
return Active;
}
void PolygonText::SetColour(const char NewColour, const char NewEraseColour)
{
Colour = NewColour;
EraseColour = NewEraseColour;
}
void PolygonText::SetText(const char* NewText, short Orientation)
{
short Count;
short Digit;
short OldVisible;
OldVisible = Visible;
Visible = FALSE;
Draw();
Active = TRUE;
Visible = OldVisible;
strncpy(TextString, NewText, MAX_TEXT);
for (Digit = 0; Digit < MAX_LETTERS && TextString[Digit] != '\0'; ++Digit)
{
if (TextString[Digit] != ' ')
{
for (Count = 0; Count < Letter[TextString[Digit]-'A'][MAX_POINTS].x; ++Count)
{
if (Orientation == FALSE)
{
DisplayFrame[Digit][Count].x = Letter[TextString[Digit]-'A'][Count].x
+ xOffset + Digit * 4*Scale;
DisplayFrame[Digit][Count].y = Letter[TextString[Digit]-'A'][Count].y
+ yOffset;
}
else
{
DisplayFrame[Digit][Count].x = MaxX
- (Letter[TextString[Digit]-'A'][Count].x
+ xOffset + Digit * 4*Scale);
DisplayFrame[Digit][Count].y = MaxY
- (Letter[TextString[Digit]-'A'][Count].y
+ yOffset);
}
}
DisplayFrame[Digit][MAX_POINTS].x
= Letter[TextString[Digit]-'A'][MAX_POINTS].x;
}
}
}
const char* PolygonText::GetText()
{
return TextString;
}
void PolygonText::SetFlash(const unsigned short NewFlash)
{
Flash = NewFlash;
FrameCount = Frames;
}
void PolygonText::SetFrames(const unsigned short NewFrames)
{
Frames = NewFrames;
FrameCount = Frames;
}
void PolygonText::SetFrameCount(const unsigned short NewFrameCount)
{
FrameCount = NewFrameCount;
}
unsigned short PolygonText::GetFrameCount()
{
return FrameCount;
}
|
|
|