鱼C论坛

 找回密码
 立即注册
查看: 809|回复: 3

[已解决]看不懂小甲鱼的贪吃蛇代码

[复制链接]
发表于 2019-3-19 10:11:53 | 显示全部楼层 |阅读模式
100鱼币
代码如下
#include <windows.h>
#include <time.h>
#include <stdlib.h>

//定义4个方向
#define UP                1  //向上,蛇头y坐标不断减小
#define DOWN        2  //向下,蛇头y坐标不断增大
#define LEFT        3  //向左,蛇头x坐标不断减小
#define RIGHT        4  //向右,蛇头x坐标不断增大

#define SNAKEWIDTH        10  //单节蛇的大小
#define XWIDTH                20  //游戏区的宽度
#define YHEIGHT                20  //游戏区的高度
#define GETSCORE        10        //吃一个食物的得分
#define ID_TIMER        1   //定时器ID
#define TIMERSET        600 //定时间隔

static int                        direct = RIGHT;  //方向(注:方向由蛇头决定)
static int                        Score;  //吃到的食物数量

bool                IsOver = false, bEat = false;

struct Snake
{
        Snake() :next(NULL), before(NULL)
        {
                pt.x = 0; pt.y = 0;
        }
        Snake(const POINT &npt, Snake *, Snake *);
        POINT        pt;
        Snake * next, *before;
} snake;  //定义蛇头

Snake::Snake(const POINT &npt, Snake * nnext, Snake * nbefore) :
        pt(npt), next(nnext), before(nbefore) {}

Snake * psLast = NULL, *food = NULL;

bool GameClient[XWIDTH][YHEIGHT]; //定义游戏区坐标布尔值,表示相应点的蛇身以及是否有食物。

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);                                                                             
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
        TCHAR                szAppName[] = TEXT("Snake"),
                szWindowName[] = TEXT("贪吃蛇");
        WNDCLASS        wndcls;
        wndcls.cbClsExtra = 0;
        wndcls.cbWndExtra = 0;
        wndcls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
        wndcls.hCursor = LoadCursor(hInstance, IDC_ARROW);
        wndcls.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
        wndcls.hInstance = hInstance;
        wndcls.lpfnWndProc = WndProc;
        wndcls.lpszClassName = szAppName;
        wndcls.lpszMenuName = NULL;
        wndcls.style = CS_HREDRAW | CS_VREDRAW;
        RegisterClass(&wndcls);

        HWND hwnd = CreateWindow(szAppName, szWindowName,
                WS_OVERLAPPED | WS_MINIMIZEBOX | WS_SYSMENU,
                CW_USEDEFAULT, CW_USEDEFAULT, (XWIDTH + 10) * SNAKEWIDTH, (YHEIGHT + 5) * SNAKEWIDTH,
                NULL, NULL, hInstance, NULL);
        ShowWindow(hwnd, nCmdShow);
        UpdateWindow(hwnd);

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

//新食物刷新
void NewFood(HWND hwnd)
{
        food = new Snake();
        SYSTEMTIME st;
        GetLocalTime(&st);
        srand(st.wMilliseconds);
        food->pt.x = rand() % XWIDTH, food->pt.y = rand() % YHEIGHT;
        while (GameClient[food->pt.x][food->pt.y])
        {
                GetLocalTime(&st);
                srand(st.wMilliseconds);
                food->pt.x = rand() % XWIDTH, food->pt.y = rand() % YHEIGHT;
        }
        GameClient[food->pt.x][food->pt.y] = true;
        InvalidateRect(hwnd, NULL, TRUE);
}

//判断前方是否是食物
inline bool IsFood()
{
        if (snake.pt.x == food->pt.x && snake.pt.y == food->pt.y)
                return true;
        else
                return false;
}

//判断是否撞墙或者撞到自己身体
bool TouchWall()
{
        Snake * temp = psLast;
        //超越边界判断
        if (snake.pt.x >= XWIDTH ||
                snake.pt.x < 0 ||
                snake.pt.y < 0 ||
                snake.pt.y >= YHEIGHT)
                return true;
        //碰撞自身身体判断
        while (temp != &snake)
        {
                if (snake.pt.x == temp->pt.x &&
                        snake.pt.y == temp->pt.y)
                        return true;
                temp = temp->before;
        }
        return false;
}


void Move(HWND hwnd)
{
        int x, y;  //用于记录蛇头的当前位置(未前进时)
        //标记前方是否为食物,默认为不是食物,表示系通常的前进
        Snake * temp = psLast;

        //记录蛇头当前坐标
        x = snake.pt.x;
        y = snake.pt.y;
        //测试前进的地方是否是食物,同时将蛇头前进
        switch (direct)
        {
        case UP:
                --snake.pt.y;
                break;
        case DOWN:
                ++snake.pt.y;
                break;
        case LEFT:
                --snake.pt.x;
                break;
        case RIGHT:
                ++snake.pt.x;
                break;
        default:
                break;
        }
        //如果不是食物,作如下处理
        if (!IsFood())
        {
                //最后一节不是蛇头
                if (temp != &snake)
                {
                        GameClient[temp->pt.x][temp->pt.y] = false;
                        while (temp != snake.next)
                        {
                                temp->pt.x = temp->before->pt.x;
                                temp->pt.y = temp->before->pt.y;
                                temp = temp->before;
                        }
                        temp->pt.x = x;
                        temp->pt.y = y;
                        GameClient[temp->pt.x][temp->pt.y] = true;
                }
                else  //psLast == &snake,即蛇只有蛇头
                        GameClient[x][y] = false;
                if (TouchWall())
                        IsOver = true;                                                //则标记游戏结束
                else
                        GameClient[snake.pt.x][snake.pt.y] = true;        //不然移动后的蛇头位置标记为有方块了
                InvalidateRect(hwnd, NULL, TRUE);                //刷新游戏区
        }
        //如果是食物,作如下处理
        else
        {
                ++Score;
                food->before = psLast;
                psLast->next = food;

                if (temp != &snake)
                {
                        food->pt.x = psLast->pt.x;
                        food->pt.y = psLast->pt.y;
                        while (temp != snake.next)
                        {
                                temp->pt.x = temp->before->pt.x;
                                temp->pt.y = temp->before->pt.y;
                                temp = temp->before;
                        }
                        temp->pt.x = x;
                        temp->pt.y = y;
                }
                else  //psLast == &snake,即蛇只有蛇头
                {
                        food->pt.x = x; food->pt.y = y;
                }
                psLast = food;
                NewFood(hwnd);
        }
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
        HDC                                hdc;
        PAINTSTRUCT                ps;
        TEXTMETRIC                tm;
        static int                cxChar, cyChar;
        TCHAR                        szScore[] = TEXT("得分:"),
                szGameOver[] = TEXT("游戏结束!"),
                szPause[] = TEXT("游戏暂停!"),
                szBuffer[20],
                *szText = NULL;
        int                                x, y;
        static bool                pause = false;

        switch (message)
        {
        case WM_CREATE:
                direct = RIGHT;   //游戏开局,默认方向向右
                snake.pt.x = XWIDTH / 2;  //默认显示在游戏区中间位置
                snake.pt.y = YHEIGHT / 2;
                psLast = &snake;
                GameClient[snake.pt.x][snake.pt.y] = true;
                hdc = GetDC(hwnd);
                GetTextMetrics(hdc, &tm);
                cyChar = tm.tmExternalLeading + tm.tmHeight;
                ReleaseDC(hwnd, hdc);
                NewFood(hwnd);
                SetTimer(hwnd, ID_TIMER, TIMERSET, NULL);
                return 0;

        case WM_TIMER:
                if (pause) return 0;
                Move(hwnd);
                if (IsOver)
                {
                        KillTimer(hwnd, ID_TIMER);
                        InvalidateRect(hwnd, NULL, TRUE);
                }
                return 0;

        case WM_KEYDOWN:
                if (IsOver || pause) return 0;
                switch (wParam)
                {
                case VK_UP:
                        if (direct != DOWN)
                        {
                                direct = UP;
                                Move(hwnd);
                        }
                        break;
                case VK_DOWN:
                        if (direct != UP)
                        {
                                direct = DOWN;
                                Move(hwnd);
                        }
                        break;
                case VK_LEFT:
                        if (direct != RIGHT)
                        {
                                direct = LEFT;
                                Move(hwnd);
                        }
                        break;
                case VK_RIGHT:
                        if (direct != LEFT)
                        {
                                direct = RIGHT;
                                Move(hwnd);
                        }
                        break;
                default:
                        break;
                }
                return 0;

        case WM_CHAR:
                if (IsOver && wParam != 'r') return 0;
                switch (wParam)
                {
                case 'p':
                {
                        pause = !pause;
                        InvalidateRect(hwnd, NULL, TRUE);
                }
                break;
                case 'r':
                {
                        for (int x = 0; x < XWIDTH; ++x)
                                for (int y = 0; y < YHEIGHT; ++y)
                                        GameClient[x][y] = false;
                }
                SetTimer(hwnd, ID_TIMER, TIMERSET, NULL);
                direct = RIGHT;   //游戏开局,默认方向向右
                snake.pt.x = XWIDTH / 2;  //默认显示在游戏区中间位置
                snake.pt.y = YHEIGHT / 2;
                psLast = &snake;
                IsOver = false;
                pause = false;
                GameClient[snake.pt.x][snake.pt.y] = true;
                NewFood(hwnd);
                break;
                default:
                        break;
                }
                return 0;

        case WM_PAINT:
                hdc = BeginPaint(hwnd, &ps);

                SetViewportOrgEx(hdc, SNAKEWIDTH, SNAKEWIDTH, NULL);
                //画游戏区的边框
                MoveToEx(hdc, -1, -1, NULL);
                LineTo(hdc, XWIDTH * SNAKEWIDTH + 1, -1);
                LineTo(hdc, XWIDTH * SNAKEWIDTH + 1, YHEIGHT * SNAKEWIDTH + 1);
                LineTo(hdc, -1, YHEIGHT * SNAKEWIDTH + 1);
                LineTo(hdc, -1, -1);

                TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 0, szScore, lstrlen(szScore));
                TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, cyChar,
                        szBuffer, wsprintf(szBuffer, TEXT("%4d"), Score));
                if (pause)
                        TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 3 * cyChar, szPause, lstrlen(szPause));
                else if (IsOver)
                        TextOut(hdc, (XWIDTH + 1) * SNAKEWIDTH, 3 * cyChar, szGameOver, lstrlen(szGameOver));
                SelectObject(hdc, GetStockObject(BLACK_BRUSH));
                for (x = 0; x < XWIDTH; ++x)
                {
                        for (y = 0; y < YHEIGHT; ++y)
                        {
                                if (GameClient[x][y])
                                        Rectangle(hdc, x * SNAKEWIDTH, y * SNAKEWIDTH,
                                        (x + 1) * SNAKEWIDTH, (y + 1) * SNAKEWIDTH);
                        }
                }
                return 0;

        case WM_DESTROY:
                KillTimer(hwnd, ID_TIMER);
                PostQuitMessage(0);
                return 0;
        }
        return DefWindowProc(hwnd, message, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);                                                                             
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)

这两句看不懂,想问一下,这部分需要补充什么内容的知识,然后这个代码我的编译器会报一些编译错误,他的main函数在哪里?
最佳答案
2019-3-19 10:11:54
这是windows编程的内容,后面的MFC框架的基础
你可以去简单学习一下windows编程设计课程

最佳答案

查看完整内容

这是windows编程的内容,后面的MFC框架的基础 你可以去简单学习一下windows编程设计课程
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-3-19 10:11:54 | 显示全部楼层    本楼为最佳答案   
这是windows编程的内容,后面的MFC框架的基础
你可以去简单学习一下windows编程设计课程

评分

参与人数 1荣誉 +5 鱼币 +5 贡献 +3 收起 理由
RIXO + 5 + 5 + 3 谢谢

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-9-12 16:03:44 | 显示全部楼层
Windows。h这个头文件怎么下载
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-9-17 08:47:51 | 显示全部楼层
好厉害
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-1-13 03:20

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表