重点:
蛇的移动是先更新蛇身和蛇头坐标,再重新画蛇实现,此过程在循环中进行
snake.h
#pragma once
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <Windows.h>
#define WIDE 60
#define HIGH 20
//设计蛇身体和头
struct BODY {
int X;
int Y;
}; //一节蛇头或蛇身对应1个坐标
//设计蛇
struct SNAKE {
struct BODY body[WIDE * HIGH];//蛇头+蛇身的上限是铺满整个界面,body[0][0]代表蛇头,其他代表蛇身
int size;//蛇头+蛇身的节数
}snake;//顺便创建条全局蛇变量
//设计食物,一个食物对应1个坐标
struct FOOD {
int X;
int Y;
}food;//顺便创建一个全局食物变量
//int score = 0;//游戏得分
//
//int kx = 0; //用户按下awsd任意键所得到的坐标值
//int ky = 0;
//
//int sleepTime = 300; //记录控制蛇移动速度的睡眠秒数
//
//int tailX = 0; //蛇尾坐标
//int tailY = 0;
//初始化蛇
void initSnake();
//初始化食物
void initFood();
//画蛇和食物
void initUI();
//画墙
void initWall();
//开始游戏
void playGame();
//显示分数
void showScore();
snake.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
int score = 0;//游戏得分
int kx = 0; //用户按下awsd任意键所得到的坐标值
int ky = 0;
int sleepTime = 300; //记录控制蛇移动速度的睡眠秒数
int tailX = 0; //蛇尾坐标
int tailY = 0;
void initSnake()//初始化蛇
{
//设置蛇长度
snake.size = 2;
//设置蛇头坐标
snake.body[0].X = WIDE / 2;
snake.body[0].Y = HIGH / 2;
//设置蛇第一节身体的坐标
snake.body[1].X = WIDE / 2 - 1;
snake.body[1].Y = HIGH / 2;
}
void initFood()//初始化食物
{
//设置食物坐标
food.X = rand() % WIDE;//0~59
food.Y = rand() % HIGH;//0~19
}
void initUI()//画蛇和食物
{
COORD coord = { 0, 0 };
//画蛇
for (size_t i = 0; i < snake.size; i++)
{
coord.X = snake.body[i].X;
coord.Y = snake.body[i].Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//设置控制台光标起始位置
if (i == 0)
{
putchar('@');//画蛇头
}
else
{
putchar('*');//画蛇身
}
}
//去除蛇尾
coord.X = tailX;
coord.Y = tailY;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//设置控制台光标起始位置
putchar(' ');
//画食物
coord.X = food.X;
coord.Y = food.Y;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//设置控制台光标起始位置
putchar('#');
}
void initWall()//画墙
{
for (size_t i = 0; i <= HIGH; i++)
{
for (int j = 0; j <= WIDE; j++)
{
if (j == WIDE)
{
printf("|");
}
else if (i == HIGH)
{
printf("_");
}
else
{
printf(" ");
}
}
printf("\n");
}
}
void playGame()
{
//设置蛇的默认移动方向
char key = 'd';
//判断蛇撞墙
while (snake.body[0].X >= 0 && snake.body[0].X < WIDE
&& snake.body[0].Y >= 0 && snake.body[0].Y < HIGH)
{
//刷新画蛇
initUI();
//接收用户的按键输入 awsd
if (_kbhit())//不阻塞响应键盘输入,为真时说明用户按下按键
{
key = _getch();//不回显接收字符
}
switch (key)//根据用户按下不同按键得到不同坐标值
{
case 'a': kx = -1; ky = 0; break;
case 'w': kx = 0; ky = -1; break;
case 's': kx = 0; ky = +1; break;
case 'd': kx = +1; ky = 0; break;
default: break;
}
//蛇头撞身体,蛇头坐标==任意一节蛇身坐标
for (size_t i = 1; i < snake.size; i++)
{
if (snake.body[0].X == snake.body[i].X && snake.body[0].Y == snake.body[i].Y)
return;//游戏结束
}
//蛇头撞食物
if (snake.body[0].X == food.X && snake.body[0].Y == food.Y)
{
initFood();//刷新食物
snake.size++;//身体增长
score += 10;//加分
sleepTime -= 100;//蛇移动速度加快
}
//存储蛇尾坐标
tailX = snake.body[snake.size - 1].X;
tailY = snake.body[snake.size - 1].Y;
//蛇移动,前1节身体给后1节身体赋值
for (int i = snake.size -1; i >0; i--)
{
snake.body[i].X = snake.body[i - 1].X;
snake.body[i].Y = snake.body[i - 1].Y;
}
//根据用户按键修改蛇头坐标
snake.body[0].X += kx;
snake.body[0].Y += ky;
Sleep(sleepTime);//控制蛇移动速度
}
}
void showScore()//显示分数
{
//移动控制台光标至墙外
COORD coord;
coord.X = 0;
coord.Y = HIGH + 1;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);//设置控制台光标起始位置
printf("Game Over\n");
printf("此次成绩:%d\n", score);
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "snake.h"
int main()
{
//隐藏控制台光标,设置一次即可生效
CONSOLE_CURSOR_INFO cci;
cci.dwSize = sizeof(cci);
cci.bVisible = FALSE;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
srand((unsigned int)time(NULL));//设置随机数生成起点
initSnake();//初始化蛇
initFood();//初始化食物
initWall();//画墙
initUI();//画蛇和食物
playGame();//开始游戏
showScore();//显示分数
return 0;
}