C語言實現簡易版貪喫蛇,通過移除蛇尾和打印新的蛇頭來實現移動效果,可以避免刷新整個蛇身的閃屏現象。
下面分別是頭文件和實現文件:
#ifndef SNAKE_H_INCLUDED
#define SNAKE_H_INCLUDED
/***************************************************
* 文件名:snake.h
* 描 述:定義遊戲的核心方法及相關結構
* 創建人:777
* 日 期:2018-01-01
* 版 本:1.0
*
**************************************************/
#define MARGIN_X 25 //遊戲界面左邊距
#define up 'w' //蛇的移動方向
#define down 's'
#define left 'a'
#define right 'd'
#define stop 'p'
/*
*蛇身結構
*/
typedef struct _snake{
int x; //節點座標
int y;
struct _snake * next;
}SNAKE;
//聲明蛇頭蛇尾
SNAKE *head,*tail;
/*
*食物結構
*/
struct Food
{
int x;
int y;
}food;
//聲明蛇的移動速度和蛇長變量
int speed;
/*
*遊戲歡迎界面
*/
void welcome();
/*
*顯示地圖
*/
void creatmap();
/*
*生成蛇
*/
void showsnake();
/*
*生成食物
*/
void creatfood();
/*
*遊戲運行
*/
void playgame();
/*
*打印蛇身,參數爲座標和背景顏色
*/
void gotoprint(int x, int y,int a, int b);
/*
*清除一個點(蛇尾和食物)
*/
void gotodelete(int x, int y);
/*
*移動蛇
*/
void MovingBody(char click);
/*
*移動蛇身
*/
void ChangeBody(int a,int b);
/*
*喫屎
*/
void Eating();
/*
*結束判斷
*/
int Judge();
/*
*結束遊戲
*/
void gameover();
#endif // SNAKE_H_INCLUDED
#ifndef SNAKELIB_H_INCLUDED
#define SNAKELIB_H_INCLUDED
/***************************************************
* 文件名:GameLib.h
* 描 述:定義遊戲中常用的控制檯操作
* 創建人:777
* 日 期:2018-01-01
* 版 本:1.0
*
**************************************************/
/* 設置控制檯窗口標題 */
void SetTitle(char * title);
/* 設置控制檯窗口顏色 */
void SetColor(int, int);
/* 設置控制檯窗口尺寸 */
void SetConsoleWindowSize(int width, int height);
/* 設置光標的x、y座標-正常座標軸 */
void SetPosition(int x, int y);
/* 清屏 */
void Clear(int X, int Y);
#endif // SNAKELIB_H_INCLUDED
/***************************************************
* 文件名:GameLib.c
* 描 述:GameLib.h的實現文件
* 創建人:777
* 日 期:2018-01-01
* 版 本:1.0
*
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <windows.h>
#include "snakeLib.h"
/*
*設置窗口標題
*/
void SetTitle(char * title)
{
SetConsoleTitle(title);
}
/*
*設置窗口顏色
*/
void SetColor(int ForeColor, int BackGroundColor)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //獲取當前窗口句柄
SetConsoleTextAttribute(handle, ForeColor + BackGroundColor * 0x10);//設置顏色
}
/*
*設置窗口大小
*/
void SetConsoleWindowSize(int width, int height)
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
//設置控制檯窗口的緩衝區大小
COORD size = {width, height};
SetConsoleScreenBufferSize(handle, size);
//設置控制檯窗口大小,最大座標是緩衝區大小-1
SMALL_RECT rect = {0, 0, width-1, height-1};
SetConsoleWindowInfo(handle, 1, &rect);
}
/*
*設置光標位置
*/
void SetPosition(int x, int y)
{
COORD cursorPosition; //光標的座標
HANDLE handle; //當前窗口句柄
handle = GetStdHandle(STD_OUTPUT_HANDLE);
cursorPosition.X = x; //設置x、y座標
cursorPosition.Y = y;
SetConsoleCursorPosition(handle, cursorPosition);
}
/*
*清屏函數,參數爲開始的行數和列數
*/
void Clear(int X, int Y)
{
DWORD written;
COORD start; //開始座標
HANDLE handle; //當前窗口句柄
handle = GetStdHandle(STD_OUTPUT_HANDLE);
start.X = X;
start.Y = Y;
FillConsoleOutputAttribute(handle, 15, 120*35, start, &written);
FillConsoleOutputCharacter(handle, ' ', 120*35, start, &written);
SetConsoleCursorPosition(handle, start);
}
#include "snake.h"
#include "snakeLib.h"
int main()
{
welcome();
creatmap();
creatfood();
playgame();
gameover();
return 0;
}
/***************************************************
* 文件名:snake.c
* 描 述:實現遊戲的核心玩法
* 創建人:777
* 日 期:2018-01-01
* 版 本:1.0
*
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>
#include "snake.h"
#include "snakeLib.h"
/*
*運行遊戲
*/
void playgame()
{
char click; //用戶按鍵
while (1)
{
if (Judge()== 0) break; //判斷遊戲是否結束
//kbhit()函數,檢查當前是否有鍵盤輸入,若有則返回一個非0值,否則返回0。
if (_kbhit()) click = _getch();
MovingBody(click);
Eating();
}
}
/*
*生成食物
*/
void creatfood()
{
srand((int)time(NULL));
lable:
food.y = rand() % 28 + 3;
food.x = rand() % 52 + MARGIN_X + 7;
if (food.x % 2 != 0)
{
food.x = food.x + 1;
}
SNAKE *judgement = head;
while (1) //遍歷排除蛇身重複
{
if (judgement->next == NULL) break;
if (food.x == judgement->x && food.y == judgement->y)
{
goto lable;
}
judgement = judgement->next;
}
gotoprint(food.x, food.y,7,0); //參數分別是X,Y座標和打印的背景顏色
}
/*
*打印遊戲地圖
*/
void creatmap()
{
int i;
for (i = 0; i<58; i += 2)//打印上下邊框
{
gotoprint(i + MARGIN_X + 5, 2, 4,0);
gotoprint(i + MARGIN_X + 5, 32, 4,0);
}
for (i = 1; i < 30; i++)
{
gotoprint(0 + MARGIN_X + 5, i + 2, 4,0);
gotoprint(56 + MARGIN_X + 5, i + 2, 4,0);
}
//創建蛇頭
head = (SNAKE*)malloc(sizeof(SNAKE));
head->x = 15 + MARGIN_X + 10;
head->y = 15;
gotoprint(head->x, head->y,10, 0);
//創建蛇尾
tail = (SNAKE*)malloc(sizeof(SNAKE));
//創建蛇身
SNAKE *body = (SNAKE*)malloc(sizeof(SNAKE));
body->x = 15 + MARGIN_X + 10;
body->y = 16;
head->next = body;
body->next = tail;
gotoprint(body->x, body->y,10, 0);
//head->next = tail;
tail->next = NULL;
tail->x = 15 + MARGIN_X + 10;
tail->y = 17;
gotoprint(tail->x, tail->y,10, 0);
}
/*
*遊戲歡迎界面實現
*/
void welcome()
{
SetConsoleWindowSize(121, 36); //設置窗口大小
SetTitle("貪喫蛇1.0"); //設置標題
SetPosition(MARGIN_X,10);
/*歡迎界面 */
printf("/***************************************************************/");
SetPosition(MARGIN_X, 20);
printf("/***************************************************************/");
SetPosition(MARGIN_X + 18, 13);
printf("歡迎來到貪喫蛇小遊戲");
SetPosition(MARGIN_X, 16);
printf("請在英文輸入法中操作,wasd控制蛇移動方向,反向移動等同於喫到自己,其他鍵暫停遊戲");
SetPosition(MARGIN_X + 20, 18);
printf("按任意鍵開始遊戲");
_getch();
Clear(0,0);
}
/*
*打印蛇身
*/
void gotoprint(int x, int y, int a,int b)
{
SetColor(a, b);
SetPosition(x, y);
printf("■");
}
/*
*清除一個點(蛇尾和食物)
*/
void gotodelete(int x, int y)
{
SetPosition(x, y);
printf(" ");
}
/*
*判斷遊戲是否結束
*/
int Judge()
{
if (head->x == (MARGIN_X + 5)|| head->x == (MARGIN_X +61) || head->y == 2 || head->y == 32)
{
return 0;
}
SNAKE *p = head->next;
while (1)
{
//通過遍歷蛇身座標,與蛇頭座標對比,判斷蛇頭是否撞到蛇身
if (head->x == p->x && head->y == p->y)
{
return 0;
}
if (p->next == NULL) break; //遍歷完成退出循環
p = p->next;
}
return 1;
}
/*
*移動蛇,參數爲用戶按鍵
*/
void MovingBody(char click)
{
int count = 0; //記錄蛇長
int a = head->x, b = head->y; //記錄蛇頭座標
SNAKE *p = head;
//通過清除蛇尾實現動畫效果,注意在運動轉態才清除蛇尾,暫停時不清除
if(click == up || click == down || click == right || click == left)
{
while (1)
{
count++;
if (p->next == NULL)
{
gotodelete(p->x, p->y);
break;
}
p = p->next;
}
}
switch (click)
{
case up:
head->y -= 1;
ChangeBody(a,b);
break;
case down:
head->y += 1;
ChangeBody(a,b);
break;
case left:
head->x -= 2;
ChangeBody(a,b);
break;
case right:
head->x += 2;
ChangeBody(a,b);
break;
default:
break;
}
//打印新的蛇頭
p = head;
gotoprint(p->x, p->y,10,0);
if (count <= 10) speed = 150;
else if (count > 10 && count <= 20) speed = 100;
else if (count > 20 && count <= 40) speed = 50;
else speed = 10;
Sleep(speed);
}
/*
*移動蛇身
*/
void ChangeBody(int a,int b)
{
SNAKE *p = head->next;
int mid1, mid2,_mid1,_mid2;
mid1 = p->x;
mid2 = p->y;
while (1)
{
if (p->next == NULL) break;
_mid1 = p->next->x;
_mid2 = p->next->y;
p->next->x = mid1;
p->next->y = mid2;
mid1 = _mid1;
mid2 = _mid2;
p = p->next;
}
p = head->next;
p->x = a;
p->y = b;
}
/*
*喫屎
*/
void Eating()
{
if (head->x == food.x && head->y == food.y)
{
creatfood();
SNAKE * _new = (SNAKE*)malloc(sizeof(SNAKE));
_new->next = NULL;
SNAKE *p;
p = head;
while (1)
{
if (p->next == NULL) break;
p = p->next;
}
p->next = _new;
}
}
/*
*結束
*/
void gameover()
{
Clear(0,0);
SetPosition(MARGIN_X + 10,15);
SetColor(10,0);
printf("遊戲結束!");
}