375 lines
12 KiB
C
375 lines
12 KiB
C
#include <stdio.h>
|
||
#include <unistd.h>
|
||
#include <conio.h>
|
||
#include <stdlib.h>
|
||
#include <time.h>
|
||
#include <windows.h>
|
||
|
||
#define map_Longitudinal 27//地图高度
|
||
#define map_across 102//地图宽度
|
||
int integral = 0;//玩家积分
|
||
int MAX_integral = 0;//最高积分
|
||
int pick_food = 1;//判断地图上有没有食物
|
||
int map[map_Longitudinal][map_across];//储存地图状态
|
||
#define mark_NULL 0//标记空
|
||
#define mark_snake 1//标记蛇
|
||
#define mark_wall 2//标记墙
|
||
#define mark_food 3//标记为食物
|
||
|
||
void color ( int c )//颜色设置
|
||
{
|
||
SetConsoleTextAttribute ( GetStdHandle ( STD_OUTPUT_HANDLE ) , c ); //颜色设置
|
||
//注:SetConsoleTextAttribute是一个API(应用程序编程接口)
|
||
}
|
||
|
||
typedef struct
|
||
{
|
||
int y;//纵坐标
|
||
int x;//横坐标
|
||
int MAX_x;//横坐标
|
||
} game_Integral;//得分
|
||
|
||
game_Integral * score;//全局声明得分
|
||
|
||
typedef struct
|
||
{
|
||
int y;//纵坐标
|
||
int x;//横坐标
|
||
} snake_head;//蛇头
|
||
|
||
snake_head * head;//全局声明蛇头
|
||
|
||
typedef struct
|
||
{
|
||
int y[99];//纵坐标
|
||
int x[99];//横坐标
|
||
int length;//蛇身体长度
|
||
} snake_body;//蛇身
|
||
|
||
snake_body * body;//全局声明蛇身
|
||
|
||
void HideCursor ()//隐藏光标
|
||
{
|
||
CONSOLE_CURSOR_INFO curInfo; //定义光标信息的结构体变量
|
||
curInfo . dwSize = 1; //如果没赋值的话,光标隐藏无效
|
||
curInfo . bVisible = FALSE; //将光标设置为不可见
|
||
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE ); //获取控制台句柄
|
||
SetConsoleCursorInfo ( handle , & curInfo ); //设置光标信息
|
||
}
|
||
|
||
void CursorJump ( int y , int x )//光标跳转
|
||
{
|
||
COORD pos; //定义光标位置的结构体变量
|
||
pos . X = x; //横坐标
|
||
pos . Y = y; //纵坐标
|
||
HANDLE handle = GetStdHandle ( STD_OUTPUT_HANDLE ); //获取控制台句柄
|
||
SetConsoleCursorPosition ( handle , pos ); //设置光标位置
|
||
}
|
||
|
||
void print_score ()//打印积分
|
||
{
|
||
color ( 14 );
|
||
CursorJump ( score -> y , score -> x );
|
||
printf ( "\n当前积分为%d分\n" , integral );
|
||
CursorJump ( score -> y + 1 , score -> MAX_x );
|
||
printf ( "最高积分为%d分\n" , MAX_integral );
|
||
}
|
||
|
||
void food_map ()//在动图上生成食物
|
||
{
|
||
int i = rand ( ) % map_Longitudinal;//随机食物纵坐标
|
||
int j = rand ( ) % map_across;//随机食物横坐标
|
||
int random = rand ( ) % 14 + 1;//随机生成颜色
|
||
if ( map[ i ][ j ] == mark_NULL )//监测到有物体就重新生成
|
||
{
|
||
map[ i ][ j ] = mark_food; // 正确标记食物
|
||
color ( random );
|
||
CursorJump ( i , j );
|
||
printf ( "●" );
|
||
}
|
||
else
|
||
{
|
||
food_map ( );
|
||
}
|
||
}
|
||
|
||
void move ( int move_x , int move_y )//移动逻辑
|
||
{
|
||
color ( 10 ); //颜色设置为绿色
|
||
if ( pick_food == 0 )
|
||
{
|
||
body -> x[ body -> length ] = body -> x[ body -> length - 1 ];
|
||
body -> y[ body -> length ] = body -> y[ body -> length - 1 ];
|
||
map[ body -> y[ body -> length ] ][ body -> x[ body -> length ] ] = mark_snake;//标记蛇
|
||
body -> length += 1;//增加蛇身体长度
|
||
integral += 10;//增加积分
|
||
}
|
||
//将最后一个取消
|
||
map[ body -> y[ body -> length - 1 ] ][ body -> x[ body -> length - 1 ] ] = mark_NULL;//标记为空
|
||
CursorJump ( body -> y[ body -> length - 1 ] , body -> x[ body -> length - 1 ] );
|
||
printf ( " " );
|
||
//更新蛇身坐标
|
||
for ( int i = body -> length - 1 ; i > 0 ; -- i )
|
||
{
|
||
body -> x[ i ] = body -> x[ i - 1 ];
|
||
body -> y[ i ] = body -> y[ i - 1 ];
|
||
}
|
||
body -> x[ 0 ] = head -> x;
|
||
body -> y[ 0 ] = head -> y;
|
||
//将蛇头原来的坐标替换为身体
|
||
CursorJump ( head -> y , head -> x );
|
||
printf ( "□" );
|
||
//更新蛇头坐标
|
||
head -> x += move_x;
|
||
head -> y += move_y;
|
||
//把蛇头的坐标在地图更新
|
||
map[ head -> y ][ head -> x ] = mark_snake;//标记蛇
|
||
CursorJump ( head -> y , head -> x );
|
||
printf ( "■" );
|
||
if ( pick_food == 0 )
|
||
{
|
||
food_map ( );
|
||
print_score ( );//重新打印积分
|
||
pick_food = 1;
|
||
}
|
||
}
|
||
|
||
void Begin ()//开始界面
|
||
{
|
||
printf ( "\n\n\n\n\n\n\n\n\t\t\t\t\t——————————贪吃蛇——————————\n" );
|
||
printf ( "\t\t\t\t\t|使用WSAD进行上下左右移动|\n" );
|
||
printf ( "\t\t\t\t\t|按ESC退出游戏 |\n" );
|
||
printf ( "\t\t\t\t\t|回车进入游戏 |\n" );
|
||
printf ( "\t\t\t\t\t——————————贪吃蛇——————————\n" );
|
||
int a = _getch ( );
|
||
if ( a == 27 )
|
||
{
|
||
exit ( 0 );
|
||
}
|
||
}
|
||
|
||
void initial_snake ()//初始蛇
|
||
{
|
||
color ( 10 ); //颜色设置为绿色
|
||
//初始化蛇头
|
||
head -> x = 10;
|
||
head -> y = 10;
|
||
//初始化蛇身
|
||
body -> x[ 1 ] = 9;
|
||
body -> y[ 1 ] = 10;
|
||
body -> x[ 0 ] = 8;
|
||
body -> y[ 0 ] = 10;
|
||
body -> length = 2;
|
||
//生成蛇的图像
|
||
//蛇头
|
||
map[ head -> y ][ head -> x ] = mark_snake;//标记蛇
|
||
CursorJump ( head -> y , head -> x );
|
||
printf ( "■" );
|
||
//蛇身
|
||
for ( int i = body -> length - 1 ; i >= 0 ; -- i )
|
||
{
|
||
map[ body -> y[ i ] ][ body -> x[ i ] ] = mark_snake;//标记蛇
|
||
CursorJump ( body -> y[ i ] , body -> x[ i ] );
|
||
printf ( "□" );
|
||
}
|
||
|
||
}
|
||
|
||
void print_map ()//初始地图
|
||
{
|
||
color ( 12 );
|
||
for ( int i = 0 ; i < map_Longitudinal ; ++ i )
|
||
{
|
||
if ( i == 0 || i == map_Longitudinal - 1 )
|
||
{
|
||
for ( int j = 0 ; j < map_across ; ++ j )
|
||
{
|
||
//打印墙并且标记状态为墙
|
||
map[ i ][ j ] = mark_wall;
|
||
printf ( "█" );
|
||
}
|
||
printf ( "\n" );
|
||
}
|
||
else
|
||
{
|
||
for ( int j = 0 ; j < map_across ; ++ j )
|
||
{
|
||
if ( j == 0 || j == map_across - 1 )//打印边界
|
||
{
|
||
//打印墙并且标记状态为墙
|
||
map[ i ][ j ] = mark_wall;
|
||
printf ( "█" );
|
||
}
|
||
else
|
||
{
|
||
map[ i ][ j ] = mark_NULL;//标记为空
|
||
printf ( " " );//输出地图
|
||
}
|
||
}
|
||
printf ( "\n" );
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
int defeat ()//失败界面
|
||
{
|
||
CursorJump ( 10 , 50 );
|
||
printf ( "\n\t\t\t—————————游戏失败—————————\n" );
|
||
printf ( "\t\t\t|按ESC退出游戏 |\n" );
|
||
printf ( "\t\t\t|其他键继续游戏 |\n" );
|
||
printf ( "\t\t\t—————————游戏失败—————————\n" );
|
||
int a = _getch ( );
|
||
if ( a == 27 )
|
||
{
|
||
exit ( 0 );
|
||
}
|
||
else
|
||
{
|
||
MAX_integral = integral;//保存最大积分
|
||
return 5;
|
||
}
|
||
|
||
|
||
}
|
||
|
||
int main ()
|
||
{
|
||
HideCursor ( );//隐藏光标
|
||
|
||
game_Begin:
|
||
system ( "cls" );
|
||
score = ( game_Integral * ) malloc ( sizeof ( game_Integral ) );//动态分配光标内存
|
||
head = ( snake_head * ) malloc ( sizeof ( snake_head ) );// 动态分配蛇头内存
|
||
body = ( snake_body * ) malloc ( sizeof ( snake_body ) );// 动态分配蛇头内存
|
||
score -> x = 1;//积分横坐标
|
||
score -> y = map_Longitudinal;//积分纵坐标
|
||
score -> MAX_x = map_across - 13;//最大积分横坐标
|
||
srand ( time ( NULL ) );//设置随机数
|
||
char direction_test = 'd';//方向接收
|
||
char direction = 'd';//方向
|
||
int move_x = 0;//更新移动所产生的横坐标
|
||
int move_y = 0;//更新移动所产生的纵坐标
|
||
int pick = 0;//接收是否重开游戏
|
||
print_map ( );//打印当前地图
|
||
print_score ( );//打印积分
|
||
initial_snake ( );//生成蛇
|
||
food_map ( );//在动图上生成食物
|
||
while ( 1 )
|
||
{
|
||
if ( _kbhit ( ) )//接收用户输入
|
||
{
|
||
direction_test = _getch ( );
|
||
if ( direction_test == 'W' || direction_test == 'w' || direction_test == 'S' || direction_test == 's' ||
|
||
direction_test == 'A' || direction_test == 'a' || direction_test == 'D' ||
|
||
direction_test == 'd' )//判断方向对不对
|
||
{
|
||
direction = direction_test;//更新移动方向
|
||
}
|
||
}
|
||
|
||
|
||
//判断移动的坐标
|
||
if ( direction == 'W' || direction == 'w' )//判断向上
|
||
{
|
||
if ( move_y == 1 )
|
||
{
|
||
move_x = 0;//更新移动所产生的横坐标
|
||
move_y = 1;//更新移动所产生的纵坐标
|
||
}
|
||
else
|
||
{
|
||
if ( map[ head -> y - 1 ][ head -> x ] == mark_snake ||
|
||
map[ head -> y - 1 ][ head -> x ] == mark_wall )//判断有没有失败
|
||
{
|
||
pick = defeat ( );
|
||
}
|
||
if ( map[ head -> y - 1 ][ head -> x ] == mark_food )
|
||
{
|
||
pick_food = 0;//提示食物没有了
|
||
}
|
||
move_x = 0;//更新移动所产生的横坐标
|
||
move_y = - 1;//更新移动所产生的纵坐标
|
||
}
|
||
}
|
||
else if ( direction == 'S' || direction == 's' )//判断向下
|
||
{
|
||
if ( move_y == - 1 )
|
||
{
|
||
move_x = 0;//更新移动所产生的横坐标
|
||
move_y = - 1;//更新移动所产生的纵坐标
|
||
}
|
||
else
|
||
{
|
||
if ( map[ head -> y + 1 ][ head -> x ] == mark_wall ||
|
||
map[ head -> y + 1 ][ head -> x ] == mark_snake )//判断有没有失败
|
||
{
|
||
pick = defeat ( );
|
||
}
|
||
if ( map[ head -> y + 1 ][ head -> x ] == mark_food )
|
||
{
|
||
pick_food = 0;//提示食物没有了
|
||
}
|
||
move_x = 0;//更新移动所产生的横坐标
|
||
move_y = 1;//更新移动所产生的纵坐标
|
||
}
|
||
}
|
||
else if ( direction == 'A' || direction == 'a' )//判断向左
|
||
{
|
||
if ( move_x == 1 )
|
||
{
|
||
move_x = 1;//更新移动所产生的横坐标
|
||
move_y = 0;//更新移动所产生的纵坐标
|
||
}
|
||
else
|
||
{
|
||
if ( map[ head -> y ][ head -> x - 1 ] == mark_wall ||
|
||
map[ head -> y ][ head -> x - 1 ] == mark_snake )//判断有没有失败
|
||
{
|
||
pick = defeat ( );
|
||
}
|
||
if ( map[ head -> y ][ head -> x - 1 ] == mark_food )
|
||
{
|
||
pick_food = 0;//提示食物没有了
|
||
}
|
||
move_x = - 1;//更新移动所产生的横坐标
|
||
move_y = 0;//更新移动所产生的纵坐标
|
||
}
|
||
}
|
||
else if ( direction == 'D' || direction == 'd' )//判断右
|
||
{
|
||
if ( move_x == - 1 )
|
||
{
|
||
move_x = - 1;//更新移动所产生的横坐标
|
||
move_y = 0;//更新移动所产生的纵坐标
|
||
}
|
||
else
|
||
{
|
||
if ( map[ head -> y ][ head -> x + 1 ] == mark_wall ||
|
||
map[ head -> y ][ head -> x + 1 ] == mark_snake )//判断有没有失败
|
||
{
|
||
pick = defeat ( );
|
||
}
|
||
if ( map[ head -> y ][ head -> x + 1 ] == mark_food )
|
||
{
|
||
pick_food = 0;//提示食物没有了
|
||
}
|
||
move_x = 1;//更新移动所产生的横坐标
|
||
move_y = 0;//更新移动所产生的纵坐标
|
||
}
|
||
}
|
||
|
||
if ( pick == 5 || direction_test == 'R' || direction_test == 'r' )//判断是否重开游戏
|
||
{
|
||
system ( "cls" );
|
||
integral = 0;//重置玩家积分
|
||
free ( score );
|
||
free ( head );
|
||
free ( body );
|
||
goto game_Begin;
|
||
}
|
||
move ( move_x , move_y );//将坐标移动
|
||
Sleep ( 80 );//停顿一秒
|
||
}
|
||
return 0;
|
||
} |