贪吃蛇部分
三个角度分析贪吃蛇的主要组成部分
数据
界面
控制器
数据分析
1:只有一条蛇
2:每次屏幕上只有一个食物
3:每(300毫秒)往前走一步
目标界面
蛇
食物
墙
游戏界面
蛇结构体
坐标系中的坐标
蛇的每个节点结构
蛇的运动方向蛇本身
{
蛇头
蛇尾
蛇方向
}
食物
墙
游戏结构本身
game
{
蛇
食物
蛇的当前得分
每个食物的得分
蛇的速度 sleeptime
}伪代码部分
int gamerun
{
//初始化工作
1、蛇初始化
蛇的身子
蛇的方向
2、食物生成
边界之内。
不能和蛇重叠
随机
3、基本数据初始化(得分、速度等)while(1)
{
下个格子坐标
给蛇加一格,给蛇的结构体加上下一个格子的坐标
1、蛇会前进
2、如果按方向键,蛇能改变方向
3、可能会吃到食物
1、蛇增长
2、重新生成食物
3、加分
//游戏结束
1。撞墙
2。撞自己
3。ESC退出
}
}
其中要使用到的Windows函数
Windows函数
键盘接收函数 接收异步状态
GetAsyncKetState
SHORT WINAPI GetAsyncKeyState(In int vKey);
返回值 按住不放 返回一个很复杂的数 按过一次返回1 没按过返回0
示例
#include <Windows.h>
while(1)
{
SHORT r=GetAsyncKeyState(VK_UP);
printf("%d\n",r);
Sleep(300);
}
//调用标准输出函数
//hStdout 就是平时看到的stdout,类型不一样
//stdout FILE * 类型
//hStdout HANDLE 类型
移动光标函数
SetConsoleCursorPosition
设置控制台光标坐标
原型
BOOL WINAPI SetConsoleCursorPosition
(
_In_ HANDLE hconsoleoutput GetStdHandle
_In_ COORD dwCursorPosition
);
示例
移动光标函数 得到标准句柄
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE)
int i;
COORD coord;
for(i=0; i<6;i++)
{
coord.X = 2 * i;
coord.Y = i;
SetConsoleCursorPosition(hStdout, coord);
printf("%d",i);
}
控制输出框的界面大小
mod con cols = 10 line = 20
system("mode con cols=60 lines=30");
改变输出字体颜色函数
SetConsoleTextAttribute
设置控制台文本属性
#include <Windows.h>
#include <stdio.h>
int main()
{ //控制台 句柄
HANDLE consolehwnd =GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(consolehwnd,FOREGROUND_INTENSITY|FOREGROUND_RED);
printf("RED");
return 0;
}
FOREGROUND_RED 表示设置前景色为红色,即字体颜色为红色
//前景
FOREGROUND_INTENSITY表示设置前景色为高亮显示,FOREGROUND_GREEN表示绿色,两个参数中间加|表示前景色为高亮绿色 //前景
BACKGROUND_INTENSITY表示设置背景色为高亮显示,BACKGROUND_BULE表示背景色为蓝色
要表示红色字体,白色背景可以使用
SetConsoleTextAttribute(GetStdHandle(STD_OUT_HANDLE),BACKGROUND_INTENSITY|FOREGROUND_INTENSITY|FOREGROUND_RED|BACKGROUND_RED|BACKGROUND_GREEN|BACKGROUND_BULE)
https://blog.csdn.net/sum7mer/article/details/79003631
播放音乐使用步骤连接
#include"resource.h"//导入资源之后有一个resource.h头文件 记得加上
#include<Windows.h>
#include<mmsystem.h>
#pragma comment(lib,"winmm.lib")
int main()
{
PlaySound(LPWSTR(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP);
//PlaySound(MAKEINTRESOURCE(IDR_WAVE1), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC | SND_LOOP);
* //上面两种方式都可以 IDR_WAVE1 是导入资源的ID
* //下面针对第三个参数做一下解释
* //SND_RESOURCE 表示使用的资源文件(如果是文本文件 exe要带上一个音乐文件才能实现音乐播放)
* //SND_ASYNC 异步播放
* //SND_LOOP 循环播放 必须要用到SND_ASYNC
return 0;
}
正式代码
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <Windows.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")
#define ROW (28)
#define COL (28)
//每个节点坐标
typedef struct Pos
{
int x;
int y;
}Pos;
//蛇的方向
typedef enum FangXiang
{
UP,DOWN,LEFT,RIGHT
}FX;
//蛇每个节点结构体
typedef struct SnakeNode
{
Pos pos;
struct SnakeNode *pNext;
}SnakeNode;
//蛇结构体
typedef struct Snake
{
SnakeNode *pHead;
SnakeNode *pTail;
FX fx;
}Snake;
//游戏结构体
typedef struct Game
{
Snake snake;
Pos FoodPos;
int score;
int scorePerFood;
int sleeptime;
}Game;
void Move(int x, int y);
void DelSnakeBlock(Pos pos);
void PrintSnakeBlock(Pos pos);
//初始化蛇体,生成位置,蛇体长度等
void SnakeInit(Snake *snake)
{
Pos pos;
int i = 0;
SnakeNode *snakenode;
snake->pHead = NULL;
for(i=0; i<3; i++)
{
pos.x = 5+i;
pos.y = 5;
snakenode = (SnakeNode *)malloc(sizeof(SnakeNode));
assert(snakenode);
snakenode->pos = pos;
snakenode->pNext = snake->pHead;
snake->pHead = snakenode;
}
snake->pTail = snake->pHead->pNext->pNext;
snake->fx = RIGHT;
}
//生成食物时,是否与蛇体重叠
int IsOverlapSnake(int x, int y, Snake *snake)
{
SnakeNode *pNode;
pNode = snake->pHead;
while(pNode != NULL)
{
if(pNode->pos.x == x && pNode->pos.y == y)
return 1;
pNode = pNode->pNext;
}
return 0;
}
//初始化食物
void FoodInit(Pos *pos, Snake *snake)
{
int x,y;
do{
x = rand() % (ROW-1);
y = rand() % (COL-1);
}while(IsOverlapSnake(x,y,snake));
pos->x = x;
pos->y = y;
}
//初始化
void GameInit(Game *game)
{
SnakeInit(&game->snake);
FoodInit(&game->FoodPos,&game->snake);
game->score = 10;
game->scorePerFood = 10;
game->sleeptime = 300;
}
//判断蛇的下一步走到哪个格子
Pos GetNextPos(Snake *snake)
{
Pos pos = snake->pHead->pos;
if(snake->fx == RIGHT)
{
pos.x += 1;
return pos;
}
else if(snake->fx == UP)
{
pos.y -= 1;
return pos;
}
else if(snake->fx == DOWN)
{
pos.y += 1;
return pos;
}
else
{
pos.x -= 1;
return pos;
}
}
//判断是否吃到食物
int IsEatFood(Pos pos1,Pos pos)
{
return pos1.x == pos.x && pos1.y == pos.y;
}
//吃到食物,增加一格
void SnakeAdd(Snake *snake,Pos pos)
{
SnakeNode *pNode = (SnakeNode *)malloc(sizeof(SnakeNode));
assert(pNode);
pNode->pos = pos;
pNode->pNext = snake->pHead;
snake->pHead = pNode;
PrintSnakeBlock(pos);
}
//蛇前进
void SnakeRemoveTail(Snake *snake)
{
SnakeNode *pNode;
pNode = snake->pHead;
while(pNode->pNext->pNext != NULL)
{
pNode = pNode->pNext;
}
DelSnakeBlock(pNode->pNext->pos);
free(pNode->pNext);
pNode->pNext = NULL;
}
//是否撞墙
int IsKillByWall(Pos pos)
{
if(pos.x < 0)
return 1;
if(pos.y < 0)
return 1;
if(pos.x > ROW-2)
return 1;
if(pos.y > COL-2)
return 1;
return 0;
}
//是否撞到自己
int IsSuicide(Snake *snake)
{
Pos pos = snake->pHead->pos;
SnakeNode *pNode = snake->pHead->pNext;
while(pNode != NULL)
{
if(pNode->pos.x == pos.x && pNode->pos.y == pos.y)
return 1;
pNode = pNode->pNext;
}
return 0;
}
//暂停函数
void StopRun()
{
while(1)
{
Sleep(300);
if(GetAsyncKeyState(VK_SPACE))
{
return;
}
}
}
//移动光标
void Move(int x, int y)
{
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
COORD coord;
coord.X = x;
coord.Y = y;
SetConsoleCursorPosition(hStdout, coord);
}
//字符颜色
//生成蓝色
void PrintColorBlue()
{
HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_BLUE);
}
//生成红色
void PrintColorRed()
{
HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_RED);
}
//生成绿色
void PrintColorGreen()
{
HANDLE c = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(c,FOREGROUND_INTENSITY|FOREGROUND_GREEN);
}
//打印墙体
void PrintWall()
{
int i=0;
//上方
system("cls");
Move(2,1);
for(i=0; i<ROW;i++)
{
Sleep(20);
PrintColorBlue();
printf("█");
}
//下方
Move(2,COL+2);
for(i=0; i<ROW+1;i++)
{
Sleep(20);
PrintColorBlue();
printf("█");
}
//左方
for(i=0; i<COL+1; i++)
{
Sleep(20);
Move(2,i+1);
PrintColorBlue();
printf("█");
}
//右方
for(i=0; i<COL+1; i++)
{
Sleep(20);
Move((ROW+1)*2,i+1);
PrintColorBlue();
printf("█");
}
Move((ROW+1)*2+20,COL/2);
PrintColorRed();
printf("↑↓←→移动");
Move((ROW+1)*2+20,COL/2+2);
printf("F1加速、F2减速");
Move((ROW+1)*2+20,COL/2+4);
printf("按空格键暂停,再按一次继续游戏");
Move((ROW+1)*2+20,COL/2+8);
printf("当前得分%-3d,食物得分%-2d",10,10);
}
//打印蛇增加的那部分
void PrintSnakeAdd(Pos pos)
{
PrintColorGreen();
Move((pos.x+1)*2+2,pos.y+2);
printf("█");
}
//擦除蛇走过的部分
void PrintDelSnake(Snake *snake)
{
SnakeNode *pNode;
pNode = snake->pHead;
while(pNode->pNext->pNext != NULL)
{
pNode = pNode->pNext;
}
Move((pNode->pos.x+1)*2+2,pNode->pos.y+2);
printf(" ");
}
//打印食物
void Printfood(Pos pos)
{
Move((pos.x+1)*2+2,pos.y+2);
PrintColorRed();
printf("¤");
}
//打印一格蛇
void PrintSnakeBlock(Pos pos)
{
PrintColorGreen();
Move((pos.x+1)*2+2,pos.y+2);
printf("█");
}
//擦除一格蛇
void DelSnakeBlock(Pos pos)
{
Move((pos.x+1)*2+2,pos.y+2);
printf(" ");
}
//打印蛇
void PrintfSnake(Snake *snake)
{
SnakeNode *pNode = snake->pHead;
while(pNode != NULL)
{
PrintSnakeBlock(pNode->pos);
pNode = pNode->pNext;
}
}
//欢迎函数,打印墙体
void Welcome()
{
char str[] = "这是你没有玩过的船新版本我是渣渣辉我在贪吃蛇等你";
int i = 0;
PrintColorRed();
Move((ROW+1)*2-2*7,COL/2);
for(i=0; i < 24 ;i=i+2)
{
Sleep(50);
printf("%c%c",str[i],str[i+1]);
}
Move((ROW+1)*2-2*4+1,COL/2+2);
Sleep(500);
for(i=24; i < 34;i=i+2)
{
Sleep(20);
printf("%c%c",str[i],str[i+1]);
}
Sleep(500);
Move((ROW+1)*2-2*5+1,COL/2+4);
for(i=34; i < 48;i=i+2)
{
Sleep(20);
printf("%c%c",str[i],str[i+1]);
}
Sleep(1500);
Move((ROW+1)*2-2*5,COL/2+6);
printf("什么?我没在中间?");
system("mode con cols=100 lines=40");
Sleep(800);
Move((ROW+1)*2-2*5,COL/2+7);
printf("我还没在中间?");
Sleep(800);
system("mode con cols=120 lines=40");
Move((ROW+1)*2-2*5,COL/2+7);
printf("这下好了");
Move((ROW+1)*2-2*5,COL/2+8);
system("pause");
}
void run()
{
char buf[2] = {0};
Game game;
Pos pos;
//bgm函数
PlaySound("D:\\1C作业\\Snake\\Snake\\Legend.wav",NULL,SND_FILENAME|SND_ASYNC);
START:
PrintWall();
GameInit(&game);
Printfood(game.FoodPos);
PrintfSnake(&(game.snake));
while(1)
{
//根据按键方向
if(GetAsyncKeyState(VK_UP) && game.snake.fx != DOWN){
game.snake.fx = UP;
}else if(GetAsyncKeyState(VK_DOWN) && game.snake.fx != UP){
game.snake.fx = DOWN;
}else if(GetAsyncKeyState(VK_RIGHT) && game.snake.fx != LEFT){
game.snake.fx = RIGHT;
}else if(GetAsyncKeyState(VK_LEFT) && game.snake.fx != RIGHT){
game.snake.fx = LEFT;
}
if(GetAsyncKeyState(VK_SPACE)){
StopRun();
}
//按esc退出游戏
if(GetAsyncKeyState(VK_ESCAPE)){
Move((ROW+1)+1-2*2,COL/2);
printf("游戏结束");
break;
}
//按F1F2加速减速
if(GetAsyncKeyState(VK_F1)){
if(game.sleeptime >=200)
if(game.scorePerFood <= 20)
game.scorePerFood += 10;
if(game.sleeptime >= 100)
game.sleeptime -= 20;
}
if(GetAsyncKeyState(VK_F2)){
if(game.sleeptime <= 600)
game.sleeptime += 20;
}
//game->snake.fx = RIGHT;
//下一个格子坐标是什么
pos = GetNextPos(&(game.snake));
//判断蛇是否吃到食物
if(IsEatFood(game.FoodPos,pos))
{
//吃到了 蛇加一节 没吃到继续刷新蛇
//先删除最后的尾巴,再往蛇头加下一个坐标
SnakeAdd(&(game.snake),pos);
FoodInit(&(game.FoodPos),&game.snake);
Printfood(game.FoodPos);
game.score += game.scorePerFood;
//Move((ROW+1)*2+3,COL/2+8);
Move((ROW+1)*2+20,COL/2+8);
PrintColorRed();
printf("当前得分%-3d,食物得分%-2d",game.score,game.scorePerFood);
}
else
{
SnakeRemoveTail(&(game.snake));
SnakeAdd(&(game.snake),pos);
}
//是否撞墙
if(IsKillByWall(pos))
{
Move((ROW+1)+1-2*6,COL/2);
printf("撞墙了,游戏结束");
break;
}
////是否撞自己
if(IsSuicide(&(game.snake)))
{
Move((ROW+1)+1-2*8,COL/2);
printf("撞到自己了,游戏结束");
break;
}
//睡眠时间
Sleep(game.sleeptime);
}
}
//主要调用函数
void test()
{
//调用音乐函数
PlaySound("D:\\1C作业\\Snake\\Snake\\Remember (Original Mix) - Sensitive_Bogdan Bondarenko.wav",NULL,SND_FILENAME|SND_ASYNC);
Welcome();
srand((unsigned)time(NULL));
run();
Move(0,COL+3);
printf("\n");
}
引入音乐自动带出来的头文件
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by she.rc
//
#define IDR_WAVE1 101
#define IDR_WAVE2 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif
名存实亡的主函数
#include "Snake.h"
int main()
{
test();
}
跑起来的样子: