贪吃蛇2.0(双人版)

zyl 喵星人 2023-12-17 19:03:08 2024-02-05 14:46:34 45
#include<iostream>
#include<conio.h>
#include<windows.h>
using namespace std;

#define W 60
#define H 40

// 函数声明
void setPos(int x,int y);  // 设置光标位置
void COLOR_PRINT(const char* s, int color); // 带颜色的输出

char key;
int FPS = 200;
int Foodx, Foody, Foodt=0;
int speed = (220-FPS)/20;

struct Body{
	int x,y;
};

struct Player{
	int len;   // 长度
	int speed; // 速度
	int HP;    // 血量
	int dir;   // 移动方向 1 2 3 4
	int color; // 蛇头的颜色
	Body body[W*H]; // 身体结构体
	
	// 初始化
	void init(int _len, int x, int y, int hp, int c){
		// 初始化蛇
		color = c;
		HP = hp;
		dir = 2;
		len = _len;
		body[0].x = x;
		body[0].y = y;
		for(int i=1;i<len;i++){
			body[i].x = body[i-1].x;
			body[i].y = body[i-1].y - 1;
		}
	}
	// 移动
	void move(){
		int dx = 0, dy = 0;
		if(dir == 1) dy = -1;
		else if(dir == 2) dy = 1;
		else if(dir == 3) dx = -1;
		else if(dir == 4) dx = 1;
		setPos(body[len-1].x*2,body[len-1].y);
		printf("  ");
		for(int i=len-1;i>=1;i--){
			body[i].x = body[i-1].x;
			body[i].y = body[i-1].y;
		}
		body[0].x = body[0].x + dx;
		body[0].y = body[0].y + dy;	
	}
	// 吃到食物
	void eatFood(int& foodx, int& foody, int& foodt){
		if(body[0].x == foodx && body[0].y == foody){
			len++;
			for(int i=len-1;i>=1;i--){
				body[i].x = body[i-1].x;
				body[i].y = body[i-1].y;
			}
			body[0].x = foodx;
			body[0].y = foody;
			setPos(foodx*2,foody);
			printf("  ");
			if(foodt == 1) HP++;
			else if(foodt != 0) FPS += foodt; 
			foodx = foody = foodt = 0;
		}
	}
	// 画出蛇身
	void draw(){
		for(int i=0;i<len;i++){
			setPos(body[i].x*2,body[i].y);
			//		printf("■");
			if(i == 0) COLOR_PRINT("", color);
			else COLOR_PRINT("", 14);
		}
	}
	// 游戏
	void isOver(const Player& p2){
		// 撞墙
		if(body[0].x >= W-1 || body[0].x <= 0 || body[0].y >= H-1 || body[0].y <= 0){
			HP = 0;
			return;
		}
		// 撞到别人
		for(int i=0;i<p2.len;i++){
			if(body[0].x == p2.body[i].x && body[0].y == p2.body[i].y){
				HP--;
				return;
			}
		}
	}
	// 更新
	void update(){
		move();
		eatFood(Foodx, Foody, Foodt);
		draw();
	}
	
};

//     玩家1 和 玩家2
Player player1, player2;

// 设置光标位置
void setPos(int x,int y)  {
	CONSOLE_SCREEN_BUFFER_INFO csbiInfo;                            
	HANDLE hConsoleOut;
	hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
	GetConsoleScreenBufferInfo(hConsoleOut,&csbiInfo);
	csbiInfo.dwCursorPosition.X = x;                                    
	csbiInfo.dwCursorPosition.Y = y;                                    
	SetConsoleCursorPosition(hConsoleOut,csbiInfo.dwCursorPosition);
}

// 带颜色的输出
void COLOR_PRINT(const char* s, int color){
	HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | color);
	printf(s);
	SetConsoleTextAttribute(handle, FOREGROUND_INTENSITY | 7);
}

// 随机生成食物
void createFood(){
	srand(time(0));
	int seed = rand()%10+1;
	if(seed>=5) Foodt = 0; // 普通食物,只加长度
	else if(seed == 1 || seed == 2) Foodt = 1; // 特殊食物,增加血量
	else if(seed == 3)Foodt = 20; // 特殊食物,加快游戏速度
	else if(seed == 4)Foodt = -20; // 特殊食物,加快游戏速度
	Foodx = rand()%(W-2)+1;
	Foody = rand()%(H-2)+1;
}

// 初始化
void init(){
	player1.init(4, 4, 4, 3, 4);
	player2.init(4, W-5, 4, 3, 1);
	createFood();
}

void info(){
	setPos(W*2+4, 3);
	printf("游戏说明:\n");
	setPos(W*2+4, 5);
	printf("玩家1:按W A S D操控\n");
	setPos(W*2+4, 7);
	printf("玩家2:按小键盘↑ ↓ ← → 操控\n");
	setPos(W*2+4, 9);
	printf("玩家1血量:%d\n", player1.HP);
	setPos(W*2+4, 11);
	printf("玩家2血量:%d\n", player2.HP);
	setPos(W*2+4, 13);
	printf("当前游戏速度等级:%d\n", speed);
}

// 游戏更新
void update(){
	// 画地图
	for(int i=0;i<W;i++){
		for(int j=0;j<H;j++){
			if(i==0 || j==0 || i == W-1 || j == H-1) {
				setPos(i*2,j);
				printf("");
			}
		}
	}
	// 画食物
	setPos(Foodx*2,Foody);
	//	printf("■");
	COLOR_PRINT("", 10);
	// 更新游戏数据
	FPS = min(FPS, 200);
	FPS = max(FPS, 60);
	speed = (220-FPS)/20;
	info();
}

// 游戏结束判断
bool GemeStatus(){
	if(player1.HP == 0){
		setPos((W+1)/2,(H-1)/2);
		COLOR_PRINT("游戏结束!,玩家2胜利,获得:", 4);
		printf("%d", player2.HP*speed*100);
		setPos(0,H+2);
		return 1;
	}
	else if(player2.HP == 0){
		setPos((W+1)/2,(H-1)/2);
		COLOR_PRINT("游戏结束!,玩家1胜利,获得:", 4);
		printf("%d", player1.HP*speed*100);
		setPos(0,H+2);
		return 1;
	}
	return false;
}

// 按键响应
void keydown(){
	while(kbhit()) key = _getch();
	if((key == 'w' || key == 'W') && player1.dir!=2) player1.dir = 1;
	else if((key == 's' || key == 'S') && player1.dir!=1) player1.dir = 2;
	else if((key == 'a' || key == 'A') && player1.dir!=4) player1.dir = 3;
	else if((key == 'd' || key == 'D') && player1.dir!=3) player1.dir = 4;
	if(key == 72 && player2.dir != 2) player2.dir = 1;
	else if(key == 80 && player2.dir != 1) player2.dir = 2;
	else if(key == 75 && player2.dir != 4) player2.dir = 3;
	else if(key == 77 && player2.dir != 3) player2.dir = 4;
}

void Game(){
	init();
	while(1){
		update();
		keydown();
		player1.update();
		player2.update();
		if(Foodx==0 && Foody==0) createFood();
		player1.isOver(player2);
		player2.isOver(player1);
		if(GemeStatus()) break;
		Sleep(FPS);
	}
}

void menu(){
	int t = 6;
	COLOR_PRINT("抵制不良游戏,拒绝盗版游戏。 \n\n", 11);
	COLOR_PRINT("注意自我保护,谨防受骗上当。 \n\n", 11);
	COLOR_PRINT("适度游戏益脑,沉迷游戏伤身。 \n\n", 11);
	COLOR_PRINT("合理安排时间,享受健康生活。 \n\n", 11);
	
	while(t--!=1){
		COLOR_PRINT("正在加载中,", t);
		printf("%d",t);
		COLOR_PRINT("秒后进入游戏...\n", t);
		Sleep(1000);
	}
	system("pause");
	system("cls");
	printf("以下是游戏介绍,请认真阅读哦!\n");
	printf("1、游戏可以两个玩家一起对战,玩家1在左边,玩家2在右边。\n");
	printf("2、关于操作,玩家1使用W、A、S、D, 玩家2使用小键盘的上、下、左、右。\n");
	COLOR_PRINT("3、在按键时请不要长按键盘,不然会影响游戏体验。需要转向时按一下键盘即可,即使你长按也没用,蛇会自己移动。\n",4);
	printf("4、地图边框出现问号时,说明你的黑窗口不支持中文,需要以旧版控制台运行。\n");
	printf("5、游戏地图会闪,说明你的屏幕比较小或者没有全屏,需要把代码6、7行中的数字改的小一点(W表示地图的宽,H表示地图的高。)\n");
	COLOR_PRINT("6、读到这条请将你的电脑全屏,以便获得更好的游戏体验。\n\n",4);
	printf("游戏规则:\n");
	printf("1、每个玩家开始的生命值为3。\n");
	COLOR_PRINT("2、撞到地图的墙,生命值直接归零。\n",4);
	COLOR_PRINT("3、自己撞到自己不会死,撞到对手身体扣一滴血。\n",4);
	printf("4、当有任意一方生命值为零时,游戏结束。\n\n");
	printf("食物介绍:\n");
	printf("目前共有4种食物:\n");
	printf("1、普通食物,生成概率为60%%\n");
	printf("2、加一滴血食物,生成概率为20%%\n");
	printf("3、游戏加速食物,生成概率为10%%\n");
	printf("4、游戏减速食物,生成概率为10%%\n");
	printf("5、食物每次只会生成一个,吃到了才会生成下一个食物。\n");
	printf("6、不同食物没有区分,以盲盒形式存在(主要是我懒,不想写代码了^_^)。\n");
	printf("7、当你读到这条请再次确认是否全屏,以便获得更好的游戏体验。\n\n");
	system("pause");
	system("cls");
}


int main(){
	menu();
	Game();
	system("pause");
	return 0;
}

持续更新。。。

欢迎找bug

{{ vote && vote.total.up }}

共 7 条回复

lyhldy MineC++raft

好像少加了一个ctime文件(别问我怎么知道的,随机数大佬)

lyq123 星空寂静

@zyl z老师尼想不想活了!还是有错!

tctm157

134还是有错

zyl 喵星人

把NULL改成0就可以了,已修复

tctm160

134有错

CPP 刷题王

6

ykj43

134行报错了→←