Snake/PlayingProc.c

460 lines
10 KiB
C

#include "PlayingProc.h"
#include "GameWndProc.h"
#include "map_data.h"
//////////////////////////////////////////////////////////////////////////
void testImpace( HWND hwnd );
void testFoodPlace( HWND hwnd );
static GM_STATUS APP = {
TEXT("贪吃蛇"),
0,
{ {20, 20} },
{-10, -10},
DR_RIGHT,
5,
0
};
//////////////////////////////////////////////////////////////////////////
LRESULT PlayingProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
POINT pt = {0};
switch( message )
{
case WM_TIMER:
switch( wParam )
{
case TMR_PLAYING_READY:
srand( (unsigned int)time(0) );
SetTimer( hwnd, TMR_PLAYING_READY, 1000*60, NULL ); //调整定时器为60秒
PlaySound( MAKEINTRESOURCE( IDR_READY ), (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ), SND_RESOURCE | SND_ASYNC );
KillTimer( hwnd, TMR_PLAYING_READY );
SetTimer( hwnd, TMR_PLAYING_GO, 1500, NULL ); //启动游戏启动定时器
GetRandomFoodPlace( hwnd, &APP.food );
break;
case TMR_PLAYING_GO:
KillTimer( hwnd, TMR_PLAYING_GO );
PlaySound( MAKEINTRESOURCE( IDR_GO ), (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ), SND_RESOURCE | SND_ASYNC );
//游戏开始
PostMessage( hwnd, CM_START_GAME, 0, 0 );
SetTimer( hwnd, TMR_START_MOVE, 200, 0 );
break;
}
return 0;
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
InitPlayingMap( hwnd, hdc, APP.food, gm_map, APP.level );
EndPaint( hwnd, &ps );
return 0;
case CM_START_GAME:
SetWindowLong( hwnd, GWL_WNDPROC, (long)StartPlaying );
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, message, wParam, lParam );
}
//////////////////////////////////////////////////////////////////////////
void getWallLineRect( int, RECT *, RECT *, int ); //获取地图障碍物i在窗口中的实际位置
BOOL borderImpace( RECT, POINT, int ); //边缘碰撞检测
//点障碍物的碰撞检测
BOOL PointImpaceTest( HWND hwnd, POINT pt, int exc )
{
int i = 0;
RECT rect = {0};
RECT line = {0};
GetClientRect( hwnd, &rect );
if( borderImpace(rect, pt, exc) ) //边缘碰撞
return TRUE;
for( i = 0; i < 5; i++ )
{
getWallLineRect( i, &rect, &line, exc );
if( line.right - line.left == 0 ) //垂直障碍物
if( pt.x >= line.left - exc && pt.x < line.left + 10 + exc && \
pt.y >= line.top - exc && pt.y < line.bottom + exc )
return TRUE;
if( line.bottom - line.top == 0 ) //水平障碍物
if( pt.x >= line.left - exc && pt.x < line.right + exc && \
pt.y >= line.top - exc && pt.y < line.top + 10 + exc )
return TRUE;
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//获取地图障碍物i在窗口中的实际位置
void getWallLineRect( int i, RECT *rect, RECT *line, int exc )
{
//获取地图数据在窗口中的映射位置
line->left = (int)(gm_map[APP.level].line[i].x1 * rect->right); //x1
line->top = (int)(gm_map[APP.level].line[i].y1 * rect->bottom); //y1
line->right = (int)(gm_map[APP.level].line[i].x2 * rect->right); //x2
line->bottom = (int)(gm_map[APP.level].line[i].y2 * rect->bottom); //y2
//添加偏移坐标
if( line->left )
{
line->left += (10 - line->left % 10);
line->top += (10 - line->top % 10);
line->right += (10 - line->right % 10);
line->bottom += (10 - line->bottom % 10);
}
}
//////////////////////////////////////////////////////////////////////////
//边缘碰撞检测
BOOL borderImpace( RECT rect, POINT pt, int exc )
{
if( pt.x > rect.right-20-exc || pt.x < rect.left+10 )
return TRUE;
if( pt.y > rect.bottom-20-exc || pt.y < rect.top+10 )
return TRUE;
return FALSE;
}
//////////////////////////////////////////////////////////////////////////
//生成随机食物坐标
void GetRandomFoodPlace( HWND hwnd, POINT *ptFood )
{
int i = 0, x = 0, y = 0;
RECT rect = {0}, line = {0};
POINT pt = {0};
ptFood->x = ptFood->y = 0;
GetClientRect( hwnd, &rect );
while( PointImpaceTest( hwnd, *ptFood, 10 ) )
{
x = rand()%rect.right; y = rand()%rect.bottom;
ptFood->x = x - x%10; ptFood->y = y - y%10;
}
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int dealKeywordMsg( HWND hwnd, WPARAM ); //处理键盘消息
void moveSnake( ); //移动蛇身
void eraseNode( HWND, POINT ); //擦除一个蛇身节点
void drawSnakeBody( HWND ); //绘制蛇身
BOOL testEating( HWND ); //检测食物是否被吃掉
void updateGameInfo( HWND ); //更新游戏标题栏信息
void resetGameStatus(); //重置游戏状态
void nextLevel( HWND ); //下一关
BOOL testEatSelf( HWND ); //测试是否吃到自己
void gameOver( HWND ); //游戏结束
void gameAgain( HWND ); //再来一局
void startSnakeMove( HWND ); //蛇开始移动(封装移动方法)
//////////////////////////////////////////////////////////////////////////
//开始游戏
LRESULT CALLBACK StartPlaying( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
HDC hdc;
PAINTSTRUCT ps;
switch( message )
{
case WM_PAINT:
hdc = BeginPaint( hwnd, &ps );
InitPlayingMap( hwnd, hdc, APP.food, gm_map, APP.level );
EndPaint( hwnd, &ps );
return 0;
case WM_TIMER:
switch( wParam )
{
case TMR_START_MOVE:
startSnakeMove( hwnd );
break;
}
return 0;
case CM_GAME_OVER:
gameOver( hwnd );
break;
case CM_GAME_NEXT:
nextLevel( hwnd );
break;
case CM_GAME_SUCCEED:
MessageBox( NULL, "ok", "", 0 );
break;
case WM_KEYDOWN:
dealKeywordMsg( hwnd, wParam );
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc( hwnd, message, wParam, lParam );
}
//////////////////////////////////////////////////////////////////////////
//处理键盘消息
int dealKeywordMsg( HWND hwnd, WPARAM wParam )
{
switch( wParam )
{
case VK_UP:
case 'W':
if(APP.direction != DR_DOWN) APP.direction = DR_UP; break;
case VK_DOWN:
case 'S':
if(APP.direction != DR_UP) APP.direction = DR_DOWN; break;
case VK_LEFT:
case 'A':
if(APP.direction != DR_RIGHT) APP.direction = DR_LEFT; break;
case VK_RIGHT:
case 'D':
if(APP.direction != DR_LEFT) APP.direction = DR_RIGHT; break;
case VK_CONTROL:
PostMessage( hwnd, WM_TIMER, TMR_START_MOVE, 0 );
break;
case VK_ESCAPE:
if ( MessageBox( NULL, TEXT("游戏正在运行, 确定退出吗?"), \
TEXT("确认"), MB_OKCANCEL | MB_ICONQUESTION ) == IDOK )
PostQuitMessage(0);
break;
}
return 0;
}
//移动蛇身
void moveSnake( )
{
int i = APP.len;
for( i; i > 0; i-- )
APP.body[i] = APP.body[i-1];
switch( APP.direction )
{
case DR_UP:
APP.body[0].y -= 10; break;
case DR_DOWN:
APP.body[0].y += 10; break;
case DR_LEFT:
APP.body[0].x -= 10; break;
case DR_RIGHT:
APP.body[0].x += 10; break;
}
}
//擦除蛇身的一个节点
void eraseNode( HWND hwnd, POINT ptNode )
{
HDC hdc;
HPEN hPen;
HBRUSH hBrush;
hdc = GetDC( hwnd );
hPen = CreatePen( PS_SOLID, 3, RGB(0, 0, 0) );
hBrush = CreateSolidBrush( RGB(0, 0, 0) );
SelectObject( hdc, hPen );
SelectObject( hdc, hBrush );
Rectangle( hdc, ptNode.x, ptNode.y, ptNode.x+10, ptNode.y+10 );
DeleteObject( hBrush );
ReleaseDC( hwnd, hdc );
}
//绘制蛇身
void drawSnakeBody( HWND hwnd )
{
int i = 0;
HDC hdc;
HPEN hPen;
HBRUSH hBrush;
hdc = GetDC( hwnd );
hPen = CreatePen( PS_SOLID, 3, RGB(0, 128, 0) );
hBrush = CreateSolidBrush( RGB(0, 255, 0) );
SelectObject( hdc, hPen );
SelectObject( hdc, hBrush );
for( i; i <= APP.len; i++ )
RoundRect( hdc, APP.body[i].x, APP.body[i].y, APP.body[i].x+10, APP.body[i].y+10, 3, 3 );
eraseNode( hwnd, APP.body[APP.len] );
DeleteObject( hPen );
DeleteObject( hBrush );
ReleaseDC( hwnd, hdc );
}
//检测食物是否被吃掉
BOOL testEating( HWND hwnd )
{
if( APP.food.x == APP.body[0].x && APP.food.y == APP.body[0].y )
{
PlaySound( MAKEINTRESOURCE( IDR_EATING ), (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ), SND_RESOURCE | SND_ASYNC );
APP.len += 2;
APP.score += 10;
if( (APP.level == APP.score / 100-1) && (APP.level < 9) )
{
APP.level++;
PostMessage( hwnd, CM_GAME_NEXT, 0, 0 );
}
GetRandomFoodPlace( hwnd, &APP.food );
return TRUE;
}
return FALSE;
}
//更新游戏信息
void updateGameInfo( HWND hwnd )
{
if( APP.score < 1000 )
wsprintf( APP.szGameTitle, "贪吃蛇 第 %d 关 得分: %d 进度: %d/10",
APP.level + 1, APP.score, APP.score/10%10 );
else //第十关以后的无尽模式统计方案
wsprintf( APP.szGameTitle, "贪吃蛇 第 %d 关 得分: %d 进度: %d/10",
APP.level + 1, APP.score, (APP.score-1000)/10 );
SetWindowText( hwnd, APP.szGameTitle );
}
//重置游戏状态
void resetGameStatus()
{
int i = APP.len;
APP.direction = DR_RIGHT;
APP.body[0].x = 10; APP.body[0].y = 20;
APP.food.x = -10; APP.food.y = -10;
for( i; i > 0; i-- )
{
APP.body[i].x = APP.body[0].x;
APP.body[i].y = APP.body[0].y;
}
}
//下一关
void nextLevel( HWND hwnd )
{
PlaySound( MAKEINTRESOURCE( IDR_NEXT ), (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ), SND_RESOURCE | SND_ASYNC );
resetGameStatus();
InvalidateRect( hwnd, NULL, TRUE );
}
//测试是否吃到自己
BOOL testEatSelf( HWND hwnd )
{
int i = APP.len;
for( i; i > 0; i-- )
if( APP.body[0].x == APP.body[i].x && APP.body[0].y == APP.body[i].y )
{
PostMessage( hwnd, CM_GAME_OVER, 0, 0 );
return TRUE;
}
return FALSE;
}
//游戏结束
void gameOver( HWND hwnd )
{
int menuID = 0;
KillTimer( hwnd, TMR_START_MOVE );
PlaySound( MAKEINTRESOURCE( IDR_GAME_OVER ), (HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ), SND_RESOURCE );
InvalidateRect( hwnd, NULL, TRUE );
menuID = DialogBox(
(HINSTANCE)GetWindowLong( hwnd, GWL_HINSTANCE ),
MAKEINTRESOURCE(IDD_GAMEOVER_DLG),
hwnd, GameOverProc
);
switch( menuID )
{
case GAME_AGAIN:
gameAgain( hwnd );
break;
case GAME_MAIN:
SetWindowLong( hwnd, GWL_WNDPROC, (long)DealBeginMenuMsg );
PostMessage( hwnd, CM_GAME_READY, 0, 0 );
resetGameStatus();
APP.level = 0; APP.score = 0;
InvalidateRect( hwnd, NULL, TRUE );
SetWindowText( hwnd, TEXT("贪吃蛇") );
return ;
case GAME_EXIT:
PostMessage( hwnd, WM_DESTROY, 0, 0 );
return ;
}
}
//再来一局
void gameAgain( HWND hwnd )
{
resetGameStatus();
APP.level = 0;
APP.score = 0;
SetWindowLong( hwnd, GWL_WNDPROC, (long)PlayingProc );
PostMessage( hwnd, WM_TIMER, TMR_PLAYING_READY, 0 );
InvalidateRect( hwnd, NULL, TRUE );
}
//////////////////////////////////////////////////////////////////////////
//蛇开始移动 (封装移动方法)
void startSnakeMove( HWND hwnd )
{
if( PointImpaceTest(hwnd, APP.body[0], 0) )
{
PostMessage( hwnd, CM_GAME_OVER, 0, 0 );
return ;
}
testEating( hwnd );
drawSnakeBody( hwnd );
moveSnake( );
testEatSelf( hwnd );
updateGameInfo( hwnd );
InvalidateRect( hwnd, NULL, FALSE );
}