赞
踩
话不多说,首先要实现的是贪吃蛇地图的绘制。我们要绘制的贪吃蛇地图如下图所示:
要实现地图就必须得有坐标,方便我们找到对应的位置绘制墙壁、贪吃蛇的身体以及食物,控制台窗口的坐标如下图所示,横向的是X轴,从左向右依次增⻓,纵向是Y轴,从上到下依次增⻓。
游戏地图上我们以宽字符'□'来打印墙壁;宽字符'●'打印贪吃蛇的身体;宽字符'◆'食物。注:普通字符占一个字节,这类宽字符是占2个字节的。我们需要使用 wprintf() 来打印这类宽字符,由于c语言默认采用ASCLL编码,无法打印宽字符,所以需要<locale.h>本地化来实现宽字符的打印。
这里就不详细说明<locale.h>,我们只需要使用setlocale函数即可。该函数是用来修改当前地区,可以针对一个类项修改,也可以对所有类项修改。
setlocale函数有两个参数,第一个参数表示被修改的类项,可以是某一个类项也可以是全部类项,如果第⼀个参数是LC_ALL,就会影响所有的类项。第二个参数有两种取值:"C" (正常模式)和 " " (本地化模式)。使用如下代码就可以实现本地化了。
setlocale(LC_ALL, " ");
在本地化之后我们就可以使用wprint()来打印宽字符了,那么 wprint() 和 printf() 在使用过程中有何不同呢?
- printf("%c",'a');
- //printf()函数打印一个字符'a'
-
- wprintf(L"%lc",L'●');
- //wprintf()函数打印一个宽字符'●'
上面这两段代码可以看出wprintf函数和printf函数在使用的时候非常相似,仅仅是多了前缀“L”在单引号前⾯,表⽰宽字符,对应 wprintf() 的占位符为 %lc。
宽字符在打印的时候是占用两个普通字符的位置的,所以我们在设计地图的时候横纵坐标是不同的。
- typedef struct SnakeNode
- {
- int x;
- int y;
- struct SnakeNode* next;
- }SnakeNode,* pSnakeNode;
- typedef struct Snake
- {
- pSnakeNode _pSnake;//蛇的身体节点的指针
- pSnakeNode _pFood;//食物节点的指针
- enum Direction _Dir;//方向
- enum Game_Status _Status;//游戏状态
- int _Score;//总得分
- int _Food_Weight;//当前食物的分数
- int _SleepTime;//休息时间
- }Snake,* pSnake;
方向有上、下、左、右,是可以列举的,使用枚举:
- enum Direction
- {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
游戏状态有:正常运行、被墙撞死、被自己撞死以及主动退出四种,也使用枚举:
- enum Game_Status
- {
- OK,//正常运行
- KILL_BY_WALL,//撞到墙
- KILL_BY_SELF,//撞到自己
- END_NOMAL//正常退出
- };
- void test()
- {
- char n = 0;
- srand((unsigned int)time(NULL));
- do
- {
- Snake Snake = { 0 };
- system("cls");
- //开始游戏
- GameStart(&Snake);
- //游戏运行
- GameRun(&Snake);
- //游戏结束
- GameEnd(&Snake);
- _SetPos(24, 17);
- printf("是否先后来一局?(Y/N)");
- n=getchar();
- } while (n=='Y');
- }
-
- int main()
- {
- setlocale(LC_ALL, "");//修改为本地模式(为了打印宽字符)
- test();
- _SetPos(0, 27);
- return 0;
- }
该模块完成游戏的初始化
- //开始游戏
- void GameStart(pSnake ps)
- {
- //设置窗口为100列30行
- system("mode con cols=100 lines=30");
- //设置窗口名称
- system("title 贪吃蛇");
- //设置光标不显示
- _SetCursorInfo(false);
- //打印欢迎界面
- WelcomeToGame();
- //打印地图
- CreateMap();
- //初始化蛇身
- InitSnake(ps);
- //创建第一个食物
- CreateFood(ps);
- }
- //游戏运行
- void GameRun(pSnake ps)
- {
- //打印右侧帮助信息
- PrintInfo();
- do
- {
- _SetPos(64, 10);
- printf("分数:%2d", ps->_Score);
- _SetPos(64, 11);
- printf("当前食物分数:%2d", ps->_Food_Weight);
- if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
- {
- ps->_Dir = UP;
- }
- else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
- {
- ps->_Dir = DOWN;
- }
- else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
- {
- ps->_Dir = LEFT;
- }
- else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
- {
- ps->_Dir = RIGHT;
- }
- else if (KEY_PRESS(VK_F1))
- {
- if (ps->_SleepTime > 80)
- {
- ps->_SleepTime -= 30;
- ps->_Food_Weight += 2;
- }
- }
- else if (KEY_PRESS(VK_F2))
- {
- if (ps->_Food_Weight>2)
- {
- ps->_SleepTime += 30;
- ps->_Food_Weight -= 2;
- }
- }
- else if (KEY_PRESS(VK_ESCAPE))
- {
- ps->_Status = END_NOMAL;
- break;
- }
- else if (KEY_PRESS(VK_SPACE))
- {
- pause();
- }
- ///蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快
- Sleep(ps->_SleepTime);
- //蛇的移动
- SnakeMove(ps);
- } while (ps->_Status==OK);
- }
- //游戏结束
- void GameEnd(pSnake ps)
- {
- pSnakeNode cur = ps->_pSnake;
- _SetPos(24, 12);
- switch (ps->_Status)
- {
- case KILL_BY_WALL:
- printf("被墙撞死了!");
- break;
- case KILL_BY_SELF:
- printf("被自己撞死了!");
- break;
- case END_NOMAL:
- printf("主动退出!");
- break;
- }
-
- while (cur)
- {
- pSnakeNode del = cur;
- cur = cur->next;
- free(del);
- }
- }
- #define _CRT_SECURE_NO_WARNINGS
-
- #include "Snake.h"
-
- //开始游戏
- void GameStart(pSnake ps)
- {
- //设置窗口为100列30行
- system("mode con cols=100 lines=30");
- //设置窗口名称
- system("title 贪吃蛇");
- //设置光标不显示
- _SetCursorInfo(false);
- //打印欢迎界面
- WelcomeToGame();
- //打印地图
- CreateMap();
- //初始化蛇身
- InitSnake(ps);
- //创建第一个食物
- CreateFood(ps);
- }
-
- void pause()
- {
- while (1)
- {
- Sleep(200);
- if (KEY_PRESS(VK_SPACE))
- {
- break;
- }
- }
- }
-
- //游戏运行
- void GameRun(pSnake ps)
- {
- //打印右侧帮助信息
- PrintInfo();
- do
- {
- _SetPos(64, 10);
- printf("分数:%2d", ps->_Score);
- _SetPos(64, 11);
- printf("当前食物分数:%2d", ps->_Food_Weight);
- if (KEY_PRESS(VK_UP) && ps->_Dir != DOWN)
- {
- ps->_Dir = UP;
- }
- else if (KEY_PRESS(VK_DOWN) && ps->_Dir != UP)
- {
- ps->_Dir = DOWN;
- }
- else if (KEY_PRESS(VK_LEFT) && ps->_Dir != RIGHT)
- {
- ps->_Dir = LEFT;
- }
- else if (KEY_PRESS(VK_RIGHT) && ps->_Dir != LEFT)
- {
- ps->_Dir = RIGHT;
- }
- else if (KEY_PRESS(VK_F1))
- {
- if (ps->_SleepTime > 80)
- {
- ps->_SleepTime -= 30;
- ps->_Food_Weight += 2;
- }
- }
- else if (KEY_PRESS(VK_F2))
- {
- if (ps->_Food_Weight>2)
- {
- ps->_SleepTime += 30;
- ps->_Food_Weight -= 2;
- }
- }
- else if (KEY_PRESS(VK_ESCAPE))
- {
- ps->_Status = END_NOMAL;
- break;
- }
- else if (KEY_PRESS(VK_SPACE))
- {
- pause();
- }
- ///蛇每次⼀定之间要休眠的时间,时间短,蛇移动速度就快
- Sleep(ps->_SleepTime);
- //蛇的移动
- SnakeMove(ps);
- } while (ps->_Status==OK);
- }
-
- //游戏结束
- void GameEnd(pSnake ps)
- {
- pSnakeNode cur = ps->_pSnake;
- _SetPos(24, 12);
- switch (ps->_Status)
- {
- case KILL_BY_WALL:
- printf("被墙撞死了!");
- break;
- case KILL_BY_SELF:
- printf("被自己撞死了!");
- break;
- case END_NOMAL:
- printf("主动退出!");
- break;
- }
-
- while (cur)
- {
- pSnakeNode del = cur;
- cur = cur->next;
- free(del);
- }
- }
-
- void test()
- {
- char n = 0;
- srand((unsigned int)time(NULL));
- do
- {
- Snake Snake = { 0 };
- system("cls");
- //开始游戏
- GameStart(&Snake);
- //游戏运行
- GameRun(&Snake);
- //游戏结束
- GameEnd(&Snake);
- _SetPos(24, 17);
- printf("是否先后来一局?(Y/N)");
- n=getchar();
- } while (n=='Y');
- }
-
- int main()
- {
- setlocale(LC_ALL, "");//修改为本地模式(为了打印宽字符)
- test();
- _SetPos(0, 27);
- return 0;
- }
- #pragma once
-
- #include<windows.h>
- #include<string.h>
- #include<stdio.h>
- #include<stdlib.h>
- #include<stdbool.h>
- #include<locale.h>
- #include<assert.h>
- #include<time.h>
-
- #define POS_X 20
- #define POS_Y 8
- #define KEY_PRESS(VK) (GetAsyncKeyState(VK) &0X1 ? 1 : 0 )
-
-
- typedef struct SnakeNode
- {
- int x;
- int y;
- struct SnakeNode* next;
- }SnakeNode,* pSnakeNode;
-
- enum Direction
- {
- UP = 1,
- DOWN,
- LEFT,
- RIGHT
- };
-
- enum Game_Status
- {
- OK,//正常运行
- KILL_BY_WALL,//撞到墙
- KILL_BY_SELF,//撞到自己
- END_NOMAL//正常退出
- };
- typedef struct Snake
- {
- pSnakeNode _pSnake;//蛇的身体节点的指针
- pSnakeNode _pFood;//食物节点的指针
- enum Direction _Dir;//方向
- enum Game_Status _Status;//游戏状态
- int _Score;//总得分
- int _Food_Weight;//当前食物的分数
- int _SleepTime;//休息时间
- }Snake,* pSnake;
-
- //设置光标位置
- void _SetPos(short x, short y);
-
- //设置光标是否显示
- void _SetCursorInfo(bool a);
-
- //打印欢迎界面
- void WelcomeToGame();
-
- //打印地图
- void CreateMap();
-
- //创建节点
- pSnakeNode BuyNode(short x, short y);
-
- //初始化蛇身
- void InitSnake(pSnake ps);
-
- //创建第一个食物
- void CreateFood(pSnake ps);
-
- //打印右侧帮助信息
- void PrintInfo();
-
- //蛇的移动
- void SnakeMove(pSnake ps);
- #define _CRT_SECURE_NO_WARNINGS
-
- #include "Snake.h"
-
- //设置光标位置
- void _SetPos(short x, short y)
- {
- COORD pos = { x,y };
- HANDLE hOutput = NULL;
- //获取标准输出流句柄
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- //设置光标于所给参数位置
- SetConsoleCursorPosition(hOutput, pos);
- }
-
- //设置光标是否显示
- void _SetCursorInfo(bool a)
- {
- HANDLE hOutput = NULL;
- hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
- CONSOLE_CURSOR_INFO CursorInfo = { 0 };
- GetConsoleCursorInfo(hOutput, &CursorInfo);
- CursorInfo.bVisible = a;
- SetConsoleCursorInfo(hOutput, &CursorInfo);
- }
-
- //打印欢迎界面
- void WelcomeToGame()
- {
- _SetPos(41, 13);
- printf("欢迎来到贪吃蛇!\n");
- _SetPos(41, 25);
- system("pause");
- system("cls");
- _SetPos(15, 13);
- wprintf(L"按 ↑ . ↓ . ← . → 控制方向;");
- _SetPos(15, 14);
- wprintf(L"按F1加快移动速度并提升食物分数,按F2降低移动速度并减少食物分数;");
- _SetPos(15, 15);
- wprintf(L"按ESC退出游戏,按space暂停/继续游戏;");
- _SetPos(15, 16);
- wprintf(L"不能撞到墙或自己。");
- _SetPos(41, 25);
- system("pause");
- system("cls");
- }
-
- //打印地图
- void CreateMap()
- {
- _SetPos(0, 0);
- int i = 0;
- for (i = 0; i < 58; i += 2)
- {
- wprintf(L"%c", L'□');
- }
- _SetPos(0, 26);
- for (i = 0; i < 58; i += 2)
- {
- wprintf(L"%c", L'□');
- }
- for (i = 1; i < 26; i++)
- {
- _SetPos(0, i);
- wprintf(L"%c", L'□');
- _SetPos(56, i);
- wprintf(L"%c", L'□');
- }
- }
-
- //创建节点
- pSnakeNode BuyNode(short x, short y)
- {
- pSnakeNode cur = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (cur == NULL)
- {
- perror("InitSnake:: BuyNode::malloc");
- return NULL;
- }
- cur->x = x;
- cur->y = y;
- cur->next = NULL;
- return cur;
- }
-
- //初始化蛇身
- void InitSnake(pSnake ps)
- {
- //创建蛇身节点
- int i = 0;
- for (i = 0; i < 5; i++)
- {
- pSnakeNode cur = BuyNode((short)POS_X + i * 2, (short)POS_Y);
-
- if (ps->_pSnake == NULL)
- {
- ps->_pSnake = cur;
- }
- else
- {
- cur->next = ps->_pSnake;
- ps->_pSnake = cur;
- }
- }
-
- //打印蛇的身体
- pSnakeNode cur = NULL;
- cur = ps->_pSnake;
- while (cur)
- {
- _SetPos(cur->x, cur->y);
- wprintf(L"%c", L'●');
- cur = cur->next;
- }
- //初始化蛇的数据
- ps->_Dir = RIGHT;
- ps->_Food_Weight = 10;
- ps->_Score = 0;
- ps->_SleepTime = 200;
- ps->_Status = OK;
- }
-
- #define FOOD L'◆'
- //创建第一个食物
- void CreateFood(pSnake ps)
- {
- short x = 0;
- short y = 0;
- again:
- //随机生成食物节点坐标
- do
- {
- x = rand() % 53 + 2;
- y = rand() % 25 + 1;
- } while (x % 2 != 0);
- pSnakeNode cur = ps->_pSnake;
- //遍历蛇身,食物不能与蛇身重合
- while (cur)
- {
- if (cur->x == x && cur->y == y)
- {
- goto again;
- }
- cur = cur->next;
- }
- //创建食物
- pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pFood == NULL)
- {
- perror("pSnakeNode::malloc");
- return;
- }
- else
- {
- pFood->x = x;
- pFood->y = y;
- _SetPos(x, y);
- wprintf(L"%c", FOOD);
- ps->_pFood = pFood;
- }
- }
-
- //打印右侧帮助信息
- void PrintInfo()
- {
- _SetPos(62, 15);
- wprintf(L"按 ↑ . ↓ . ← . → 控制方向;");
- _SetPos(62, 16);
- wprintf(L"按F1加快移动速度并提升食物分数,");
- _SetPos(62, 17);
- wprintf(L"按F2降低移动速度并减少食物分数;");
- _SetPos(62, 18);
- wprintf(L"按ESC退出游戏,按space暂停/继续游戏;");
- _SetPos(62, 19);
- wprintf(L"不能撞到墙或自己。");
- }
-
- //判断下一个坐标是否是食物
- int NextIsFood(pSnakeNode nextnode, pSnake ps)
- {
- if ((ps->_pFood->x == nextnode->x) && (ps->_pFood->y == nextnode->y))
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
-
- //吃食物
- void EatFood(pSnakeNode nextnode, pSnake ps)
- {
- nextnode->next = ps->_pSnake;
- ps->_pSnake = nextnode;
- pSnakeNode cur = ps->_pSnake;
-
- while (cur)
- {
- _SetPos(cur->x, cur->y);
- wprintf(L"%c", L'●');
- cur = cur->next;
- }
- ps->_Score += ps->_Food_Weight;
- free(ps->_pFood);
- //创建新食物
- CreateFood(ps);
- }
-
- //不是食物
- void NoFood(pSnakeNode nextnode, pSnake ps)
- {
- nextnode->next = ps->_pSnake;
- ps->_pSnake = nextnode;
- pSnakeNode cur = ps->_pSnake;
- while (cur->next->next)
- {
- _SetPos(cur->x, cur->y);
- wprintf(L"%c", L'●');
- cur = cur->next;
- }
- pSnakeNode del = cur->next;
- cur->next = NULL;
- _SetPos(del->x, del->y);
- printf(" ");
- free(del);
- del = NULL;
- }
-
- void KillByWall(pSnake ps)
- {
- if ((ps->_pSnake->x == 0) || (ps->_pSnake->x == 56) || (ps->_pSnake->y == 0) || (ps->_pSnake->y == 26))
- {
- ps->_Status = KILL_BY_WALL;
- }
- }
-
- void KillBySelf(pSnake ps)
- {
- pSnakeNode cur = ps->_pSnake->next;
- while (cur)
- {
- if ((cur->x == ps->_pSnake->x) && (cur->y == ps->_pSnake->y))
- {
- ps->_Status = KILL_BY_SELF;
- }
- cur = cur->next;
- }
- }
-
- //蛇的移动
- void SnakeMove(pSnake ps)
- {
- pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));
- if (pNextNode == NULL)
- {
- perror("SnakeMove::malloc");
- return;
- }
- //确定下⼀个节点的坐标,下⼀个节点的坐标根据,蛇头的坐标和⽅向确定
- switch(ps->_Dir)
- {
- case UP:
- {
- pNextNode->x = ps->_pSnake->x;
- pNextNode->y = ps->_pSnake->y - 1;
- }
- break;
- case DOWN:
- {
- pNextNode->x = ps->_pSnake->x;
- pNextNode->y = ps->_pSnake->y + 1;
- }
- break;
- case LEFT:
- {
- pNextNode->x = ps->_pSnake->x-2;
- pNextNode->y = ps->_pSnake->y;
- } break;
- case RIGHT:
- {
- pNextNode->x = ps->_pSnake->x+2;
- pNextNode->y = ps->_pSnake->y;
- }
- break;
- }
- //如果下一个位置是食物
- if (NextIsFood(pNextNode, ps))
- {
- //吃食物
- EatFood(pNextNode, ps);
- }
- else//不是食物
- {
- NoFood(pNextNode, ps);
- }
- KillByWall(ps);
- KillBySelf(ps);
- }
使用上述代码在VS环境下就可以实现一个简单的贪吃蛇小游戏了,喜欢的朋友可以点赞收藏呦。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。