回 帖 发 新 帖 刷新版面

主题:贪吃蛇源码-使用 DirectDraw, DirectInput, 带声音

//主程序  TheSnake.cpp
#include <windows.h>
#include <mmsystem.h>
#include <ddraw.h>
#include <dinput.h>
#include <stdio.h>

#include "ddutil.h"
#include "bass.h"
#include "resource.h"

#define szApp "The Snake"

#define SNAKE_X 8
#define SNAKE_Y 8

#define RES_X 24
#define RES_Y 16

#define MSG_X 300
#define MSG_Y 200

#define GAME_X 78
#define GAME_Y 56

#define DRAW_SPLASH 0
#define DRAW_GAME 1
#define DRAW_GAMEOVER 2
#define DRAW_PAUSE 3

#define TYPE_COMMON 0
#define TYPE_SUPER 1

#define KEYDOWN(name, key) (name[key] & 0x80)

void UpdateFrame(void);
void ProcessGame(void);
void RebuildSurfaces(void);

void WINAPI GetInput(void);

char buffer[256];
DWORD dwWait;
HWND hWnd;

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);

struct HIGHSCORES
{
int initial;
int adapt;
int master;
};

HIGHSCORES hs;

class CSnake
{
public:
POINT ptSnake[4400];    // Position for the snake
POINT ptPeas[3];    // Position for the peas
int typePeas[3];    // Decide the type of the peas
int nCur;    // The current length of the snake
int nScore;    // The score of the snake
int nHigh;    // High Score
DWORD dwDir;    // The direction of the snake
void FlushSnake(void);
void AddLength(int nLen = 1);
void GeneratePea(int nIndex);
void MoveSnake(void);
};

void CSnake::FlushSnake(void)
{
int nIndex;
for(nIndex = 0; nIndex < 4400; nIndex++)
{
ptSnake[nIndex].x = 0;
ptSnake[nIndex].y = 0;
}
nCur = 10;
for(nIndex = 0; nIndex < 10; nIndex++)
{
ptSnake[nIndex].x = 10 - nIndex;
ptSnake[nIndex].y = 28;
}
nScore = 0;
for(nIndex = 0; nIndex < 3; nIndex++)
GeneratePea(nIndex);
dwDir = VK_RIGHT;
}

void CSnake::AddLength(int nLen)
{
int nIndex;
for(nIndex = 0; nIndex < nLen; nIndex++)
{
ptSnake[nIndex + nCur].x = ptSnake[0].x;
ptSnake[nIndex + nCur].y = ptSnake[0].y;
}
nCur += nLen;
}

void CSnake::GeneratePea(int nIndex)
{
srand(timeGetTime());
typePeas[nIndex] = rand() % 2;
ptPeas[nIndex].x = (rand () % GAME_X) + 1;
ptPeas[nIndex].y = (rand () % GAME_Y) + 3;
}

void CSnake::MoveSnake(void)
{
int nIndex;
for(nIndex = nCur; nIndex > 0; nIndex--)
{
ptSnake[nIndex].x = ptSnake[nIndex - 1].x;
ptSnake[nIndex].y = ptSnake[nIndex - 1].y;
}
switch(dwDir)
{
case VK_UP:
if(ptSnake[0].y == 3)
ptSnake[0].y = 58;
else
ptSnake[0].y--;
break;
case VK_DOWN:
if(ptSnake[0].y == 58)
ptSnake[0].y = 3;
else
ptSnake[0].y++;
break;
case VK_LEFT:
if(ptSnake[0].x == 1)
ptSnake[0].x = 78;
else
ptSnake[0].x--;
break;
case VK_RIGHT:
if(ptSnake[0].x == 78)
ptSnake[0].x = 1;
else
ptSnake[0].x++;
break;
}
}

HINSTANCE hInst;
DWORD dwDraw;
CSnake snake;
CDisplay *pDisplay = NULL;
CSurface *pRes = NULL;
CSurface *pMsg = NULL;
CSurface *pText = NULL;
CSurface *pBack = NULL;

LPDIRECTINPUT8 lpDI;
LPDIRECTINPUTDEVICE8 lpDIDevice;

HSTREAM hAte;
HSTREAM hDie;
HSTREAM hStart;

FILE *fp;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
MSG msg;
HWND hwnd;
WNDCLASSEX wndclass;

hInst = hInstance;

wndclass.cbClsExtra = 0;
wndclass.cbSize = sizeof(wndclass);
wndclass.cbWndExtra = 0;
wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclass.hCursor = NULL;
wndclass.hIcon = LoadIcon(hInst, (LPCSTR)IDI_ICON1);
wndclass.hIconSm = wndclass.hIcon;
wndclass.hInstance = hInst;
wndclass.lpfnWndProc = WndProc;
wndclass.lpszClassName = szApp;
wndclass.lpszMenuName = NULL;
wndclass.style = CS_HREDRAW | CS_VREDRAW;

RegisterClassEx(&wndclass);

hwnd = CreateWindowEx(WS_EX_APPWINDOW, szApp, szApp, WS_POPUP | WS_VISIBLE, 0, 0, 0, 0, 0, 0, hInst, 0);

hWnd = hwnd;

ShowWindow(hwnd, SW_NORMAL);
UpdateWindow(hwnd);

BASS_Init(-1, 44100, 32, 0);
BASS_Start();

hAte = BASS_StreamCreateFile(FALSE, "Ate.wav", 0, 0, 0);
hDie = BASS_StreamCreateFile(FALSE, "Die.wav", 0, 0, 0);
hStart = BASS_StreamCreateFile(FALSE, "Start.wav", 0, 0, 0);

//BASS_MusicPlay(hMusic);

// Initializes the DirectDraw
pDisplay = new CDisplay();
pDisplay->CreateFullScreenDisplay(hwnd, 640, 480, 16);
pDisplay->CreateSurfaceFromBitmap(&pRes, "thesnake.bmp", RES_X, RES_Y);
pDisplay->CreateSurfaceFromBitmap(&pMsg, "gameover.bmp", MSG_X, MSG_Y);
pDisplay->CreateSurface(&pText, 640, SNAKE_Y * 2);
pText->DrawText(NULL, "Score: 0", 0, 0, RGB(0, 0, 0), RGB(255, 255, 0));
pRes->SetColorKey(0);

pDisplay->CreateSurfaceFromBitmap(&pBack, "Back.bmp", 640, 480);

// Initializes the DirectInput
DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&lpDI, NULL);
lpDI->CreateDevice(GUID_SysKeyboard, &lpDIDevice, NULL);
lpDIDevice->SetDataFormat(&c_dfDIKeyboard);
lpDIDevice->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
lpDIDevice->Acquire();

// Access the high scores
fp = fopen("C:\\TheSnake.hss", "rb");
if(fp == NULL)
{
hs.adapt = 0;
hs.initial = 0;
hs.master = 0;
}
else
{
fseek(fp, 0, SEEK_SET);
fread(&hs, sizeof(hs), 1, fp);
fclose(fp);
}

snake.FlushSnake();

dwDraw = DRAW_SPLASH;

while(1)
{
if(PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))
{
if(!GetMessage(&msg, 0, 0, 0))
return 0;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
GetInput();
ProcessGame();
}
}

return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch(iMsg)
{
case WM_CREATE:
SetCursor(NULL);
break;
case WM_KEYDOWN:
switch(wParam)
{
case VK_ESCAPE:
SendMessage(hwnd, WM_CLOSE, 0, 0);
break;
default:
break;
}
break;
case WM_CLOSE:
BASS_Stop();
BASS_StreamFree(hAte);
BASS_StreamFree(hDie);
BASS_StreamFree(hStart);
BASS_Free();
// Free DirectInput
lpDIDevice->Unacquire();
lpDIDevice->Release();
lpDI->Release();
// Saves the high scores
switch(dwWait)
{
case 20:
hs.initial = snake.nHigh;
break;
case 10:
hs.adapt = snake.nHigh;
break;
case 5:
hs.master = snake.nHigh;
break;
}
fp = fopen("C:\\TheSnake.hss", "wb");
if(fp != NULL)
{
fwrite(&hs, sizeof(hs), 1, fp);
fclose(fp);
}
PostQuitMessage(0);
break;
default:
break;
}
return DefWindowProc(hwnd, iMsg, wParam, lParam);
}

void RebuildSurfaces(void)
{
char szMsg[260];
pRes->DrawBitmap("thesnake.bmp", RES_X, RES_Y);
pMsg->DrawBitmap("gameover.bmp", MSG_X, MSG_Y);
wsprintf(szMsg, "Score: %d", snake.nScore);
pText->DrawText(NULL, "                                        ", 0, 0, RGB(0, 0, 0), RGB(255, 255, 0));
pText->DrawText(NULL, szMsg, 0, 0, RGB(0, 0, 0), RGB(255, 255, 0));
}

void UpdateFrame(void)
{
RECT rc;
HBITMAP hBmp;
int nIndex;

if(dwDraw == DRAW_SPLASH)
{
hBmp = (HBITMAP)LoadImage(NULL, "Splash.bmp", IMAGE_BITMAP, 640, 480, LR_LOADFROMFILE);
pDisplay->ShowBitmap(hBmp);
DeleteObject(hBmp);
return;
}

if(dwDraw == DRAW_GAME)
{
pDisplay->Clear();

// Blts the back
pDisplay->Blt(0, 0, pBack);
// Draw the wall
SetRect(&rc, 2 * SNAKE_X, 0, 3 * SNAKE_X, SNAKE_Y);
for(nIndex = 0; nIndex < 80; nIndex++)
{
pDisplay->Blt(nIndex * SNAKE_X, 2 * SNAKE_Y, pRes, &rc);
pDisplay->Blt(nIndex * SNAKE_X, 59 * SNAKE_Y, pRes, &rc);
}
for(nIndex = 3; nIndex < 60; nIndex++)
{
pDisplay->Blt(0, nIndex * SNAKE_Y, pRes, &rc);
pDisplay->Blt(79 * SNAKE_Y, nIndex * SNAKE_Y, pRes, &rc);
}
// Draw the peas
for(nIndex = 0; nIndex < 3; nIndex++)
{
SetRect(&rc, snake.typePeas[nIndex] * SNAKE_X, SNAKE_Y, (snake.typePeas[nIndex] + 1) * SNAKE_X, SNAKE_Y * 2);
pDisplay->Blt(snake.ptPeas[nIndex].x * SNAKE_X, snake.ptPeas[nIndex].y * SNAKE_Y, pRes, &rc);
}
// Draw the snake
SetRect(&rc, SNAKE_X, 0, SNAKE_X * 2, SNAKE_Y);
for(nIndex = 1; nIndex < snake.nCur; nIndex++)
{
pDisplay->Blt(snake.ptSnake[nIndex].x * SNAKE_X, snake.ptSnake[nIndex].y * SNAKE_Y, pRes, &rc);
}
SetRect(&rc, 0, 0, SNAKE_X, SNAKE_Y);
pDisplay->Blt(snake.ptSnake[0].x * SNAKE_X, snake.ptSnake[0].y * SNAKE_Y, pRes, &rc);
// Draw the text
pDisplay->Blt(0, 0, pText);
// Show the screen
if(FAILED(pDisplay->Present()))
RebuildSurfaces();
Sleep(dwWait);
return;
}

if(dwDraw == DRAW_PAUSE)
{
pMsg->DrawBitmap("pause.bmp", MSG_X, MSG_Y);
pDisplay->Blt((640 - MSG_X) / 2, (480 - MSG_Y) / 2, pMsg);
pDisplay->Present();
}

if(dwDraw == DRAW_GAMEOVER)
{
pMsg->DrawBitmap("gameover.bmp", MSG_X, MSG_Y);
pDisplay->Blt((640 - MSG_X) / 2, (480 - MSG_Y) / 2, pMsg);
pDisplay->Present();
}

}

void ProcessGame(void)
{
int nIndex;
char szMsg[260];

if(dwDraw == DRAW_GAME)
{
// Check for inputs and decides it.
if(KEYDOWN(buffer, DIK_LEFT))
{
if(snake.dwDir != VK_RIGHT)
snake.dwDir = VK_LEFT;
}
if(KEYDOWN(buffer, DIK_RIGHT))
{
if(snake.dwDir != VK_LEFT)
snake.dwDir = VK_RIGHT;
}
if(KEYDOWN(buffer, DIK_UP))
{
if(snake.dwDir != VK_DOWN)
snake.dwDir = VK_UP;
}
if(KEYDOWN(buffer, DIK_DOWN))
{
if(snake.dwDir != VK_UP)
snake.dwDir = VK_DOWN;
}
if(KEYDOWN(buffer, DIK_P))
{
dwDraw = DRAW_PAUSE;
UpdateFrame();
return;
}

snake.MoveSnake();    // Move the snake for 1 step
// Decide if the snake ate itself
for(nIndex = 1; nIndex < snake.nCur; nIndex++)
{
if(snake.ptSnake[0].x == snake.ptSnake[nIndex].x && snake.ptSnake[0].y == snake.ptSnake[nIndex].y)
{
dwDraw = DRAW_GAMEOVER;
BASS_StreamPlay(hDie, 0, 0);
UpdateFrame();
return;
}
}
// Decide if the snake ate objects
for(nIndex = 0; nIndex < 3; nIndex++)
{
if(snake.ptSnake[0].x == snake.ptPeas[nIndex].x && snake.ptSnake[0].y == snake.ptPeas[nIndex].y)
{
switch(snake.typePeas[nIndex])
{
case TYPE_COMMON:
snake.AddLength();
snake.nScore += 5;
break;
case TYPE_SUPER:
srand(timeGetTime());
snake.AddLength(rand() % 10);
snake.nScore += 20;
break;
}
if(snake.nScore > snake.nHigh)
snake.nHigh = snake.nScore;
snake.GeneratePea(nIndex);
BASS_StreamPlay(hAte, 0, 0);
}
}
// Now, build the score text
pText->DrawBitmap("BLACK.BMP", 640, SNAKE_Y * 2);
wsprintf(szMsg, "Score: %d", snake.nScore);
pText->DrawText(NULL, szMsg, 0, 0, RGB(0, 0, 0), RGB(255, 255, 0));
switch(dwWait)
{
case 20:
pText->DrawText(NULL, "Skill Level: Initial", 200, 0, RGB(0, 0, 0), RGB(0, 255, 0));
break;
case 10:
pText->DrawText(NULL, "Skill Level: Adapt", 200, 0, RGB(0, 0, 0), RGB(255, 255,0));
break;
case 5:
pText->DrawText(NULL, "Skill Level: Master", 200, 0, RGB(0, 0, 0), RGB(255, 153, 0));
break;
}
wsprintf(szMsg, "High Score: %d", snake.nHigh);
pText->DrawText(NULL, szMsg, 400, 0, RGB(0, 0, 0), RGB(0, 153, 255));
// Draw the frames
UpdateFrame();
UpdateFrame();
}

if(dwDraw == DRAW_SPLASH)
{
if(KEYDOWN(buffer, DIK_1))
{
dwWait = 20;
dwDraw = DRAW_GAME;
snake.nHigh = hs.initial;
BASS_StreamPlay(hStart, 0, 0);
}
if(KEYDOWN(buffer, DIK_2))
{
dwWait = 10;
dwDraw = DRAW_GAME;
snake.nHigh = hs.adapt;
BASS_StreamPlay(hStart, 0, 0);
}
if(KEYDOWN(buffer, DIK_3))
{
dwWait = 5;
dwDraw = DRAW_GAME;
snake.nHigh = hs.master;
BASS_StreamPlay(hStart, 0, 0);
}

UpdateFrame();
}

if(dwDraw == DRAW_PAUSE)
{
if(KEYDOWN(buffer, DIK_SPACE))
{
dwDraw = DRAW_GAME;
UpdateFrame();
}
}

if(dwDraw == DRAW_GAMEOVER)
{
if(KEYDOWN(buffer, DIK_SPACE))
{
dwDraw = DRAW_GAME;
snake.FlushSnake();
BASS_StreamPlay(hStart, 0, 0);
UpdateFrame();
}
}
}

void WINAPI GetInput(void)
{
HRESULT  hr;

    hr = lpDIDevice->GetDeviceState(sizeof(buffer),(LPVOID)&buffer);
    if FAILED(hr)
    {  
hr = lpDIDevice->Acquire();
while(hr == DIERR_INPUTLOST)
hr = lpDIDevice->Acquire();
    }
}

说明:ddutil.h 是 DX8SDK 里的文件。res.bmp 是包含了蛇、豆、墙的图像的位图文件,back.bmp 是背景图片。gameover.bmp 是游戏结束的图片,pause.bmp 是游戏暂停的图片。start.wav, die.wav, ate.wav 都是游戏中所使用的声音文件。
bass.h bass.lib 是 BASS 声音引擎的相关文件。
该工程需将 dxguid.lib winmm.lib ddraw.lib dinput8.lib bass.lib 加入 Link 选项中。

具体的工程请来信索要。mailto: vrace_studios@hotmail.com
(要耐心一点,我们在封校,很难得上传文件...)

回复列表 (共7个回复)

沙发

我已经给你发信了
希望能得到您的允许.
谢谢

板凳

No problem...

3 楼

好长的代码。。。

4 楼

在给别人看编码的时候能不能注释换成中文的! 好看的懂!!

5 楼

你好,我已经给你发了邮件希望能得到你的指导

6 楼

怎么不把步骤写出来呢?要好难编哦!

7 楼

ddutil.h
  这个文件是干什么的哦??
 我这里面提示找不到该文件

我来回复

您尚未登录,请登录后再回复。点此登录或注册