实现简易飞行棋

第一次自己写这样的大作业,代码风格真的很重要。例如函数的封装性很重要,不然后期很容易无法维护,加一点功能就容易出一堆bug~

在这边完成了简易的图形化,并且其中可以选择人数,自带一个电脑玩家(还挺容易让电脑玩家赢得哈哈哈哈哈哈)写电脑玩家的时候就是按照我自己玩的思维方式写的~还挺有趣的,欢迎尝试。

head.h

#pragma once
#ifndef HEAD_H
#define HEAD_H
#include <conio.h>
#include<graphics.h>
#include <cstdlib>
#include <ctime>
#include<windows.h>
#include<mmsystem.h>

//#pragma comment (lib,"winmm.lib")

class Plane{
public:
	int x;  //飞机的x坐标
	int y;  //飞机的y坐标

	void init_plane(int player);  //初始化飞机的坐标
	void draw_plane(int player);  //画出飞机的图像
};


Plane player_plane[4][4];         //每个玩家各有四架飞机
						               
int go_pos[4][4] = { {0,0,0,0},   //这个数组记录每架飞机的坐标(也就是所在格子的位置)
					 {0,0,0,0},
					 {0,0,0,0},
					 {0,0,0,0} }; //这个数组用于标记该飞机是否到达终点,若到达终点 那么就不再动这架飞机
int get_end[4][4] = { {0,0,0,0},
					  {0,0,0,0},
					  {0,0,0,0},
					  {0,0,0,0} };

Plane plane;
int player = 4;         //记录玩家的个数

int num = 0;             //记录每轮得到的数字
int turn = 0;            //记录摇了多少次骰子
int pos_x = 0;           //记录要移动的位置的x坐标
int pos_y = 0;           //记录要移动的位置的y坐标
int now_i = -1;          //记录当前要移动的飞机是哪一位玩家的
int now_j = -1;          //记录当前要移动该玩家的哪一架飞机
int tmp_j = 0;           //存储上一轮AI启动的飞机(为第j架)
int flag_3 = 0;          //判断上一次AI是否启动了飞机 若启动了飞机则这次只能移动这个飞机
int winner = -1;
bool sixpts = false;
char AInum = ' ';


void Plane::init_plane(int player)//初始化飞机坐标
{
	switch (player)
	{
	case 4: 
	{
		
		int idx = 0;
		for (int i = 1; i <= 2; i++)
			for (int j = 1; j <= 2; j++)
			{
				player_plane[3][idx].x = 50 + i * 50;
				player_plane[3][idx].y = 100 + j * 50;
				idx++;
			}
	}
	case 3:
	{
		
		int idx = 0;
		for (int i = 1; i <= 2; i++)
			for (int j = 1; j <= 2; j++)
			{
				player_plane[2][idx].x = 50 + i * 50;
				player_plane[2][idx].y = 250 + j * 50;
				idx++;
			}
	}
	case 2:
	{
		
		int idx = 0;
		for (int i = 1; i <= 2; i++)
			for (int j = 1; j <= 2; j++)
			{
				player_plane[1][idx].x = 50 + i * 50;
				player_plane[1][idx].y = 400 + j * 50;
				idx++;
			}
	}
	case 1:
	{

		int idx = 0;
		for (int i = 1; i <= 2; i++)
			for (int j = 1; j <= 2; j++)
			{
				player_plane[0][idx].x = 50 + i * 50;
				player_plane[0][idx].y = 550 + j * 50;
				idx++;
			}
	}
	}
}

void Plane::draw_plane(int player) //画出飞机
{
	for (int i = 0; i < 4; i++)
	{
		setfillcolor(GREEN);
		solidcircle(player_plane[0][i].x, player_plane[0][i].y, 25);
		rectangle(75, 575, 175, 675);


		setfillcolor(RED);
		solidcircle(player_plane[1][i].x, player_plane[1][i].y, 25);
		rectangle(75, 425, 175, 525);

		if (player >= 3)
		{
			setfillcolor(YELLOW);
			solidcircle(player_plane[2][i].x, player_plane[2][i].y, 25);
			rectangle(75, 275, 175, 375);
		}
		if (player == 4)
		{
			setfillcolor(BLUE);
			solidcircle(player_plane[3][i].x, player_plane[3][i].y, 25);
			rectangle(75, 125, 175, 225);
		}
	}
}

class Board {
public:
	void init_draw(int player);    //画出基础的格子

	void draw_button();            //画出Board上的按钮

	void draw_event();             //画出Board上的event框架
};

void Board::draw_event()   //画出时间对话框  各种事件的显示 放在Setting的show_event里
{
	setlinecolor(BLACK);
	rectangle(250, 100, 800, 300);

}

void Board::draw_button()  //画出两个按钮以及上面的文字
{
	setfillcolor(BLACK);
	setlinecolor(BLACK);
	for (int i = 1; i <= 4; i++)
		rectangle(200 + i * 100,600, 300 + i * 100, 700);
	
	rectangle(800, 550, 1000, 750);

	//在button上显示文字
	setbkmode(TRANSPARENT);
	settextstyle(70, 50, "Comic Sans MS");
	settextcolor(RED);
	outtextxy(325, 615, '2');
	settextcolor(GREEN);
	outtextxy(425, 615, '3');
	settextcolor(BLUE);
	outtextxy(525, 615, '4');
	settextcolor(BLACK);
	settextstyle(45, 20, "Comic Sans MS");
	outtextxy(610, 605, "RE");
	outtextxy(610, 645, "SET");
	settextstyle(55, 25, "Comic Sans MS");
	outtextxy(820, 570, "PUSH");
	outtextxy(820, 620, "TO");
	outtextxy(820, 670, "ROLL");
}

void Board::init_draw(int player) //画出赛道
{
	setbkcolor(WHITE);
	cleardevice();
	setlinecolor(BLACK);
	switch (player)
	{
	case 4: setlinecolor(BLUE);

		for (int i = 1; i <= 5; i++)
			rectangle(1000+ i * 50, 220, 1050 + i * 50, 160);   //终点的五个格子

	case 3:setlinecolor(YELLOW);

		for (int i = 1; i <= 5; i++)
			rectangle(1000 + i * 50, 370, 1050 + i * 50, 310);

	case 2:setlinecolor(RED);

		for (int i = 1; i <= 5; i++)
			rectangle(1000 + i * 50, 520, 1050 + i * 50, 460);
		
	case 1:setlinecolor(GREEN);

		for (int i = 1; i <= 5; i++)
			rectangle(1000 + i * 50, 670, 1050 + i * 50, 610);
	}
	setlinecolor(BLACK);
	for (int i = 1; i <= 15; i++)
		rectangle(200 + i * 50, 365, 250 + i * 50, 465);

}

class Setting :public Board {
public:

	bool state = false;						  //记录游戏启动状态(在未选择玩家以及出现胜利者时为false)
	bool button_state = true;			      //记录button的状态(即是否可以进行点击)使得在一些操作未完成之前不能再点击button

	char get_rand();						  //获取范围为1~6的随机数

	void Get_msg();							  //用于获取鼠标点击的event

	void Outcome();						      //画出这一轮投出的点数

	void get_pos();							  //重新绘制飞机 (在更新飞机坐标后进行绘制)

	void record_pos(int pos, int i, int j);   //记录每个格子对应的坐标

	bool choose_plane(int x, int y);          //在玩家投出点数后,获取鼠标点击的是哪一架飞机

	bool plane_state();                       //用于判断该玩家是否还有停留在机场的飞机

	void get_back();                          //将其他飞机踩回机场

	bool win();                               //判断是否有玩家胜利

	void reset_game();                        //重置游戏 初始化各个数据和状态

	void draw_circle();                       //画出圆圈

	void show_event();                        //画出event框架上的事件

	void ai_player();                         //封装ai player的下棋基本逻辑 以及各种操作的优先级
	 
	bool isback(int pos);                     //判断 ai player能否把别人踩回机场

	void showAInum();                         //画出上一轮ai投出的点数

	//void backgroudMusic();                  //加上游戏的BGM 但未成功
};

void Setting::showAInum()
{
	//if (turn % player == 0)
	//	AInum = num + '0';
	if (state)
	{
		settextstyle(60, 30, "Comic Sans MS");
		settextcolor(GREEN);
		outtextxy(250, 35, "AI Team get");
		outtextxy(650, 35, AInum);
		outtextxy(700, 35, "last turn");
	}
}

bool Setting::isback(int pos)
{
	for (int i = 1; i < player; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (pos != 0 && pos + num < 17 && go_pos[i][j] == pos + num)
				return true;
		}
	}
	return false;
}

void Setting::ai_player()
{
	//行动优先级:上一轮已经得到6点 > 无机可动 > 抵达终点 > 可踩回玩家 > 飞机可以起飞 > 不会撞墙反弹的最前方的飞机行动(反弹收益较低)
	if (state && turn % player == 0)
	{
		cleardevice();
		init_draw(player);
		draw_event();
		draw_button();
		showAInum();
		button_state = false;
		Outcome();      //这一部分是为了在界面上做出显示

		//_getch();
		int flag_1 = 0;
		int flag_2 = 0; //判断是否还有下一步不会被反弹的飞机

		int max_idx = 0;//记录的是离终点最近的飞机的下标

		int judge[4] = { 0,0,0,0 }; //判断是否会反弹 或已经到达终点
		for (int i = 0; i < 4; i++)
			if (go_pos[0][i] + num > 21 || go_pos[0][i] == 21) //go_pos数组记录的是每个飞机现在的位置 num是这一轮投到的点数
				judge[i] = 1;
		
		for (int i = 0; i < 4; i++)
			if (!judge[i] && go_pos[0][i]!=0)
			{
				flag_2 = 1;
				max_idx = i;
			}
		//--------------------------为了找到max_idx 在下面优先级判断中用到-------------------------------------
		if (flag_2)
		{
			for (int i = 0; i < 4; i++)
			{
				if (!judge[i] && go_pos[0][i] > go_pos[0][max_idx])
				{
					max_idx = i;
				}
			}
		}
		else
		{
			for (int i = 0; i < 4; i++)
			{
				if (go_pos[0][i] != 21)
					max_idx = i;
			}
			for (int i = 0; i < 4; i++)
			{
				if (go_pos[0][i] != 21 && go_pos[0][i] > go_pos[0][max_idx])
					max_idx = i;
			}
		}
		//------------------------下面去找rest 看电脑玩家的机场中是否还有飞机 在下面优先级判断中用到--------------------------------------
		int rest = -1;
		for (int i = 0; i < 4; i++)
		{
			if (go_pos[0][i] + num == 21)
				flag_1 = 1;


			if (go_pos[0][i] == 0)
				rest = i;
		}
        //------------------------下面找back_idx  判断是否可以踩回别人的飞机------------------------------------------------
		int back_idx = -1;
		for (int i = 0; i < 4; i++)
		{
			if (isback(go_pos[0][i]))
			{
				back_idx = i;
				break;
			}
		}

		//下面为电脑玩家移动优先级的判断
		now_i = 0;   //now_i = 0 代表当前为电脑玩家的回合
		if (flag_3)    //flag_3 用于判断上一次AI是否启动了飞机 若启动了飞机则这次只能移动这个飞机
		{
			flag_3 = 0;
			now_j = tmp_j;
			go_pos[0][now_j] += num;
			get_pos();
		}
		else if (num != 6 && !plane_state()) //无机可动
		{
			turn++;
			button_state = true;
		}
		else if (flag_1)                 //有飞机可以行动并且能够抵达终点
		{
			for (int i = 0; i < 4; i++)
			{
				if (go_pos[0][i] + num == 21)
				{
					go_pos[0][i] += num;
					get_end[0][i] = 1;
					now_j = i;
					get_pos();
				}
			}
		}
		else if (back_idx != -1)       //可以将其他玩家的飞机踩回去
		{
			go_pos[0][back_idx] += num;
			now_j = back_idx;
			get_pos();
		}
		else if (num == 6 && rest!= -1) //出飞机
		{
			go_pos[0][rest] = 1;
			now_j = rest;
			tmp_j = now_j;
			flag_3 = 1;
			get_pos();
		}
		else
		{
			now_j = max_idx;
			if (go_pos[0][max_idx] + num < 21)
			{
				go_pos[0][max_idx] += num;
			}
			else
			{
				go_pos[0][max_idx] = 21 - (num + go_pos[0][max_idx] - 21);
			}
			get_pos();
		}

		
	}
}

//void Setting::backgroudMusic()
//{
//	mciSendString("open ./Victory.mp3 alias BGM", 0, 0, 0);
//	mciSendString("play BGM repeat", 0, 0, 0);
//	if (0)
//		mciSendString("clsoe BGM", 0, 0, 0);
//}

void Setting::show_event()
{
	if (win())
	{
		settextstyle(50, 30, "Comic Sans MS");
		if (winner == 0)
		{
			settextcolor(GREEN);
			outtextxy(280, 150, "Winner :");
			outtextxy(280, 200, "Green Team !");
		}
		else if (winner == 1)
		{
			settextcolor(RED);
			outtextxy(280, 150, "Winner :");
			outtextxy(280, 200, "Red Team !");
		}
		else if (winner == 2)
		{
			settextcolor(YELLOW);
			outtextxy(280, 150, "Winner :");
			outtextxy(280, 200, "Yellow Team !");
		}
		else if (winner == 3)
		{
			settextcolor(BLUE);
			outtextxy(280, 150, "Winner :");
			outtextxy(280, 200, "Blue Team !");
		}
	}
	else if (state == false)
	{
		settextstyle(50, 30, "Comic Sans MS");
		outtextxy(270, 140, "Please choose");
		outtextxy(270, 200, "Number of player");
	}

	else if (state == true && turn % player == 0)
	{
		settextstyle(50, 30, "Comic Sans MS");
		settextcolor(GREEN);
		outtextxy(280, 150, "Turn :");
		outtextxy(280, 200, "Green Team");
	}

	else if (state == true && turn % player == 1)
	{
		settextstyle(50, 30, "Comic Sans MS");
		settextcolor(RED);
		outtextxy(280, 150, "Turn :");
		outtextxy(280, 200, "Red Team");
	}

	else if (state == true && turn % player == 2)
	{
		settextstyle(50, 30, "Comic Sans MS");
		settextcolor(YELLOW);
		outtextxy(280, 150, "Turn :");
		outtextxy(280, 200, "Yellow Team");
	}

	else if (state == true && turn % player == 3)
	{
		settextstyle(50, 30, "Comic Sans MS");
		settextcolor(BLUE);
		outtextxy(280, 150, "Turn :");
		outtextxy(280, 200, "Blue Team");
	}
}

void Setting::reset_game()
{
	for (int i = 0; i < player; i++)
		for (int j = 0; j < 4; j++) 
			go_pos[i][j] = 0;
	for (int i = 0; i < player; i++)
		for (int j = 0; j < 4; j++)
			get_end[i][j] = 0;
	for (int i = 0; i < player; i++)
		for (int j = 0; j < 4; j++)
		{
			record_pos(go_pos[i][j], i, j);
			player_plane[i][j].x = pos_x;
			player_plane[i][j].y = pos_y;
		}
	
	state = true;
	turn = 0;
	winner = -1;
	now_i = 0;
	now_j = 0;

	cleardevice();
	init_draw(player);
	draw_event();
	draw_button();
}

void Setting::draw_circle()
{
	setfillcolor(WHITE);
	setlinecolor(WHITE);
	fillcircle(0, 0, 50);
}

bool Setting::win()
{
	for (int i = 0; i < player; i++)
	{
		bool iswin = true;
		for (int j = 0; j < 4; j++)
		{
			if (go_pos[i][j] != 21)
				iswin = false;
		}
		if (iswin)
		{
			winner = i;
			state = false;          //胜利就让游戏停止
			return true;
		}
	}
	return false;
}

void Setting::get_back()
{
	for (int i = 0; i < player; i++)
		for (int j = 0; j < 4; j++)
		{
			if (i != now_i && go_pos[now_i][now_j] == go_pos[i][j] && go_pos[now_i][now_j] >= 2 && go_pos[now_i][now_j] <= 16)
				go_pos[i][j] = 0;
		}
}

bool Setting::plane_state()
{
	for (int i = 0; i < 4; i++)
	{
		if (go_pos[turn % player][i] && go_pos[turn % player][i] != 21)
			return true;
	}
	return false;
}

bool Setting::choose_plane(int x,int y) //鼠标点击的x,y坐标
{
	now_i = turn % player;

	if (sixpts) //若上次得到6点且启动在机场的飞机 则只能移动刚起飞的飞机
	{
		for (int j = 0; j < 4; j++)
		{
			if (go_pos[now_i][j] == 1 && x > player_plane[now_i][j].x - 25 && x<player_plane[now_i][j].x + 25 && y>player_plane[now_i][j].y - 25 && y < player_plane[now_i][j].y + 25)
			{
				now_j = j;
				sixpts = false;
				return true;
			}
		}
	}
	else
	{
		for (int j = 0; j < 4; j++)
		{
			if (go_pos[now_i][j] != 21)
			{
				if (num == 6)
				{
					if (x > player_plane[now_i][j].x - 25 && x<player_plane[now_i][j].x + 25 && y>player_plane[now_i][j].y - 25 && y < player_plane[now_i][j].y + 25)
					{
						if(go_pos[now_i][j] == 0)
							sixpts = true; //记录上一轮投到了6 且启动了机场的飞机
						now_j = j;
						return true;
					}
				}
				else
				{
					if (go_pos[now_i][j] != 0 && x > player_plane[now_i][j].x - 25 && x<player_plane[now_i][j].x + 25 && y>player_plane[now_i][j].y - 25 && y < player_plane[now_i][j].y + 25)
					{
						now_j = j;
						return true;
					}
				}
			}
		}
	}
	return false;
}

void Setting::record_pos(int go_pos,int i,int j)  //记录每个标号对应的xy坐标
{
	if (go_pos == 0)
	{
		if (j < 2)               //四个飞机编号为 0 2
			pos_x = 100;         //               1 3
		else
			pos_x = 150;
		pos_y = 650 - 50 * (j % 2) - 150 * i;
	}
	else if (go_pos == 1)
	{
		pos_x = 200;
		pos_y = 625 - 150 * i;
	}
	else if (go_pos >= 2 && go_pos <= 16)
	{
		pos_x = 225 + 50 * (go_pos - 1);
		pos_y = 415;
	}
	else if (go_pos >= 17)
	{
		pos_x = 1075 + 50 * (go_pos - 17);
		pos_y = 640 - 150 * i;
	}
}

void Setting::get_pos() //使得十六架飞机都更新自己的坐标
{ 
	if (turn % player != 0 && now_i == turn % player)
	{
		if (go_pos[now_i][now_j] == 0 && num == 6)
			go_pos[now_i][now_j] = 1;
		else if (go_pos[now_i][now_j]!=0 && go_pos[now_i][now_j] + num <= 21)
		{
			go_pos[now_i][now_j] += num;
			if (go_pos[now_i][now_j] == 21)
				get_end[now_i][now_j] = 1;
		}
		else if(go_pos[now_i][now_j] != 0 && !get_end[now_i][now_j])
			go_pos[now_i][now_j] = 21 - (num + go_pos[now_i][now_j] - 21);
		
	}
	if (turn % player == 0)
		button_state = true;
	get_back();
	cleardevice();
	init_draw(player);
	draw_event();
	draw_button();
	showAInum();

	turn++;
	if (num == 6) //如果摇到了6就再摇一次
	{
		turn--;
	}

	for (int i = 0; i < player; i++)
		for (int j = 0; j < 4; j++)
		{
			record_pos(go_pos[i][j], i, j);
			player_plane[i][j].x = pos_x;
			player_plane[i][j].y = pos_y;
		}
}

char Setting::get_rand()
{
	num = rand() % 6 + 1;
	if (turn % player == 0)
		AInum = num + '0';
	char str = num + '0';
	return str;
}

void Setting::Outcome()
{
	char str = get_rand();

	if (turn % player == 0)
		settextcolor(GREEN);
	else if (turn % player == 1)
		settextcolor(RED);
	else if (turn % player == 2)
		settextcolor(YELLOW);
	else if (turn % player == 3)
		settextcolor(BLUE);
	setbkmode(TRANSPARENT);
	settextstyle(100, 100, "楷体");
	outtextxy(850, 150, str);

}

void Setting:: Get_msg()
{
	if (MouseHit())
	{
		MOUSEMSG msg = GetMouseMsg();
		if (msg.uMsg == WM_LBUTTONDOWN)
		{

			if (button_state == false && ((num != 6 && !plane_state()) || choose_plane(msg.x, msg.y)))
			{
				get_pos();
				button_state = true;
			}

			//选择玩家个数
			else if (msg.x >= 300 && msg.x < 400 && msg.y >= 600 && msg.y <= 700 && state == false)
			{
				player = 2;
				cleardevice();
				draw_event();
				draw_button();
				showAInum();
				init_draw(player);
				plane.init_plane(player);
				state = true;

			}
			else if (msg.x >= 400 && msg.x < 500 && msg.y >= 600 && msg.y <= 700 && state == false)
			{
				player = 3;
				cleardevice();
				draw_event();
				draw_button();
				showAInum();
				init_draw(player);
				plane.init_plane(player);
				state = true;
			}
			else if (msg.x >= 500 && msg.x < 600 && msg.y >= 600 && msg.y <= 700 && state == false)
			{
				player = 4;
				cleardevice();
				draw_event();
				draw_button();
				showAInum();
				init_draw(player);
				plane.init_plane(player);
				state = true;
			}

			else if (msg.x >= 600 && msg.x <= 700 && msg.y >= 600 && msg.y <= 700)
			{
				reset_game();
			}

			else if (button_state==true && state == true && msg.x >= 800 && msg.x < 1000 && msg.y >= 550 && msg.y <= 750 )
			{
				cleardevice();
				init_draw(player);
				draw_event();
				draw_button();
				showAInum();
				Outcome();
				button_state = false;
			}
		}
	}
}

class Game :public Setting{
public:
	void run();
};

void Game::run()
{
	Board board;
	Setting setting;
	initgraph(1500, 900);
	//setting.backgroudMusic();
	setbkcolor(WHITE);
	cleardevice();

	srand(time(0));

	BeginBatchDraw();
	while (true)
	{
		board.draw_button();
		board.draw_event();
		setting.ai_player();
		setting.Get_msg();

		plane.draw_plane(player);
		setting.show_event();
		setting.showAInum();
		setting.draw_circle();
		
		FlushBatchDraw();
	}
	EndBatchDraw();

	_getch();
}

#endif

main.cpp

#include "head.h"
int main()
{
	Game game;
	game.run();

	return 0;
}

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值