关闭

win32贪吃蛇实现

标签: win32互联网创新
3442人阅读 评论(4) 收藏 举报
分类:

写程序是一个循序渐进的过程,一开始都是加加减减,修修补补,这和我们做企业做创新的原理都是一样的,没有一蹴而就的成功,最近看了周鸿祎的《我的互联网方法论》蛮有启发,分享给大家几句摘抄:
1.所有的颠覆式创新都不是敲锣打鼓来的,而是隐藏在一片噪声里。

2.颠覆式创新,就像自然界的新陈代谢一样,不断把老的、旧的公司从行业中挤出去。所以,这种颠覆式创新已经成为美国硅谷的一个象征。破坏和颠覆,都是强调打破原有的平衡,建立新秩序。但这两个词在中文里都是贬义词,因为中国文化崇尚平衡、稳定、和谐。一说颠覆式创新,我们的潜意识就会觉得是反动的东西,就不由自主地想到阶级敌人搞破坏。我有些时候受邀给一些单位讲互联网里的颠覆式创新。讲完后,有的领导就过来跟我握手说:小周,讲得挺好的嘛,只不过以后不要讲颠覆、讲破坏,影响社会和谐。

3.我不赞成企业大张旗鼓地搞创新,非要巨额投入资金,非要设立创新研究院,非要做一个整套的创新战略。我觉得休克式疗法的创新很难成功,我主张把创新从神坛上拉下来,从一些细微点上进行持续创新,这样反而更有效。

4.乔布斯有一天给谷歌高管打电话,说苹果iOS有一个谷歌地图图标,放大多少倍之后,第三行一个像素颜色不对,他认为这影响了iOS的美观。这就是对细节的一种坚持。

下面我们来看一个贪吃蛇的实现代码:
主要有两个大的步骤:
1.界面的绘制
这里写图片描述
2.蛇的绘制
这里写图片描述

主要代码:


// Snake.cpp : 定义应用程序的入口点。
//

#include "stdafx.h"
#include "Snake.h"
#include <vector>
#include<time.h>

#define MAX_LOADSTRING 100
//定义游戏区 和 控制区大小
#define BOUND_SIZE 10
#define SNACK_SIZE 10
#define GAME_WIDTH  80
#define GAME_HEIGHT 60
#define INFO_WIDTH  30
#define INFO_HEIGHT GAME_HEIGHT

#define MAX_NODE  80 //蛇的最大长度 80 节

#define MY_TIMER 1  //定时器ID
#define DEFAULT_INTERVAL 200 //定义贪食蛇的默认移动速度 500毫秒移动一节
#define PAUSE_ID 1

std::vector<POINT> vSnake;
UCHAR g_ucSnakeLen = 4;
UCHAR g_ucSnakeHead = 4; //vSnack[g_ucSnakeHead-1] 表示蛇头的坐标
UCHAR g_ucSnakeTail = 0; //vSnack[g_ucSnakeTail] 表示蛇尾的坐标
UINT32 g_uiInterval = DEFAULT_INTERVAL; //移动速度
POINT  g_ptDirect = {1, 0}; //移动方向,每次x+1, y不变
POINT  g_ptFoodPos;

BOOL g_bState = TRUE; //游戏是否结束
BOOL g_bNeedFood = TRUE; //是否要投放食物
BOOL g_bPause = FALSE; //暂停


// 全局变量: 
HINSTANCE hInst;                                // 当前实例
TCHAR szTitle[MAX_LOADSTRING];                  // 标题栏文本
TCHAR szWindowClass[MAX_LOADSTRING];            // 主窗口类名

// 此代码模块中包含的函数的前向声明: 
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
    _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPTSTR    lpCmdLine,
    _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO:  在此放置代码。
    MSG msg;
    HACCEL hAccelTable;

    // 初始化全局字符串
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_SNAKE, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // 执行应用程序初始化: 
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_SNAKE));

    // 主消息循环: 
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  函数:  MyRegisterClass()
//
//  目的:  注册窗口类。
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SNAKE));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_SNAKE);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   函数:  InitInstance(HINSTANCE, int)
//
//   目的:  保存实例句柄并创建主窗口
//
//   注释: 
//
//        在此函数中,我们在全局变量中保存实例句柄并
//        创建和显示主程序窗口。
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
    HWND hWnd;

    hInst = hInstance; // 将实例句柄存储在全局变量中

    hWnd = CreateWindow(szWindowClass, szTitle, WS_SYSMENU | WS_MINIMIZEBOX,
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

    if (!hWnd)
    {
        return FALSE;
    }

    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    return TRUE;
}

VOID InitSnack()  //初始化蛇,设定蛇的起始位置
{
    int i;

    vSnake.clear();
    vSnake.resize(MAX_NODE);    

    g_ucSnakeTail = 0;
    g_ucSnakeHead = 4;
    g_ucSnakeLen = 4;
    g_uiInterval = DEFAULT_INTERVAL;

    for (i = 0; i < g_ucSnakeLen; i++)
    {
        //初始化蛇的各个节点
        vSnake[i].x = i;
        vSnake[i].y = 1;
    }
}

POINT &GetSnakeNode(int index) //获取蛇节点位置:倒数第几个节点
{
    int i = g_ucSnakeTail + index;

    if (i >= MAX_NODE)
    {
        i -= MAX_NODE;
    }

    return vSnake[i];
}

VOID DrawSnake(HDC hdc)
{
    int i;
    POINT ptNode;
    HBRUSH hBrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
    SelectObject(hdc, hBrush);
    for (i = 0; i < g_ucSnakeLen; i++)
    {
        //从蛇尾开始画
        ptNode = GetSnakeNode(i);
        Rectangle(hdc, ptNode.x * SNACK_SIZE + BOUND_SIZE,
            ptNode.y * SNACK_SIZE + BOUND_SIZE,
            (ptNode.x + 1) * SNACK_SIZE + BOUND_SIZE,
            (ptNode.y + 1) * SNACK_SIZE + BOUND_SIZE);
    }
}

//移动蛇坐标
VOID RefreshSnake()
{
    //采用翻滚的形式 比如,vSnake[0], vSnake[1],vSnake[2] vSnake[3] 表示蛇的话
    //移动一节后,vSnake[1],vSnake[2] vSnake[3] vSnake[4] 表示蛇
    //vSnake[MAX_NODE -1 ] 后,蛇头存入 vSnake[0]
    POINT ptNewHead; //新的蛇头位置
    POINT ptNode;
    int i;

    ptNewHead.x = GetSnakeNode(g_ucSnakeLen - 1).x + g_ptDirect.x;
    ptNewHead.y = GetSnakeNode(g_ucSnakeLen - 1).y + g_ptDirect.y;

    if (!g_bNeedFood && ptNewHead.x == g_ptFoodPos.x && ptNewHead.y == g_ptFoodPos.y)
    {
        //吃到食物了
        vSnake[g_ucSnakeHead] = ptNewHead;

        g_ucSnakeHead++;
        if (g_ucSnakeHead == MAX_NODE) g_ucSnakeHead = 0;

        g_ucSnakeLen++;

        if (g_ucSnakeLen == MAX_NODE)
        {
            //赢了,事实上,我们不应该等到这个时候才判断赢了
            g_bState = FALSE;
            return;
        }
        g_bNeedFood = TRUE;
        return;
    }

    if (ptNewHead.x < 0 || ptNewHead.x >= GAME_WIDTH || ptNewHead.y < 0 || ptNewHead.y >= GAME_HEIGHT)
    {
        //蛇撞墙了
        g_bState = FALSE;
        return;
    }

    for (i = 1; i < g_ucSnakeLen; i++)
    {
        ptNode = GetSnakeNode(i);
        if (ptNode.x == ptNewHead.x && ptNode.y == ptNewHead.y)
        {
            //蛇撞到自己了
            g_bState = FALSE;
            return;
        }
    }


    vSnake[g_ucSnakeHead].x = ptNewHead.x;
    vSnake[g_ucSnakeHead].y = ptNewHead.y;//新的蛇头

    g_ucSnakeHead++;
    if (g_ucSnakeHead == MAX_NODE) g_ucSnakeHead = 0;

    g_ucSnakeTail++;
    if (g_ucSnakeTail == MAX_NODE) g_ucSnakeTail = 0;

    return;
}

VOID DrawFood(HDC hdc)
{
    int x, y;
    POINT ptNode; 
    int i;
    HBRUSH hBrush = (HBRUSH)GetStockObject(BLACK_BRUSH);

    if (!g_bNeedFood)
    {
        SelectObject(hdc, hBrush);
        Ellipse(hdc, BOUND_SIZE + g_ptFoodPos.x * SNACK_SIZE, 
            BOUND_SIZE + g_ptFoodPos.y * SNACK_SIZE,
            BOUND_SIZE + (g_ptFoodPos.x + 1) * SNACK_SIZE, 
            BOUND_SIZE + (g_ptFoodPos.y + 1) * SNACK_SIZE);
        return;
    }

    srand(time(0)); //随机数种子
    //获取随机坐标,不能是蛇的位置
    while (1)
    {
        x = rand() % GAME_WIDTH;
        y = rand() % GAME_HEIGHT;

        for (i = 0; i < g_ucSnakeLen; i++)
        {
            ptNode = GetSnakeNode(i);
            if (ptNode.x == x && ptNode.y == y)
            {
                break;
            }
        }
        if (i == g_ucSnakeLen) //一直没有break,表示不重复
        {
            break;
        }
    }
    g_bNeedFood = FALSE;
    g_ptFoodPos.x = x;
    g_ptFoodPos.y = y;

    SelectObject(hdc, hBrush);
    Ellipse(hdc, BOUND_SIZE + x * SNACK_SIZE, BOUND_SIZE + y * SNACK_SIZE,
        BOUND_SIZE + (x + 1) * SNACK_SIZE, BOUND_SIZE + (y + 1) * SNACK_SIZE);

    return;
}
//
//  函数:  WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  目的:    处理主窗口的消息。
//
//  WM_COMMAND  - 处理应用程序菜单
//  WM_PAINT    - 绘制主窗口
//  WM_DESTROY  - 发送退出消息并返回
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    RECT rect;
    int i;
    int nWinX, nWinY, nClientX, nClientY;
    HBRUSH hBrush;
    static HWND hPause;

    switch (message)
    {
    case WM_CREATE: //创建窗口时候执行的代码
        GetWindowRect(hWnd, &rect); //获取窗口大小
        nWinX = rect.right - rect.left;
        nWinY = rect.bottom - rect.top;
        GetClientRect(hWnd, &rect); //客户区大小
        nClientX = rect.right - rect.left;
        nClientY = rect.bottom - rect.top;

        //修改窗口大小 客户区大小 + 边框大小 (nWinX-nClientX)
        MoveWindow(hWnd, 0, 0, 
            (GAME_WIDTH + INFO_WIDTH)*SNACK_SIZE + BOUND_SIZE * 3 + (nWinX - nClientX),
            GAME_HEIGHT*SNACK_SIZE + BOUND_SIZE * 2 + (nWinY - nClientY), TRUE);

        hPause = CreateWindow(TEXT("Button"), TEXT("暂停"),
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
            3 * BOUND_SIZE + GAME_WIDTH * SNACK_SIZE, 200, 200, 100,
            hWnd, (HMENU)PAUSE_ID, hInst, NULL
            );

        InitSnack();

        SetTimer(hWnd, MY_TIMER, g_uiInterval,NULL); //起一个定时器

        break;
    case WM_TIMER: //定时器到点
        //移动蛇
        RefreshSnake();
        if (!g_bState)
        {
            KillTimer(hWnd, MY_TIMER); //停止计时器
            MessageBox(NULL, TEXT("你输了"), TEXT("FAIL"), MB_OK);
            //InitSnack();
            return 0;
        }
        InvalidateRect(hWnd, NULL, TRUE);
        break;
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // 分析菜单选择: 
        switch (wmId)
        {
        case PAUSE_ID:
            if (g_bPause)
            {
                g_bPause = FALSE;
                SetWindowText(hPause, TEXT("暂停"));
                SetTimer(hWnd, MY_TIMER, g_uiInterval, NULL);
            }
            else
            {
                g_bPause = TRUE;
                SetWindowText(hPause, TEXT("继续"));
                KillTimer(hWnd, MY_TIMER);
            }
            break;
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO:  在此添加任意绘图代码...

        hBrush = (HBRUSH)GetStockObject(GRAY_BRUSH);
        SelectObject(hdc, hBrush);

        Rectangle(hdc, BOUND_SIZE, BOUND_SIZE, 
            BOUND_SIZE + GAME_WIDTH*SNACK_SIZE, 
            BOUND_SIZE + GAME_HEIGHT*SNACK_SIZE);

        Rectangle(hdc, BOUND_SIZE * 2 + GAME_WIDTH*SNACK_SIZE  , BOUND_SIZE,
            BOUND_SIZE*2 + (GAME_WIDTH + INFO_WIDTH)*SNACK_SIZE,
            BOUND_SIZE + INFO_HEIGHT*SNACK_SIZE);

        DrawSnake(hdc);

        DrawFood(hdc);

        EndPaint(hWnd, &ps);
        break;
    case WM_KEYDOWN:
        if (!g_bState || g_bPause)
        {
            break;
        }
        switch (wParam)
        {
        case VK_UP: //调节方向:注意点,原来是往上或者往下的话,不做操作
            if (g_ptDirect.x != 0)
            {
                g_ptDirect.x = 0;
                g_ptDirect.y = -1;
            }
            break;
        case VK_DOWN:
            if (g_ptDirect.x != 0)
            {
                g_ptDirect.x = 0;
                g_ptDirect.y = 1;
            }
            break;
        case VK_LEFT:
            if (g_ptDirect.y != 0)
            {
                g_ptDirect.x = -1;
                g_ptDirect.y = 0;
            }
            break;
        case VK_RIGHT:
            if (g_ptDirect.y != 0)
            {
                g_ptDirect.x = 1;
                g_ptDirect.y = 0;
            }
            break;
        }
        break;
    case WM_DESTROY:
        KillTimer(hWnd, MY_TIMER);
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// “关于”框的消息处理程序。
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}


4
0
查看评论

队列的使用—WIN32控制台贪吃蛇(VS2010,C++语言)

VS2010平台C++开发的基于数组实现的贪吃蛇小程序
  • yaodix
  • yaodix
  • 2016-06-01 20:21
  • 1233

贪吃蛇详解Windows编程(四)

控制区的代码就不详细讲解了,自己看看就能明白,并没有什么难点。如果有兴趣的画还可以把界面做好一点,把功能做丰富一点。但是我觉得点到为止就行了。我用的是Win32空项目写的,你也可以用自动生成的代码写,但是我觉得那个太乱代码太多。 接下来是全部的代码: #include <windows.h&...
  • qq_18297675
  • qq_18297675
  • 2015-12-27 15:50
  • 1420

【141030】VC++贪吃蛇游戏源码(Win32+API)

不错的贪吃蛇游戏,运用了Win32的API。完整源代码,在VS2005下编译通过。内附有编程要点,很好的学习范例。 游戏源码下载地址:点击下载
  • qutadi
  • qutadi
  • 2014-10-30 21:31
  • 1533

win32游戏编程——贪吃蛇游戏

1.写此贴的意图         刚开始学c++,编的是win32 console application,在黑框框里进行输入和输出,觉得和自己想象的程序差好多,有点失望,后来接触到win32程序,感觉和我们平时见到的程序差不多,然后想尝试去编一些简单的游戏。
  • u010534406
  • u010534406
  • 2015-11-12 16:57
  • 426

win32编程之贪吃蛇(有瑕疵)

今天花了大概8个小时做了个贪吃蛇,主要的时间还是花费在了如何做的更流畅上面,之前的做法是每次移动整数个单位,给自己的感觉是不太流畅,所以后来改成每次移动的部署为double类型的,  但是有潜在的问题,判断无法精准,只能有个大概的判断,可能是我水平不够暂时还无法做到,希望得到指点。 ...
  • aaa1995421
  • aaa1995421
  • 2016-05-30 17:09
  • 380

C语言实现贪吃蛇(三)----结构+链表实现

前言:本博客所讲到的知识跟前面我的两篇博客:《C语言实现贪吃蛇(一)—-数组实现》、《C语言实现贪吃蛇(二)—-局部刷新》 有很大的关系,建议大家前往看一下,尤其是第一篇,那篇博客是所有关于贪吃蛇游戏的基础。之前的两篇博客将运用的C语言知识限定在了一般的数组上,但如果已经完整地了解过C语言的话,运用...
  • baidu_30000217
  • baidu_30000217
  • 2016-11-17 22:42
  • 2418

C++实现的贪吃蛇游戏

               C++实现的贪吃蛇游戏  [ 来源:SOHO-IT论坛    点击数:218&#...
  • luckisok
  • luckisok
  • 2006-07-21 16:24
  • 1789

Unity3D 协程实现贪吃蛇

using System.Collections; using System.Collections.Generic; using UnityEngine;public class ControlSnake : MonoBehaviour { List<SnakeBody> sn...
  • BattleTiger
  • BattleTiger
  • 2017-09-11 21:02
  • 226

Java实现简单的贪吃蛇

这两天学着做了一个简单的贪吃蛇,只是为了练习用,所以很多地方都不完美 实现方式是用链表 活动区域Yard: import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Graphics; ...
  • dly215011
  • dly215011
  • 2016-10-30 23:06
  • 9032

Unity实现简单贪吃蛇

贪吃蛇 游戏是一款经典的手机游戏,既简单又耐玩。通过控制蛇头方向吃蛋,使得蛇变长,从而获取积分。 蛇头的实现:
  • xiaoge132
  • xiaoge132
  • 2017-02-22 09:22
  • 4321
    公众号,github
    公众号:     老王和他的IT界朋友们
    欢迎投稿:  shiter@live.cn
    QQ交流群:  593683975
    加群问题:抛硬币正面上的期望?

    我们想用一段音乐,几张图片,
    些许文字绘制的IT圈心路历程,
    为攻城狮,为程序员带来更多的人文关怀。

    投稿原创文章有稿费,杂志等福利!!!



    github:  https://github.com/wynshiter
    个人资料
    • 访问:1327201次
    • 积分:14460
    • 等级:
    • 排名:第997名
    • 原创:191篇
    • 转载:51篇
    • 译文:74篇
    • 评论:712条
    博客专栏
    百度统计
    微信公众号
      微信公众号
      老王和他的IT界朋友们