practice_code/Snakes/main.c

375 lines
12 KiB
C
Raw Normal View History

2023-12-02 21:13:39 +08:00
#include <stdio.h>
#include <unistd.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
2023-12-04 20:17:44 +08:00
#define map_Longitudinal 27//地图高度
#define map_across 102//地图宽度
2023-12-02 21:13:39 +08:00
int integral = 0;//玩家积分
2023-12-04 20:17:44 +08:00
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//标记为食物
2023-12-02 21:13:39 +08:00
2023-12-04 20:17:44 +08:00
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;//全局声明得分
2023-12-02 21:13:39 +08:00
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 ); //设置光标信息
}
2023-12-04 20:17:44 +08:00
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 );
}
2023-12-02 21:13:39 +08:00
void food_map ()//在动图上生成食物
{
int i = rand ( ) % map_Longitudinal;//随机食物纵坐标
int j = rand ( ) % map_across;//随机食物横坐标
2023-12-04 20:17:44 +08:00
int random = rand ( ) % 14 + 1;//随机生成颜色
if ( map[ i ][ j ] == mark_NULL )//监测到有物体就重新生成
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
map[ i ][ j ] = mark_food; // 正确标记食物
color ( random );
CursorJump ( i , j );
printf ( "" );
2023-12-02 21:13:39 +08:00
}
else
{
2023-12-04 20:17:44 +08:00
food_map ( );
2023-12-02 21:13:39 +08:00
}
}
void move ( int move_x , int move_y )//移动逻辑
{
2023-12-04 20:17:44 +08:00
color ( 10 ); //颜色设置为绿色
if ( pick_food == 0 )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
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;//增加积分
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
//将最后一个取消
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 ( " " );
2023-12-02 21:13:39 +08:00
//更新蛇身坐标
2023-12-04 20:17:44 +08:00
for ( int i = body -> length - 1 ; i > 0 ; -- i )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
body -> x[ i ] = body -> x[ i - 1 ];
body -> y[ i ] = body -> y[ i - 1 ];
2023-12-02 21:13:39 +08:00
}
body -> x[ 0 ] = head -> x;
body -> y[ 0 ] = head -> y;
//将蛇头原来的坐标替换为身体
2023-12-04 20:17:44 +08:00
CursorJump ( head -> y , head -> x );
printf ( "" );
2023-12-02 21:13:39 +08:00
//更新蛇头坐标
head -> x += move_x;
head -> y += move_y;
//把蛇头的坐标在地图更新
2023-12-04 20:17:44 +08:00
map[ head -> y ][ head -> x ] = mark_snake;//标记蛇
CursorJump ( head -> y , head -> x );
printf ( "" );
if ( pick_food == 0 )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
food_map ( );
print_score ( );//重新打印积分
pick_food = 1;
2023-12-02 21:13:39 +08:00
}
}
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 );
}
}
2023-12-04 20:17:44 +08:00
void initial_snake ()//初始蛇
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
color ( 10 ); //颜色设置为绿色
2023-12-02 21:13:39 +08:00
//初始化蛇头
head -> x = 10;
head -> y = 10;
//初始化蛇身
body -> x[ 1 ] = 9;
body -> y[ 1 ] = 10;
body -> x[ 0 ] = 8;
body -> y[ 0 ] = 10;
2023-12-04 20:17:44 +08:00
body -> length = 2;
2023-12-02 21:13:39 +08:00
//生成蛇的图像
2023-12-04 20:17:44 +08:00
//蛇头
map[ head -> y ][ head -> x ] = mark_snake;//标记蛇
CursorJump ( head -> y , head -> x );
printf ( "" );
//蛇身
for ( int i = body -> length - 1 ; i >= 0 ; -- i )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
map[ body -> y[ i ] ][ body -> x[ i ] ] = mark_snake;//标记蛇
CursorJump ( body -> y[ i ] , body -> x[ i ] );
printf ( "" );
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
void print_map ()//初始地图
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
color ( 12 );
2023-12-02 21:13:39 +08:00
for ( int i = 0 ; i < map_Longitudinal ; ++ i )
{
2023-12-04 20:17:44 +08:00
if ( i == 0 || i == map_Longitudinal - 1 )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
for ( int j = 0 ; j < map_across ; ++ j )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
//打印墙并且标记状态为墙
map[ i ][ j ] = mark_wall;
printf ( "" );
2023-12-02 21:13:39 +08:00
}
printf ( "\n" );
}
2023-12-04 20:17:44 +08:00
else
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
for ( int j = 0 ; j < map_across ; ++ j )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
if ( j == 0 || j == map_across - 1 )//打印边界
{
//打印墙并且标记状态为墙
map[ i ][ j ] = mark_wall;
printf ( "" );
}
else
{
map[ i ][ j ] = mark_NULL;//标记为空
printf ( " " );//输出地图
}
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
printf ( "\n" );
2023-12-02 21:13:39 +08:00
}
}
2023-12-04 20:17:44 +08:00
2023-12-02 21:13:39 +08:00
}
int defeat ()//失败界面
{
2023-12-04 20:17:44 +08:00
CursorJump ( 10 , 50 );
printf ( "\n\t\t\t—————————游戏失败—————————\n" );
2023-12-02 21:13:39 +08:00
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
{
2023-12-04 20:17:44 +08:00
MAX_integral = integral;//保存最大积分
return 5;
2023-12-02 21:13:39 +08:00
}
}
int main ()
{
2023-12-04 20:17:44 +08:00
HideCursor ( );//隐藏光标
2023-12-02 21:13:39 +08:00
game_Begin:
2023-12-04 20:17:44 +08:00
system ( "cls" );
score = ( game_Integral * ) malloc ( sizeof ( game_Integral ) );//动态分配光标内存
2023-12-02 21:13:39 +08:00
head = ( snake_head * ) malloc ( sizeof ( snake_head ) );// 动态分配蛇头内存
body = ( snake_body * ) malloc ( sizeof ( snake_body ) );// 动态分配蛇头内存
2023-12-04 20:17:44 +08:00
score -> x = 1;//积分横坐标
score -> y = map_Longitudinal;//积分纵坐标
score -> MAX_x = map_across - 13;//最大积分横坐标
2023-12-02 21:13:39 +08:00
srand ( time ( NULL ) );//设置随机数
2023-12-04 20:17:44 +08:00
char direction_test = 'd';//方向接收
char direction = 'd';//方向
2023-12-02 21:13:39 +08:00
int move_x = 0;//更新移动所产生的横坐标
int move_y = 0;//更新移动所产生的纵坐标
2023-12-04 20:17:44 +08:00
int pick = 0;//接收是否重开游戏
print_map ( );//打印当前地图
print_score ( );//打印积分
initial_snake ( );//生成蛇
food_map ( );//在动图上生成食物
2023-12-02 21:13:39 +08:00
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' )//判断方向对不对
{
2023-12-04 20:17:44 +08:00
direction = direction_test;//更新移动方向
2023-12-02 21:13:39 +08:00
}
}
2023-12-04 20:17:44 +08:00
2023-12-02 21:13:39 +08:00
//判断移动的坐标
if ( direction == 'W' || direction == 'w' )//判断向上
{
if ( move_y == 1 )
{
move_x = 0;//更新移动所产生的横坐标
move_y = 1;//更新移动所产生的纵坐标
}
else
{
2023-12-04 20:17:44 +08:00
if ( map[ head -> y - 1 ][ head -> x ] == mark_snake ||
map[ head -> y - 1 ][ head -> x ] == mark_wall )//判断有没有失败
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick = defeat ( );
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
if ( map[ head -> y - 1 ][ head -> x ] == mark_food )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick_food = 0;//提示食物没有了
2023-12-02 21:13:39 +08:00
}
move_x = 0;//更新移动所产生的横坐标
move_y = - 1;//更新移动所产生的纵坐标
}
}
else if ( direction == 'S' || direction == 's' )//判断向下
{
if ( move_y == - 1 )
{
move_x = 0;//更新移动所产生的横坐标
move_y = - 1;//更新移动所产生的纵坐标
}
else
{
2023-12-04 20:17:44 +08:00
if ( map[ head -> y + 1 ][ head -> x ] == mark_wall ||
map[ head -> y + 1 ][ head -> x ] == mark_snake )//判断有没有失败
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick = defeat ( );
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
if ( map[ head -> y + 1 ][ head -> x ] == mark_food )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick_food = 0;//提示食物没有了
2023-12-02 21:13:39 +08:00
}
move_x = 0;//更新移动所产生的横坐标
move_y = 1;//更新移动所产生的纵坐标
}
}
2023-12-04 20:17:44 +08:00
else if ( direction == 'A' || direction == 'a' )//判断向左
2023-12-02 21:13:39 +08:00
{
if ( move_x == 1 )
{
move_x = 1;//更新移动所产生的横坐标
move_y = 0;//更新移动所产生的纵坐标
}
else
{
2023-12-04 20:17:44 +08:00
if ( map[ head -> y ][ head -> x - 1 ] == mark_wall ||
map[ head -> y ][ head -> x - 1 ] == mark_snake )//判断有没有失败
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick = defeat ( );
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
if ( map[ head -> y ][ head -> x - 1 ] == mark_food )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick_food = 0;//提示食物没有了
2023-12-02 21:13:39 +08:00
}
move_x = - 1;//更新移动所产生的横坐标
move_y = 0;//更新移动所产生的纵坐标
}
}
2023-12-04 20:17:44 +08:00
else if ( direction == 'D' || direction == 'd' )//判断右
2023-12-02 21:13:39 +08:00
{
if ( move_x == - 1 )
{
move_x = - 1;//更新移动所产生的横坐标
move_y = 0;//更新移动所产生的纵坐标
}
else
{
2023-12-04 20:17:44 +08:00
if ( map[ head -> y ][ head -> x + 1 ] == mark_wall ||
map[ head -> y ][ head -> x + 1 ] == mark_snake )//判断有没有失败
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick = defeat ( );
2023-12-02 21:13:39 +08:00
}
2023-12-04 20:17:44 +08:00
if ( map[ head -> y ][ head -> x + 1 ] == mark_food )
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
pick_food = 0;//提示食物没有了
2023-12-02 21:13:39 +08:00
}
move_x = 1;//更新移动所产生的横坐标
move_y = 0;//更新移动所产生的纵坐标
}
}
2023-12-04 20:17:44 +08:00
if ( pick == 5 || direction_test == 'R' || direction_test == 'r' )//判断是否重开游戏
2023-12-02 21:13:39 +08:00
{
2023-12-04 20:17:44 +08:00
system ( "cls" );
integral = 0;//重置玩家积分
free ( score );
free ( head );
free ( body );
2023-12-02 21:13:39 +08:00
goto game_Begin;
}
move ( move_x , move_y );//将坐标移动
Sleep ( 80 );//停顿一秒
}
return 0;
2023-12-04 20:17:44 +08:00
}