1. 程式人生 > >遊戲:貪吃蛇

遊戲:貪吃蛇

一、Game.h

#ifndef __GAME_H__
#define __GAME_H__

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

//蛇移動區域
#define gamewidth 25
#define gameheigth 25

//牆
#define wallwidth (gamewidth+2)
#define wallheigth (gameheigth+2)

//蛇的方向
#define U 1 //上
#define D 2 //下
#define L 3 //左 #define R 4 //右 typedef struct Snake //蛇身的一個節點 { int x; int y; struct Snake *next; }Snake; typedef struct Food //食物節點 { int x; int y; }Food; void Pos(int x, int y); //設定游標位置 void StartInterface(); //開始介面 void CreatWall(); //建立牆 void InitSnake(Snake **pphead); //初始化蛇 void CreateFood(Snake *head, Food **ppfood); //建立食物
void InitGame(Snake **pphead, Food **ppfood); //遊戲初始化 int TouchWall(Snake *head); //判斷是否碰到牆 int BiteSelf(Snake *head); //判斷是否咬到了自己 void Pause(); //暫停 void EndGame(int endflag, int score); //結束遊戲 void MoveSnake(Snake **pphead, Food **ppfood, int direction, int *score, int perscore); //控制蛇前進 void ControlGame(Snake **pphead, Food *food, int
score, int perscore, int sleeptime); //控制遊戲 #endif __GAME_H__

二、Game.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

//設定游標位置
void Pos(int x, int y)
{
    COORD pos = { x, y };
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput, pos);

    CONSOLE_CURSOR_INFO cci;
    GetConsoleCursorInfo(hOutput, &cci); //獲取當前游標資訊 
    cci.bVisible = FALSE; //設定游標不可見 
    SetConsoleCursorInfo(hOutput, &cci);
}

//開始介面
void StartInterface()
{
    system("cls");
    Pos((50 - strlen("歡迎來到貪食蛇遊戲") / 2), 13);
    printf("歡迎來到貪食蛇遊戲\n");
    system("pause");
    system("cls");

    Pos((50 - strlen("用↑、↓、←、→分別控制蛇的移動, F1 為加速,F2 為減速") / 2), 13);
    printf("用↑、↓、←、→分別控制蛇的移動, F1 為加速,F2 為減速");
    Pos((50 - strlen("加速將能得到更高的分數") / 2), 15);
    printf("加速將能得到更高的分數\n");
    system("pause");
    system("cls");
}

//建立牆
void CreatWall()
{
    int i = 0;
    //for (i = 0; i < wallwidth * 2; i = i + 2)
    {
        Pos(i, 0);
        printf("■");
    }
    // 下
    for (i = 0; i < wallwidth * 2; i = i + 2)
    {
        Pos(i, wallheigth - 1);
        printf("■");
    }
    // 左
    for (i = 1; i < wallheigth - 1; i++)
    {
        Pos(0, i);
        printf("■");
    }
    // 右
    for (i = 1; i < wallheigth - 1; i++)
    {
        Pos((wallwidth - 1) * 2, i);
        printf("■");
    }
}

//初始化蛇
void InitSnake(Snake **pphead)
{
    Snake *tail = (Snake *)malloc(sizeof(Snake));
    tail->x = 2;
    tail->y = 2;
    tail->next = NULL;
    for (int i = 1; i < 3; i++) //頭插法
    {
        *pphead = (Snake *)malloc(sizeof(Snake));
        (*pphead)->x = 2 + 2 * i;
        (*pphead)->y = 2;
        (*pphead)->next = tail;
        tail = *pphead;
    }
    while (tail != NULL)
    {
        Pos(tail->x, tail->y);
        printf("■");
        tail = tail->next;
    }
}

//建立食物
void CreateFood(Snake *head, Food **ppfood)
{
    int flag = 0;
    srand((unsigned)time(NULL));
    *ppfood = (Food*)malloc(sizeof(Food));

    while (1)
    {
        (*ppfood)->x = (rand() % gameheigth + 1) * 2;
        (*ppfood)->y = rand() % gameheigth + 1;
        Snake *cur = head;
        while (cur)
        {
            if (cur->x == (*ppfood)->x&&cur->y == (*ppfood)->y) //食物不能和蛇身重合
            {
                flag = 1;
                break;
            }
            cur = cur->next;
        }
        if (flag == 0)
        {
            break;
        }
    }

    Pos((*ppfood)->x, (*ppfood)->y);
    printf("■");
}

//遊戲初始化
void InitGame(Snake **pphead, Food **ppfood)
{
    StartInterface();
    CreatWall();
    InitSnake(pphead);
    CreateFood(*pphead, ppfood);
}

//判斷是否碰到牆
int TouchWall(Snake *head)
{
    if (head->x == 0 || head->x == (wallwidth - 1) * 2 || head->y == 0 || head->y == wallheigth - 1)
    {
        return 1;
    }
    return 0;
}

//判斷是否咬到了自己
int BiteSelf(Snake *head)
{
    Snake *cur = head->next;
    while (cur)
    {
        if (cur->x == head->x&&cur->y == head->y)
        {
            return 1;
        }
        cur = cur->next;
    }
    return 0;
}

//暫停
void Pause()
{
    while (1)
    {
        Sleep(300);
        if (GetAsyncKeyState(VK_SPACE))
        {
            break;
        }
    }
}

//控制蛇前進
void MoveSnake(Snake **pphead, Food **ppfood, int direction, int *score, int perscore)
{
    Snake *nextnode = (Snake *)malloc(sizeof(Snake));
    switch (direction)
    {
    case U:
    {
              nextnode->x = (*pphead)->x;
              nextnode->y = (*pphead)->y - 1;
    }
        break;
    case D:
    {
              nextnode->x = (*pphead)->x;
              nextnode->y = (*pphead)->y + 1;
    }
        break;
    case L:
    {
              nextnode->x = (*pphead)->x - 2;
              nextnode->y = (*pphead)->y;
    }
        break;
    case R:
    {
              nextnode->x = (*pphead)->x + 2;
              nextnode->y = (*pphead)->y;
    }
        break;
    }

    if (nextnode->x == (*ppfood)->x&&nextnode->y == (*ppfood)->y) //下一個位置是食物
    {
        nextnode->next = *pphead;
        *pphead = nextnode;
        Snake *cur = *pphead;
        while (cur)
        {
            Pos(cur->x, cur->y);
            printf("■");
            cur = cur->next;
        }
        *score += perscore;

        free(*ppfood);
        CreateFood(*pphead, ppfood); //建立新的食物
    }
    else //下一個位置不是食物
    {
        nextnode->next = *pphead;
        *pphead = nextnode;
        Snake *cur = *pphead;
        while (cur->next->next) //找到蛇身倒數第二個節點
        {
            Pos(cur->x, cur->y);
            printf("■");
            cur = cur->next;
        }
        Pos(cur->next->x, cur->next->y);
        printf(" ");
        free(cur->next);
        cur->next = NULL;
    }
}

//結束遊戲
void EndGame(int endflag, int score)
{
    system("cls");
    if (endflag == 1)
    {
        Pos((50 - strlen("您已結束了遊戲") / 2), 13);
        printf("您已結束了遊戲\n");
    }
    else if (endflag == 2)
    {
        Pos((50 - strlen("遊戲結束,您撞到牆了") / 2), 13);
        printf("遊戲結束,您撞到牆了\n");
    }
    else if (endflag == 3)
    {
        Pos((50 - strlen("遊戲結束,您撞到自己了") / 2), 13);
        printf("遊戲結束,您撞到自己了\n");
    }

    Pos((50 - strlen("您的最終得分是:  ") / 2), 15);
    printf("您的最終得分是:%d\n", score);
}

//控制遊戲
void ControlGame(Snake **pphead, Food *food, int score, int perscore, int sleeptime)
{
    Pos(wallwidth * 2 + 10, 12);
    printf("不能撞到牆,不能撞到自己");
    Pos(wallwidth * 2 + 10, 13);
    printf("用↑、↓、←、→分別控制蛇的移動");
    Pos(wallwidth * 2 + 10, 14);
    printf("F1為加速,F2為減速");
    Pos(wallwidth * 2 + 10, 15);
    printf("Esc為退出遊戲,Space為暫停");

    int direction = R; //蛇的初始前進方向
    while (1)
    {
        Pos(wallwidth * 2 + 10, 10);
        printf("得分:%d    每個食物得分:%2d", score, perscore);
        if (GetAsyncKeyState(VK_UP) && direction != D)
        {
            direction = U;
        }
        else if (GetAsyncKeyState(VK_DOWN) && direction != U)
        {
            direction = D;
        }
        else if (GetAsyncKeyState(VK_LEFT) && direction != R)
        {
            direction = L;
        }
        else if (GetAsyncKeyState(VK_RIGHT) && direction != L)
        {
            direction = R;
        }
        else if (GetAsyncKeyState(VK_F1))
        {
            if (sleeptime > 100)
            {
                sleeptime -= 200;
                perscore += 5;
            }
        }
        else if (GetAsyncKeyState(VK_F2))
        {
            if (sleeptime < 500)
            {
                sleeptime += 200;
                perscore -= 5;
            }
        }
        else if (GetAsyncKeyState(VK_SPACE))
        {
            Pause();
        }
        else if (GetAsyncKeyState(VK_ESCAPE))
        {
            EndGame(1, score);
            return;
        }

        MoveSnake(pphead, &food, direction, &score, perscore);
        Sleep(sleeptime);

        if (TouchWall(*pphead))
        {
            EndGame(2, score);
            return;
        }
        if (BiteSelf(*pphead))
        {
            EndGame(3, score);
            return;
        }
    }
}

三、Test.c

#define _CRT_SECURE_NO_WARNINGS 1

#include "game.h"

void Menu()
{
    printf("**********貪吃蛇遊戲**********\n");
    printf("**                          **\n");
    printf("**        1.開始遊戲        **\n");
    printf("**        0.退出遊戲        **\n");
    printf("**                          **\n");
    printf("******************************\n");
}

int main()
{
    system("mode con cols=100 lines=32");
    int op = 0;
    do{
        Menu();
        printf("請選擇:");
        scanf("%d", &op);
        switch (op)
        {
        case 1:
        {
                  Snake *head = NULL;
                  Food *food = NULL;
                  int perscore = 10;
                  int score = 0;
                  int sleeptime = 300;

                  InitGame(&head, &food);
                  ControlGame(&head, food, score, perscore, sleeptime);

                  Snake* tail = NULL;
                  while (head)
                  {
                      tail = head->next;
                      free(head);
                      head = tail;
                  }

                  free(food);
                  food = NULL;

                  system("pause");
                  system("cls");
        }
            break;
        case 0:
        {
                  system("pause");
                  return 0;
        }
            break;
        }
    } while (op);
}