WinAPI版本的貪食蛇

snake_1snake_2

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/*WinAPI版本的貪食蛇  :

 版本:v1.4

  遊戲流程 : 按方向鍵開始遊戲,按滑鼠左鍵可以暫停遊戲
         碰到邊界或撞到尾巴都會導致遊戲結束,結束時顯示分數
            並可選擇是否結束遊戲
            如果未讀取到B1.bmp,則以灰色畫面進入遊戲 

  實作日期 : 2007.3.18
*/

#include "Snake_Function.cpp"

//程式進入點
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    HWND hwnd;
    MSG Msg;
    char pic[10];
    
    
    //SetBkMode(hMyDC, );

    int wnd_W;
    int wnd_H;
    wnd_W=403;
    wnd_H=300;
        
    //亂入結束

    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance ;
    //wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hIcon = (HICON)LoadImage(NULL,"7.ico",
                IMAGE_ICON,32,32,LR_LOADFROMFILE);
                
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    
    //以下建立背景圖片
    LOGBRUSH background;
    background.lbStyle     = BS_PATTERN;
    background.lbHatch     = (long) LoadImage(hInstance,//實體代碼
                    BACKGROUND_PIC,//圖像名稱
                    IMAGE_BITMAP,//圖像種類
                        0, //期望的寬度
                    0,//期望的高度
                    LR_LOADFROMFILE);//讀取選項);
    //建立結束 
                    
    if (background.lbHatch != 0)
        wc.hbrBackground = CreateBrushIndirect(&background);
    else   //如果同資料夾中沒有名為B1.bmp的背景圖,則以白色背景取代 
        wc.hbrBackground = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
                                        //如果改成NULL_BRUSH,背景就會變透明       

    wc.lpszMenuName  = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = (HICON)LoadImage(NULL, "7.ico",
              IMAGE_ICON, 16, 16,LR_LOADFROMFILE);
    

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "視窗類別登記失敗!", "發生錯誤!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    hwnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        szAppName,
        "歡 迎 來 到 貪 食 蛇 世 界   ! !",
        WS_OVERLAPPEDWINDOW,
        nTopXY(wnd_W, GetSystemMetrics(SM_CXSCREEN)),
        nTopXY(wnd_H, GetSystemMetrics(SM_CYSCREEN)),
        wnd_W,wnd_H,
        NULL, NULL, hInstance, NULL);

    if (hwnd == NULL)
    {
        MessageBox(NULL, "視窗建立失敗!", "發生錯誤!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HDC hMyDC;
    PAINTSTRUCT ps;
    WNDCLASSEX wc;
 
    char Text[] = "文字顯示測試!!";

    int nLen = sizeof(szText)-1;
 
    int i,x,y;
    int SnakeHand = 5*nTick;  //蛇頭移動的設定變數
 
    char gameOverStr[100]; //遊戲結束的文字敘述
 
    HBRUSH hBrush; //變換方格顏色用
 
    nTickX = nTick;

    switch (msg)
    {
      case WM_CREATE:
            SetTimer(hwnd,1,cpuTime,NULL);

      break;
      case WM_TIMER:
            if (bFlag == 0 ){
                nTick ++;
                
                if (point == 0)
                    nTick = 0;
                wsprintf(szTick,"時間:%d",nTick);
                InvalidateRect(hwnd, NULL, TRUE);
                UpdateWindow(hwnd);
            
            }

       break;

       case WM_KEYDOWN: //keydown可以讀取到字鍵和系統鍵
             wsprintf(szTextKey,"按鍵:%s",TEXT("按"));
             wsprintf(szCharKey,"字鍵為:%s",&wParam);
             nowKeyNumber = wParam ; //把捕捉到的值記錄起來
             InvalidateRect(hwnd, NULL, TRUE);
             UpdateWindow(hwnd);
       break;

       case WM_KEYUP:
             wsprintf(szTextKey,"按鍵:%s",TEXT("開"));
             InvalidateRect(hwnd, NULL, TRUE);
             UpdateWindow(hwnd);

       break;
       //end
       case WM_LBUTTONDOWN:
            if (bFlag == 0){
                bFlag = 1;
                wsprintf(szText,"%s",TEXT("按滑鼠左鍵繼續"));
                InvalidateRect(hwnd, NULL, TRUE);
            } else {
                bFlag = 0;
                wsprintf(szText,"%s",TEXT("按滑鼠左鍵暫停"));
                InvalidateRect(hwnd, NULL, TRUE);
            }
       break;
       case WM_PAINT:
            wc.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
       
            //撥放音樂....還未學會
            //PlaySound("1.wav",NULL,SND_FILENAME | SND_ASYNC);

         hMyDC=BeginPaint(hwnd, &ps);
         
         SetBkMode(hMyDC, TRANSPARENT); //設定為背景通透
         
         //畫出邊界
         MoveToEx(hMyDC,10,10,NULL);
         LineTo(hMyDC,380,10);
         MoveToEx(hMyDC,380,10,NULL);
         LineTo(hMyDC,380,220);
         MoveToEx(hMyDC,380,220,NULL);
         LineTo(hMyDC,10,220);
         MoveToEx(hMyDC,10,220,NULL);
         LineTo(hMyDC,10,10);
         
         speed(hwnd); //控制速度
         
         randStar(); //看看有沒有碰到星星         

            starAndSnakeHand(hwnd,hMyDC,hBrush);  //畫出星星和蛇頭

            walked(); //計算走幾步,過去走過的路

           hBrush = CreateSolidBrush(RGB(132,255,77));
         SelectObject(hMyDC,hBrush);
         
         wsprintf(gameOverStr," 頭尾相撞 !! \n\n 總分:%d  \n\n 繼續遊戲 ? ",point);

            PrintTail(hwnd,hMyDC,gameOverStr, msg, wParam, lParam);  //畫出尾巴 並判斷有沒有頭尾相撞
         
         keyClicked();   //上下左右移動
            
            wsprintf(gameOverStr," 出界 !! \n\n 總分:%d  \n\n 繼續遊戲 ? ",point);
            outLine(hwnd,hMyDC,gameOverStr, msg, wParam, lParam);  //檢查是否出界 如果出界就結束
            
            printOther(hwnd,hMyDC);  //畫出其他有的沒的資料

            SetTextColor(hMyDC,RGB(255,111,33));
            TextOut(hMyDC,140,100,szText,lstrlen(szText));//顯示暫停與否(按滑鼠左鍵)
            
            strcpy(szText,"");  //這樣才不會殘留在畫面上
            
            DeleteObject(hBrush);
            
            EndPaint(hwnd, &ps);
          
        break;
        case WM_CLOSE:

            KillTimer(hwnd,1);
            DestroyWindow(hwnd);
        break;
        case WM_DESTROY:

            PostQuitMessage(0);
        break;
        default:
            return DefWindowProc(hwnd, msg, wParam, lParam);
    }
    return 0;
}

int nTopXY(UINT wnd_XY, UINT wnd_Dim)
{
    int resl;
    resl=((wnd_Dim/2)-(wnd_XY/2));
    return resl;
}

//-----------------end---------------------








Function.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
#include <windows.h>
#include <Winuser.h> //GDI相關的函式與資料結構宣告於Winuser.h

#include <stdlib.h>
#include <time.h>


// NEW

#define RADIUS 7  //蛇頭和星星的碰撞容許距離
#define MOVE_DISTANCE 6 //一次移動的距離
#define SNAKE_SIZE 15//蛇的大小
#define STAR_SIZE 15 //星星大小
#define BACKGROUND_PIC "B1.bmp"  //背景圖片
#define SNAKE_DISTANCE 10 //蛇身每一段相隔的距離


//  OLD

#define EQU ==
#define RIGHT 365
#define LEFT 10
#define UP 10
#define DOWN 205
#define WALKED 15000  //走超過15000格就會重頭放入array
#define TAIL_NUM 50 //尾巴超過50個就會當掉


//從主程式搬過來的

const  char* szAppName = "MyWndClass";
int nTick = 0;

int nTickX = 1;
int nTickY = 1;

BOOL bFlag =0;
char szText[5] = "&quot;;
char szTextKey[10] ="&quot;; //用來顯示狀態的字元陣列
char szTick[100] ;   //顯示時間
char szCharKey[10];  //用來顯示按鍵的字元
char    szOut[10] = "出界!!";
char    szPoint[100];

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int nTopXY(UINT, UINT);


//  NEW

int cpuTime = 60;  //控制蛇的速度

//目前的(X,Y)位置
int nowX = 160;
int nowY = 100;
char nowXYStr[20];

//上次移動的位移
int moveX = 0;
int moveY = 0;

//星星的位置
int starX = 0;
int starY = 0;

int nowKeyNumber = 0; //目前按下的鍵盤對應數值
int beforeKeyNumber = 0; //前一個方向

int nowXYPlace = 0;   //目前位置
int tailNumber = 0;   //尾巴數目

int walkedNumber = 0; //總共走了多少步

//                 上 下  左             右
int aspectX[4] = { 0 ,0  ,SNAKE_DISTANCE,-SNAKE_DISTANCE };
int aspectY[4] = { SNAKE_DISTANCE,-SNAKE_DISTANCE,0 ,0   };


//  OLD

int point = 0; //得int currentAspect = 0; //目前方向
int walkX[WALKED] = {0};  //走過的
int walkY[WALKED] = {0};


//WinAPI貪食蛇版本加入的
void randStar(); //讓星星被撞到後隨機跑
void keyClicked(); //上下左右移動
void walked(); //走過的路
void outLine(HWND ,HDC ,char ); //檢查是否出界 如果出界就結束
void PrintTail(HWND ,HDC ,char); //畫出蛇的尾巴
void starAndSnakeHand(HWND ,HDC ,HBRUSH); //畫出星星和蛇頭
void speed();  //隨分數調整速度
void reStart(); //重新開始的歸零動作


//DOS貪食蛇版本有的
int Move(int,int,int);  //移動位置
void Star(int*,int*,int,int,int*);  //畫出星星並讓其軌跡隨機
void PrintBorder(int );  //畫出外框
void Play();  //遊戲主要套件
void PrintSnake();  //畫出蛇的軌跡
void Start(); //開始處理
int End();  //結束處理
void PrintTail();  //畫出蛇的尾巴
void PrintAspect();  //標出目前的方向
void Restart(); //重新玩的歸零動作
int IsAgain();  //是否重新玩
int Walked(); //走過的路
int IsBumpTail(); //頭撞到尾巴
void Speed(); //依分數調節速度
void EndView(); //最後的等待畫面


//   以下為WinAPI貪食蛇版本加入的     

void randStar()
//讓星星被撞到後隨機移動
{

    if (starX == 0 && starY == 0         ){//第一次
        srand(time(NULL));
        starX = rand()%330 + 20;
        starY = rand()%180 + 20;
    }
    else if ( ((nowX-starX) <= RADIUS && (nowX-starX) >= -RADIUS) &&
             ((nowY-starY) <= RADIUS && (nowY-starY) >= -RADIUS)    ){ //蛇碰到星星
       srand(time(NULL));
       starX = rand()%200+rand()%160 + 15 ;
       starY = rand()%100+rand()%55 + 20;
       point += 10; //碰到星星所以加分
    }
}

void starAndSnakeHand(HWND hwnd,HDC hMyDC,HBRUSH hBrush)
//畫出星星和蛇頭
{
    hBrush = CreateSolidBrush(RGB(255,255,48));
         SelectObject(hMyDC,hBrush);
         Ellipse(hMyDC,starX,starY,starX+STAR_SIZE,starY+STAR_SIZE); //星         
         DeleteObject(hBrush);
         
         hBrush = CreateSolidBrush(RGB(0,255,0));
         SelectObject(hMyDC,hBrush);
         Ellipse(hMyDC,nowX,nowY,nowX+SNAKE_SIZE+3,nowY+SNAKE_SIZE+3); //蛇         
         DeleteObject(hBrush);
}

void keyClicked()
//上下左右移動 並紀錄方向
{
    if (nowKeyNumber == 38 ){ //上
        nowY = nowY - MOVE_DISTANCE ;
        moveX = 0;
        moveY = -MOVE_DISTANCE;
        currentAspect = 0;
    }
    else if (nowKeyNumber == 40){ //下
        nowY = nowY + MOVE_DISTANCE ;
        moveX = 0;
        moveY = MOVE_DISTANCE;
        currentAspect = 1;
    }
    else if (nowKeyNumber == 37){ //左
        nowX = nowX - MOVE_DISTANCE ;
        moveX = -MOVE_DISTANCE;
        moveY = 0;
        currentAspect = 2;
    }
    else if (nowKeyNumber == 39){ //右
        nowX = nowX + MOVE_DISTANCE ;
        moveX = MOVE_DISTANCE;
        moveY = 0;
        currentAspect = 3;
    }
    else{
        nowX = nowX + moveX;
        nowY = nowY + moveY;
    }
}

void walked()
//紀錄走過的路
{
    nowXYPlace = (walkedNumber+WALKED-1) % WALKED;  //紀錄走過的路 (0-49一循環)
    tailNumber = point / 10 ; //計算目前蛇的尾巴有多長
    
    walkedNumber ++;
    int i = nowXYPlace;

    walkX[i] = nowX;
    walkY[i] = nowY;
}

void PrintTail(HWND hwnd,HDC hMyDC,char gameOverStr[10],UINT msg, WPARAM wParam, LPARAM lParam)
//畫出蛇的尾巴
{
    int distance = 1; //蛇身每一段的相隔距離
    int handDistance = 3;
    int first = 0; //解決頭和第一個身體靠太近的問題
    int id = 0; //判斷是與否
    
    while ( tailNumber > 0){
        if (nowXYPlace > 10  ){   //走十步以上才開始計算
            if (distance == 1)
                first = -2;
            else
                first = 0;

            Ellipse(hMyDC,
                walkX[nowXYPlace-2*distance+first],
                walkY[nowXYPlace-2*distance+first],
                walkX[nowXYPlace-2*distance+first]+SNAKE_SIZE,
                walkY[nowXYPlace-2*distance+first]+SNAKE_SIZE ); //蛇
                //檢查是否撞到尾巴
            if (nowX == walkX[nowXYPlace-2*distance+first] &&
               nowY == walkY[nowXYPlace-2*distance+first]    ||
               nowX == walkX[nowXYPlace-2*distance-1] &&
               nowY == walkY[nowXYPlace-2*distance-1]       ){
                KillTimer(hwnd,1);  //讓時間計算停止

                id = MessageBox(hwnd,gameOverStr,"遊戲結束", MB_YESNO | MB_ICONINFORMATION);

                if (id == IDNO)
                    PostQuitMessage(0);   //關閉程式
                else{
                    reStart();  //把全域變數歸零
                    DefWindowProc(hwnd, msg, wParam, lParam); //重新開始
                }
            }
    
            tailNumber--;
            nowXYPlace--;
            distance++;     //增加這個是為了把每一節之間的距離拉長
        }
    }
}

void reStart()
//歸零動作
{
    nTick = 0;

    nTickX = 1;
    nTickY = 1;

    bFlag =0;
    
    strcpy(szText,"&quot;);
    strcpy(szTextKey,"&quot;);
    strcpy(szTick,"&quot;);
    strcpy(szCharKey,"&quot;);
    strcpy(szOut,"&quot;);
    strcpy(szPoint,"&quot;);


//  NEW

    cpuTime = 60;  //控制蛇的速度

//目前的(X,Y)位置
    nowX = 160;
    nowY = 100;
    strcpy(nowXYStr,"&quot;);

//上次移動的位移
    moveX = 0;
    moveY = 0;

//星星的位置
    starX = 0;
    starY = 0;

    nowKeyNumber = 0; //目前按下的鍵盤對應數值
    beforeKeyNumber = 0; //前一個方向

    nowXYPlace = 0;   //目前位置
    tailNumber = 0;   //尾巴數目

    walkedNumber = 0; //總共走了多少步


//  OLD

    point = 0; //得    currentAspect = 0; //目前方向
    
    for (int i = 0 ; i < WALKED ; i++){
        walkX[i] = 0;  //走過的
        walkY[i] = 0;
    }
}


void outLine(HWND hwnd,HDC hMyDC,char gameOverStr[10],UINT msg, WPARAM wParam, LPARAM lParam)
//檢查是否出界 如果出界就結束
{
    LPOPENFILENAME lpofn ;
    
    int id = 0; //判斷按下是還是否
    
    HBRUSH hBrush; //變換方格顏色用
    
    hBrush = CreateSolidBrush(RGB(132,255,77));
    SelectObject(hMyDC,hBrush);
    
    if ( nowX > RIGHT || nowX < LEFT || nowY > DOWN || nowY < UP){
        KillTimer(hwnd,1);  //讓時間計算停止
        id = MessageBox(hwnd,gameOverStr,"遊戲結束", MB_YESNO | MB_ICONINFORMATION);

        if (id == IDNO)
            PostQuitMessage(0);   //關閉程式
        else{
            GetOpenFileName(lpofn);
            DeleteObject(hBrush);

            reStart();  //把全域變數歸零
            DefWindowProc(hwnd, msg, wParam, lParam); //重新開始
        }
    }
}

void printOther(HWND hwnd,HDC hMyDC)
{
    int nLen = sizeof(szText)-1;
    
    SetTextColor(hMyDC,RGB(230,95,230));
    TextOut(hMyDC,10,245,szTick,lstrlen(szTick)); //顯示目前秒數

    SetTextColor(hMyDC,RGB(110,95,230));
    wsprintf(szPoint,"分數 : %d",point);  //目前分數
    TextOut(hMyDC,170,245,szPoint,strlen(szPoint));//顯示目前分數

    SetTextColor(hMyDC,RGB(0,0,0));
    wsprintf(nowXYStr," ( %d , %d )",nowX,nowY);
    TextOut(hMyDC,80,245,nowXYStr,lstrlen(nowXYStr));  //顯示目前位置
    
    SetTextColor(hMyDC,RGB(45,95,115));
    TextOut(hMyDC,320,245,szCharKey,lstrlen(szCharKey));//顯示按下的字元
    
    SetTextColor(hMyDC,RGB(111,0,115));
    TextOut(hMyDC,260,245,szTextKey,lstrlen(szTextKey));//顯示有沒有按下   
}

void speed(HWND hwnd)
//隨分數調整速度
{
    if (point > 300)
        cpuTime = 20;
    else if (point > 200)
        cpuTime = 25 ;
    else if (point > 140)
        cpuTime = 30 ;
    else if (point > 90)
        cpuTime = 40;
    else if (point > 40)
        cpuTime = 50;

    SetTimer(hwnd,1,cpuTime,NULL);   //重新設制速度
}

No response to “WinAPI版本的貪食蛇” ;

張貼留言