practice_code/Snakes/main.c
2023-12-04 20:17:44 +08:00

375 lines
12 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}