Okay, then...that makes it easier. The first file is a resource compiler source file. You do not have the capability of making them easily in VS2008 Express, which is too bad, but I can help you with that part.
This file will be named the same as your project name. In my case, it is named ASTROB.RC In your case, you will replace astrob.h with resource.h :
#include "windows.h"
#include "astrob.h"
astrobMenu MENU
BEGIN
POPUP "&Play"
BEGIN
MENUITEM "&Start", IDM_START
MENUITEM "Exit", IDM_EXIT
END
POPUP "&Help"
BEGIN
MENUITEM "&About AstroBlast...", IDM_ABOUT
END
END
AboutBox DIALOG 22, 17, 144, 75
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "About AstroBlast"
BEGIN
CTEXT "AstroBlast" -1, 0, 5, 144, 8
CTEXT " jinzai " -1, 0, 14, 144, 8
CTEXT "March 1995" -1, 0, 24, 144, 8
CTEXT "Version 1.0" -1, 0, 34, 144, 8
CTEXT "mtb61275@yahoo.com" -1, 0, 44, 144, 8
DEFPUSHBUTTON "OK" IDOK, 53, 59, 32, 14, WS_GROUP
END
ship BITMAP astro1.bmp
alien1 BITMAP alien1.bmp
ant1 BITMAP ant1.bmp
bee1 BITMAP bee1.bmp
spider1 BITMAP spider1.bmp
scorp1 BITMAP scorp1.bmp
gator1 BITMAP gator1.bmp
cat1 BITMAP cat1.bmp
title1 BITMAP title1.bmp
Next is a file that in my case is named ASTROB.H, but in your case will be named RESOURCE.H :
#define IDM_ABOUT 100
#define IDM_START 110
#define IDM_EXIT 120
#define MAX_TORPEDO 10 // The ship can only have 10 active torpedoes.
#define MAX_ALIEN 8 // 8 attackers at a time.
#define MAX_STARS 100 // Space background.
typedef enum _ABTYPE
{
ILLEGAL_TYPE = -1,
USER_SHIP = 0,
ALIEN_1 = 1,
TORPEDO = 2,
STAR = 3
} ABTYPE;
typedef struct _ASTROBLASTPIECE
{
RECT position;
ABTYPE type;
} ASTROBLASTPIECE, *LPASTROBLASTPIECE;
HBITMAP hShipBitMap, hAlien1BitMap, hAnt1BitMap, hBee1BitMap, hSpider1BitMap,
hScorp1BitMap, hGator1BitMap, hTitle1BitMap, hCat1BitMap, hDrawBitMap;
HBRUSH hRedBrush;
HMENU hSysMenu;
RECT shiprect, torpedoes[MAX_TORPEDO], aliens[MAX_ALIEN];
POINT stars[MAX_STARS];
int num_torpedoes, num_ships, num_aliens, max_aliens_level, level,
num_stars, kills, alien_xinc, alien_yinc, idTimer1, fortymsec,
second, minute, idle, width, height;
BOOL bPlaying, bGameOver, bPaused;
long score, scores[10];
DWORD dwInterval1, dwStartGenClock, dwSeconds, dwTemp;
double total_fired, num_hits;
char szstatus[80];
int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int);
BOOL InitApplication(HANDLE);
BOOL InitInstance(HANDLE, int);
long FAR PASCAL MainWndProc(HWND, unsigned, WORD, LONG);
BOOL FAR PASCAL About(HWND, unsigned, WORD, LONG);
void StartGame(void);
int RemoveTorpedo(int torpedo_number);
int RemoveAlien(int alien_number);
int RemoveStar(int star_number);
BOOL GenerateAlien(int alien_number);
void DestroyShip(void);
The next file is the main source file. Mine is named ASTROB.C, but yours should have the extension .cpp :
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "astrob.h"
HANDLE hInst;
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
if (!hPrevInstance)
if (!InitApplication(hInstance)) return FALSE;
if (!InitInstance(hInstance, nCmdShow)) return FALSE;
while (GetMessage(&msg, NULL, NULL, NULL))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
BOOL InitApplication(HANDLE hInstance)
{
WNDCLASS wc;
wc.style = NULL;
wc.lpfnWndProc = MainWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = "astrobMenu";
wc.lpszClassName = "astrobWClass";
return RegisterClass(&wc);
}
BOOL InitInstance(HANDLE hInstance, int nCmdShow)
{
int i;
HWND hWnd;
hInst = hInstance;
hWnd = CreateWindow("astrobWClass", "AstroBlast DEMO",
WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, 300, 400, NULL, NULL,
hInstance, NULL);
if (!hWnd) return FALSE;
ShowWindow(hWnd, nCmdShow);
hShipBitMap = LoadBitmap(hInstance, "ship");
hAlien1BitMap = LoadBitmap(hInstance, "alien1");
hAnt1BitMap = LoadBitmap(hInstance, "ant1");
hBee1BitMap = LoadBitmap(hInstance, "bee1");
hSpider1BitMap = LoadBitmap(hInstance, "spider1");
hScorp1BitMap = LoadBitmap(hInstance, "scorp1");
hGator1BitMap = LoadBitmap(hInstance, "gator1");
hCat1BitMap = LoadBitmap(hInstance, "cat1");
hTitle1BitMap = LoadBitmap(hInstance, "title1");
hRedBrush = CreateSolidBrush(RGB(255, 0, 0));
hSysMenu = GetSystemMenu(hWnd, FALSE);
bPlaying = bGameOver = bPaused = FALSE;
idTimer1 = SetTimer(hWnd, NULL, 40, NULL);
fortymsec = second = minute = 0;
dwInterval1 = 0;
num_stars = MAX_STARS;
for (i = 0; i < num_stars; i++)
{
stars[i].x = rand() / (RAND_MAX / (300 - 32));
stars[i].y = rand() / (RAND_MAX / 400);
}
UpdateWindow(hWnd);
return TRUE;
}
LONG FAR PASCAL MainWndProc(HWND hWnd, unsigned message, WORD wParam,
LONG lParam)
{
HDC hDC, hMemoryDC;
HBITMAP hOldBitmap;
HBRUSH hOldBrush;
PAINTSTRUCT ps;
RECT rect;
int i, j;
FARPROC lpProcAbout;
DWORD dwNow;
switch (message)
{
case WM_TIMER:
dwNow = GetTickCount(); // Get tick count. (mSecs)
if (++fortymsec == 25)
{
if (++second == 60)
{
minute++;
second = 0;
}
fortymsec = 0;
}
if (bPlaying && !bPaused)
{
// Generate a new alien every second until max aliens are on screen.
if ((num_aliens < max_aliens_level) &&
((dwNow - dwStartGenClock) > 1000))
{
GenerateAlien(num_aliens);
dwStartGenClock = dwNow;
dwSeconds++;
// Speed up alien advance every 10 seconds to max speed of 8 pixels per frame.
if (dwSeconds > 10 && dwSeconds % 10 == 0)
if (alien_yinc < 8) alien_yinc++;
}
// Check for torpedoes going off screen at the top.
for (i = 0; i < num_torpedoes; i++)
{
torpedoes[i].top -= 12;
torpedoes[i].bottom -= 12;
if (torpedoes[i].top <= 0) RemoveTorpedo(i);
}
// Advance aliens and check for collision with user's ship.
for (i = 0; i < num_aliens; i++)
{
if (IntersectRect(&rect, &shiprect, &aliens[i]))
{
DestroyShip();
RemoveAlien(i);
}
// Check for aliens going off screen at the bottom.
if (aliens[i].top > 400) RemoveAlien(i);
aliens[i].top += alien_yinc;
aliens[i].bottom += alien_yinc;
}
}
else
{
if (++dwInterval1 == 400)
{
dwInterval1 = 0;
}
}
// The star field always moves, except when the game is paused.
if (!bPaused)
{
// Generate new stars when needed.
if (num_stars < MAX_STARS)
{
stars[num_stars].x = rand() / (RAND_MAX / 300);
stars[num_stars++].y = 0;
}
// Remove stars at the bottom, and advance all others.
for (i = 0; i < num_stars; i++)
{
if (stars[i].y > 398) RemoveStar(i);
stars[i].y += 2;
}
// Call for a repaint if not paused.
InvalidateRect(hWnd, NULL, TRUE);
}
break;
case WM_PAINT:
hDC = BeginPaint(hWnd, &ps);
// The starfield is always plotted first. When doing animations, you must
// establish the scene from background to foreground. The order that things
// are drawn is of paramount importance in creating a realistic depth of field.
// The axis that is defined from the background to the foreground is the z-axis
// in 3D parlance, and establishes this depth of field.
for (i = 0; i < num_stars; i++)
SetPixel(hDC, stars[i].x, stars[i].y, RGB(255, 255, 255));
SetBkMode(hDC, TRANSPARENT);
// A memory DC is useful in plotting multiple bitmaps onto the rendering device.
hMemoryDC = CreateCompatibleDC(hDC);
if (bPlaying)
hOldBitmap = SelectObject(hMemoryDC, hShipBitMap);
else hOldBitmap = SelectObject(hMemoryDC, hTitle1BitMap);
if (hOldBitmap)
{
if (num_ships > 0)
BitBlt(hDC, shiprect.left, shiprect.top,
shiprect.right - shiprect.left,
shiprect.bottom - shiprect.top,
hMemoryDC, 0, 0, SRCCOPY);
else BitBlt(hDC, 70, 30, 148, 38, hMemoryDC, 0, 0, SRCCOPY);
for (i = 0; i < num_aliens; i++)
{
SelectObject(hMemoryDC, hDrawBitMap);
BitBlt(hDC, aliens[i].left, aliens[i].top,
aliens[i].right - aliens[i].left,
aliens[i].bottom - aliens[i].top,
hMemoryDC, 0, 0, SRCCOPY);
}
SelectObject(hMemoryDC, hOldBitmap);
}
DeleteDC(hMemoryDC);
hOldBrush = SelectObject(hDC, hRedBrush);
if (!bGameOver)
{
for (i = 0; i < num_torpedoes; i++)
{
Rectangle(hDC, torpedoes[i].left, torpedoes[i].top,
torpedoes[i].right, torpedoes[i].bottom);
for (j = 0; j < num_aliens; j++)
{
if (IntersectRect(&rect, &torpedoes[i], &aliens[j]))
{
RemoveAlien(j);
RemoveTorpedo(i);
score += 100;
if (score % 2000 == 0 && score < 20000)
{
alien_yinc = 5;
level++;
num_ships++;
if (max_aliens_level < MAX_ALIEN)
max_aliens_level++;
}
num_hits++;
if (score % 10000 == 0) num_ships++;
}
}
}
}
else
{
SetTextColor(hDC, RGB(255, 255, 255));
sprintf(szstatus, "GAME OVER");
dwTemp = GetTextExtent(hDC, szstatus, strlen(szstatus));
GetWindowRect(hWnd, &rect);
width = rect.right - rect.left;
height = rect.bottom - rect.top;
TextOut(hDC, (width - LOWORD(dwTemp)) >> 1,
(height - HIWORD(dwTemp)) >> 1, szstatus,
strlen(szstatus));
bPlaying = FALSE;
dwInterval1 = 0;
idle = 0;
}
SetTextColor(hDC, RGB(0, 0, 255));
sprintf(szstatus, "ACC : %3.2f Ships : %02i SCORE: %06li",
total_fired != 0 ?
((num_hits / total_fired) * 100.0) : 0.0,
num_ships, score);
TextOut(hDC, 40, 330, szstatus, strlen(szstatus));
SelectObject(hDC, hOldBrush);
EndPaint(hWnd, &ps);
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_RIGHT:
if (bPlaying && !bPaused)
{
shiprect.left += 8;
if (shiprect.left > 260) shiprect.left = 260;
shiprect.right = shiprect.left + 32;
InvalidateRect(hWnd, NULL, TRUE);
}
break;
case VK_LEFT:
if (bPlaying && !bPaused)
{
shiprect.left -= 8;
if (shiprect.left < 0) shiprect.left = 0;
shiprect.right = shiprect.left + 32;
InvalidateRect(hWnd, NULL, TRUE);
}
break;
case VK_SPACE:
if (bPlaying && num_torpedoes + 2 < MAX_TORPEDO &&
!bPaused)
{
torpedoes[num_torpedoes].top = shiprect.top + 10;
torpedoes[num_torpedoes].left = shiprect.left + 4;
torpedoes[num_torpedoes + 1].top = shiprect.top + 10;
torpedoes[num_torpedoes + 1].left = shiprect.right - 8;
torpedoes[num_torpedoes].bottom =
torpedoes[num_torpedoes].top + 8;
torpedoes[num_torpedoes].right =
torpedoes[num_torpedoes].left + 4;
num_torpedoes++;
torpedoes[num_torpedoes].bottom =
torpedoes[num_torpedoes].top + 8;
torpedoes[num_torpedoes].right =
torpedoes[num_torpedoes].left + 4;
num_torpedoes++;
total_fired += 2;
}
break;
case VK_F1:
if (bPlaying) bPaused = !bPaused;
break;
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_COMMAND:
switch (wParam)
{
case IDM_ABOUT:
lpProcAbout = MakeProcInstance(About, hInst);
DialogBox(hInst, "AboutBox", hWnd, lpProcAbout);
FreeProcInstance(lpProcAbout);
break;
case IDM_START:
StartGame();
break;
case IDM_EXIT:
PostMessage(hWnd, WM_DESTROY, NULL, NULL);
break;
//
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_SYSCOMMAND:
switch (wParam & 0x0fff) // Disallow resizing the window.
{
case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8:
break;
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_DESTROY:
KillTimer(hWnd, idTimer1);
DeleteObject(hRedBrush);
DeleteObject(hAlien1BitMap);
DeleteObject(hAnt1BitMap);
DeleteObject(hBee1BitMap);
DeleteObject(hSpider1BitMap);
DeleteObject(hScorp1BitMap);
DeleteObject(hGator1BitMap);
DeleteObject(hShipBitMap);
DeleteObject(hCat1BitMap);
DeleteObject(hTitle1BitMap);
PostQuitMessage(0);
break;
case WM_INITMENUPOPUP:
if (wParam == hSysMenu)
{
RemoveMenu(wParam, SC_RESTORE, MF_BYCOMMAND);
RemoveMenu(wParam, SC_MOVE, MF_BYCOMMAND);
RemoveMenu(wParam, SC_SIZE, MF_BYCOMMAND);
RemoveMenu(wParam, SC_MAXIMIZE, MF_BYCOMMAND);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
default: return DefWindowProc(hWnd, message, wParam, lParam);
}
return NULL;
}
BOOL FAR PASCAL About(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (wParam == IDOK || wParam == IDCANCEL)
{
EndDialog(hDlg, TRUE);
return TRUE;
}
break;
default:
break;
}
return FALSE;
}
void StartGame(void)
{
num_torpedoes = num_aliens = 0;
total_fired = num_hits = 0;
shiprect.top = 290;
shiprect.left = 136;
shiprect.right = shiprect.left + 32;
shiprect.bottom = shiprect.top + 32;
max_aliens_level = 4;
alien_xinc = 0;
alien_yinc = 4;
level = 0;
num_ships = 5;
score = 0;
kills = 0;
dwStartGenClock = GetTickCount();
dwSeconds = 0;
bPlaying = TRUE;
bGameOver = bPaused= FALSE;
}
int RemoveTorpedo(int torpedo_number)
{
int i, j;
for (i = torpedo_number, j = torpedo_number + 1; i < num_torpedoes;)
torpedoes[i++] = torpedoes[j++];
num_torpedoes--;
return torpedo_number > 0 ? torpedo_number - 1 : 0;
}
int RemoveAlien(int alien_number)
{
int i, j, k = num_aliens--;
for (i = alien_number, j = alien_number + 1; i < k;)
aliens[i++] = aliens[j++];
return alien_number > 0 ? alien_number - 1 : 0;
}
int RemoveStar(int star_number)
{
int i, j, k = num_stars--;
for (i = star_number, j = star_number + 1; j < k;)
stars[i++] = stars[j++];
return star_number > 0 ? star_number - 1 : 0;
}
BOOL GenerateAlien(int alien_number)
{
if (score < 2000) hDrawBitMap = hAnt1BitMap;
else if (score < 4000) hDrawBitMap = hBee1BitMap;
else if (score < 6000) hDrawBitMap = hSpider1BitMap;
else if (score < 8000) hDrawBitMap = hScorp1BitMap;
else if (score < 10000) hDrawBitMap = hCat1BitMap;
else if (score < 12000) hDrawBitMap = hGator1BitMap;
else hDrawBitMap = hAlien1BitMap;
if (num_aliens < max_aliens_level)
{
aliens[alien_number].bottom = 0;
aliens[alien_number].top = aliens[alien_number].bottom - 32;
aliens[alien_number].left = rand() / (RAND_MAX / (300 - 32));
aliens[alien_number].right = aliens[alien_number].left + 32;
num_aliens++;
return TRUE;
}
return FALSE;
}
void DestroyShip(void)
{
if (--num_ships > 0)
{
shiprect.top = 290;
shiprect.left = 136;
shiprect.right = shiprect.left + 32;
shiprect.bottom = shiprect.top + 32;
}
else bGameOver = TRUE;
}
You do not have the bitmap files, but...use 24-bit BMP files; they will work. If you have an option of saving as .DIB, I'd recommend that you use that, and rename the file to use the extension .BMP If you do not have that option, just use 24-bit BMP, and it will work the same.
Somewhere, I think I have an executable of this with animated sprites. For now, just look at how the .C file works. You need to pay particular attention to the LoadBitmap function, and also study how I blit the bitmap to the display in the WM_PAINT message.
This is basically how GDK does it....or, so I think. GDK probably draws the 3D surface, then uses a similar approach to blit the 2D stuff, which is probably why 2D slows down 3D to various extents, depending on how you write your game loop.
If I find the executable, I'll post it up.
Oh, and you will add the .rc file and the resource.h files in Solution Explorer. I can show you how.