easyx小游戏--2048

实况图

开发工具

    我使用的是Visual Studio 2022,其他版本也是可以的。由于技术问题,我用的是C语言(不是C++),能学会数组,函数,数据结构(连指针都不用)及easyx基本应用即可看懂。使用前要安装easyx库(直接网页上搜索easyx安装即可。如图:

    作为本人的第一篇博客,我会尽量讲清楚2048怎么做出来的。如果有哪一点讲的不够好可以给我提出建议哈(提前叠甲)。那么现在我们开始吧:

程序设计思路

  每次有数字变化(注意是数字变化不是按键)就在随机空白位上产生2或4。直到合成出2048或没法再变化数字则游戏结束。在结尾我会把文中所用图片发出来,有需要自取哈。

正式代码

头文件

//2048小游戏
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <mmsyscom.h>
#pragma comment(lib,"winmm.lib")

<stdio.h>用来使用C语言

<graphics.h>调用图形库

<conio.h>用来获取键盘信息

<time.h>通过时间播散随机数

#include <mmsyscom.h>
#pragma comment(lib,"winmm.lib") 播放音乐

如果不了解不要急,下面我会在各板块解释。

函数间的中转站“数据结构”

struct fff {
	int a[4][4] = {        //数据分析
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
	 };
	POINT shu[4][4];     //每一方格坐标设定
	bool ch;      
	int max=2;          //设计得分:即数字最大值
}win;

  数据结构包含2048数据,画图时每一方格左上角坐标,随机数节点,分数。

准备各项数据


void prepare() {
	initgraph(900, 480,SHOWCONSOLE);

	for (int i = 0; i < 4; i++) {    //设定方格左上角坐标
		for (int g = 0; g < 4; g++) {
			if (i==0&&g==0){
				win.shu[0][0].x = 200;
	            win.shu[0][0].y = 100;}
			else {
				win.shu[i][g].x = win.shu[0][0].x + 70 * g;
				win.shu[i][g].y = win.shu[0][0].y + 70 * i;
			}
		}
	}
	win.ch = TRUE;

	srand(time(0));       //播散随机数种子
	int i = rand() % 4;
	int t = rand() % 4;
	win.a[i][t] = 2;      //定义开始数为2
	 
	IMAGE msg;               //加点背景
	loadimage(&msg, "./背景.jpg",640,480);
	putimage(0, 0, &msg);

	mciSendString("open ./太空漫步.mp3 alias BGM", 0, 0, 0);  //加点音乐
	mciSendString("play BGM repeat", 0, 0, 0);     //注意要加头文件
	                                               //#include <mmsyscom.h>
                                                   //#pragma comment(lib,"winmm.lib")
}

  放音乐时要使音乐和程序在同一文件夹中,注意音乐为mp3模式。

头文件

#include <mmsyscom.h>
#pragma comment(lib,"winmm.lib")记得加上。

画图(重点)

void gamedraw() {
	BeginBatchDraw();
	setfillcolor(BLACK);
	fillrectangle(640, 0, 900, 250);
	setfillcolor(RGB(252, 157, 154));
	fillrectangle(640, 250, 900, 480);
	settextcolor(WHITE);
	settextstyle(50, 0, "黑体");
	setbkmode(TRANSPARENT);
	outtextxy(700, 50, "得分:");
	settextcolor(RGB(251, 178, 23));
	settextstyle(70, 0, "黑体");

	char s[8];                  //打出分数
	sprintf_s(s, "%d", win.max);     //因为outtextxy只能打出字符,故用sprintf进行转换
	outtextxy(700,150, s);

	setlinecolor(RED);
	setlinestyle(BS_SOLID,3);
	rectangle(195,95,195+285,95+285);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);

	for (int i = 0; i < 4; i++) {
		for (int g = 0; g < 4; g++) {

			setfillcolor(RGB(200, 200, 169));         //画出数字背景方格
			solidroundrect(win.shu[i][g].x, win.shu[i][g].y, win.shu[i][g].x + 66, win.shu[i][g].y + 66, 25, 25);

			if (win.a[i][g] != 0) {           //设置每个数字方格颜色都不相同
				switch (win.a[i][g]) {
				case 2:
					setfillcolor(RGB(249, 205, 173));
					break;
				case 4:
					setfillcolor(RGB(252, 157, 154));
					break;
				case 8:
					setfillcolor(RGB(244, 208, 0));
					break;
				case 16:
					setfillcolor(RGB(69, 137, 148));
					break;
				case 32:
					setfillcolor(RGB(255, 245, 247));
					break;
				case 64:
					setfillcolor(RGB(172, 81, 24));
					break;
				case 128:
					setfillcolor(RGB(64, 116, 52));
					break;
				case 256:
					setfillcolor(RGB(222, 125, 44));
					break;
				case 512:
					setfillcolor(RGB(225, 238, 210));
					break;
				case 1024:
					setfillcolor(RGB(224, 160, 158));
					break;
				}
				solidroundrect(win.shu[i][g].x, win.shu[i][g].y, win.shu[i][g].x + 66, win.shu[i][g].y + 66, 25, 25);  //画出数字特有方格

				if (win.a[i][g] < 10) {         //打印数字
					settextstyle(50, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 20, win.shu[i][g].y + 10, s);}
				else if (win.a[i][g] < 100) {
					settextstyle(50, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 13, win.shu[i][g].y + 10, s);}
				else if (win.a[i][g] < 1000) {
					settextstyle(30, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 8, win.shu[i][g].y + 8, s);	}
				else if (win.a[i][g] < 10000) {
					settextstyle(30, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 4, win.shu[i][g].y + 8, s);
				}
			}
		}
	}
	EndBatchDraw();
}

可能问题:

1.字符串输出报错

   点击屏幕上方调试--调试属性--高级--字符集->改为高字节字符集。

2.颜色不喜欢

   可以去网上搜喜欢的颜色的配成

按键控制

//小键盘上,下,左,右分别为72,80,75,77
void control() {
	if (_kbhit) {      //判断是否有按下按键,记得加头文件#include <conio.h>
		char a = _getch();
		switch (a) {
		case 'w':
		case 'W':
		case 72:
			for (int t = 0; t < 3; t++) {      //重复三次,确保数字全部移动
				for (int i = 1; i < 4; i++) {
					for (int g = 0; g < 4; g++) {
						if (win.a[i][g] != 0) {
							if (i > 0 && win.a[i - 1][g] == 0) {        //数字移动
								win.a[i - 1][g] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;       //若有数字变化就变化节点
							}

							if (i >0 && win.a[i - 1][g] == win.a[i][g]) {    //数字加成
								win.a[i - 1][g] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							    if (win.a[i - 1][g] > win.max) { win.max = win.a[i - 1][g]; }
							}
						}
					}
			}
		}
			break;
		case 's':
		case 'S':
		case 80:
			for (int t = 0; t < 3; t++) {       //重复三次,确保数字全部移动
				for (int i = 3; i >=0; i--) {
					for (int g = 0; g < 4; g++) {
						if (win.a[i][g] != 0) {
							if (i < 3 && win.a[i + 1][g] == 0) {
								win.a[i + 1][g] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (i <3 && win.a[i + 1][g] == win.a[i][g]) {
								win.a[i + 1][g] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i + 1][g] > win.max) { win.max = win.a[i + 1][g]; }
							}
						}
					}
				}
			}
			break;
		case 'a':
		case 'A':
		case 75:
			for (int t = 0; t < 3; t++) {       //重复三次,确保数字全部移动
				for (int i = 0; i < 4; i++) {
					for (int g = 0; g<4; g++) {
						if (win.a[i][g] != 0) {
							if (g > 0 && win.a[i][g - 1] == 0) {
								win.a[i][g - 1] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (g > 0 && win.a[i][g - 1] == win.a[i][g]) {
								win.a[i][g - 1] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i ][g-1] > win.max) { win.max = win.a[i][g-1]; }
							}
						}
					}
				}
			}
			break;
		case 'd':
		case 'D':
		case 77:
			for (int t = 0; t < 3; t++) {      //重复三次,确保数字全部移动
				for (int i = 0; i < 4; i++) {
					for (int g = 3; g >=0; g--) {
						if (win.a[i][g] != 0) {
							if (g < 3 && win.a[i][g + 1] == 0) {
								win.a[i][g + 1] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (g<3 && win.a[i][g+1] == win.a[i][g]) {
								win.a[i][g+1] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i][g+1] > win.max) { win.max = win.a[i][g+1]; }
							}
						}
					}
				}
			}
			break;
		}
	}

	if (win.ch == FALSE) {       //如果节点有变化
		int i = rand() % 4;      //设置一个随机格子
		int t = rand() % 4;
		while (win.a[i][t]!=0){    //注意要在空白格子出现随机数
		 i = rand() % 4;
		 t = rand() % 4;
		}
		int shu = rand() % 4;
		if (shu == 0) {     //随机出4的概率为1/4
			shu = 4;}
		else {
			shu = 2;}
		win.a[i][t] = shu;
		win.ch = TRUE;     //将节点改回去
	}
}

注意

1.判断条件时不能连等

2.放入随机数之前要判断该位是否有数字

游戏结束

void gameover() {
	for (int i = 0; i < 4; i++) {
		for (int g = 0; g < 4; g++) {
			if (win.a[i][g] == 2048) {   //当合成2048时游戏胜利
				settextcolor(WHITE);
				settextstyle(70, 0, "黑体");
				outtextxy(200, 150, "You win.");
				getchar();          //卡住页面,让玩家得意一会
				closegraph();    //关闭界面
			}
		}
	}

	int pan=1;          //设置节点(这里我不想用bool判定,临时设置一个节点)
	for (int i = 0; i < 4; i++) {
		if (pan == 0) { break; }      //节省时间,不重复判定
		for (int g = 0; g < 4; g++) {
			if (win.a[i][g] == 0) {    //只要还有空格不结束
				pan = 0;
				break;
			}
			if (win.a[i][g] == win.a[i + 1][g]||win.a[i][g]==win.a[i][g+1]) {       //只要数字能加和不结束
				pan = 0;
				break;
			}
		}
	}
	if (pan == 1) {      //如果节点不变游戏结束
		settextcolor(WHITE);
		settextstyle(70, 0, "黑体");
		outtextxy(200, 150, "GAMEOVER");
		getchar();    //卡住页面
		closegraph();
	}
}

函数组装

//2048小游戏
#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <mmsyscom.h>
#pragma comment(lib,"winmm.lib")

//用于函数间的中转站“数据结构”
struct fff {
	int a[4][4] = {        //数据分析
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
	 };
	POINT shu[4][4];     //每一方格坐标设定
	bool ch;      
	int max=2;          //设计得分:即数字最大值
}win;

//事前准备
void prepare() {
	initgraph(900, 480,SHOWCONSOLE);

	for (int i = 0; i < 4; i++) {    //设定方格左上角坐标
		for (int g = 0; g < 4; g++) {
			if (i==0&&g==0){
				win.shu[0][0].x = 200;
	            win.shu[0][0].y = 100;}
			else {
				win.shu[i][g].x = win.shu[0][0].x + 70 * g;
				win.shu[i][g].y = win.shu[0][0].y + 70 * i;
			}
		}
	}
	win.ch = TRUE;

	srand(time(0));       //播散随机数种子
	int i = rand() % 4;
	int t = rand() % 4;
	win.a[i][t] = 2;      //定义开始数为2
	 
	IMAGE msg;               //加点背景
	loadimage(&msg, "./背景.jpg",640,480);
	putimage(0, 0, &msg);

	mciSendString("open ./太空漫步.mp3 alias BGM", 0, 0, 0);  //加点音乐
	mciSendString("play BGM repeat", 0, 0, 0);     //注意要加头文件
	                                               //#include <mmsyscom.h>
                                                   //#pragma comment(lib,"winmm.lib")
}

//画图吧
void gamedraw() {
	BeginBatchDraw();
	setfillcolor(BLACK);
	fillrectangle(640, 0, 900, 250);
	setfillcolor(RGB(252, 157, 154));
	fillrectangle(640, 250, 900, 480);
	settextcolor(WHITE);
	settextstyle(50, 0, "黑体");
	setbkmode(TRANSPARENT);
	outtextxy(700, 50, "得分:");
	settextcolor(RGB(251, 178, 23));
	settextstyle(70, 0, "黑体");

	char s[8];                  //打出分数
	sprintf_s(s, "%d", win.max);     //因为outtextxy只能打出字符,故用sprintf进行转换
	outtextxy(700,150, s);

	setlinecolor(RED);
	setlinestyle(BS_SOLID,3);
	rectangle(195,95,195+285,95+285);
	settextcolor(BLACK);
	setbkmode(TRANSPARENT);

	for (int i = 0; i < 4; i++) {
		for (int g = 0; g < 4; g++) {

			setfillcolor(RGB(200, 200, 169));         //画出数字背景方格
			solidroundrect(win.shu[i][g].x, win.shu[i][g].y, win.shu[i][g].x + 66, win.shu[i][g].y + 66, 25, 25);

			if (win.a[i][g] != 0) {           //设置每个数字方格颜色都不相同
				switch (win.a[i][g]) {
				case 2:
					setfillcolor(RGB(249, 205, 173));
					break;
				case 4:
					setfillcolor(RGB(252, 157, 154));
					break;
				case 8:
					setfillcolor(RGB(244, 208, 0));
					break;
				case 16:
					setfillcolor(RGB(69, 137, 148));
					break;
				case 32:
					setfillcolor(RGB(255, 245, 247));
					break;
				case 64:
					setfillcolor(RGB(172, 81, 24));
					break;
				case 128:
					setfillcolor(RGB(64, 116, 52));
					break;
				case 256:
					setfillcolor(RGB(222, 125, 44));
					break;
				case 512:
					setfillcolor(RGB(225, 238, 210));
					break;
				case 1024:
					setfillcolor(RGB(224, 160, 158));
					break;
				}
				solidroundrect(win.shu[i][g].x, win.shu[i][g].y, win.shu[i][g].x + 66, win.shu[i][g].y + 66, 25, 25);  //画出数字特有方格

				if (win.a[i][g] < 10) {         //打印数字
					settextstyle(50, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 20, win.shu[i][g].y + 10, s);}
				else if (win.a[i][g] < 100) {
					settextstyle(50, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 13, win.shu[i][g].y + 10, s);}
				else if (win.a[i][g] < 1000) {
					settextstyle(30, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 8, win.shu[i][g].y + 8, s);	}
				else if (win.a[i][g] < 10000) {
					settextstyle(30, 0, "黑体");
					char s[8];
					sprintf_s(s, "%d", win.a[i][g]);
					outtextxy(win.shu[i][g].x + 4, win.shu[i][g].y + 8, s);
				}
			}
		}
	}
	EndBatchDraw();
}

//按键控制
//小键盘上,下,左,右分别为72,80,75,77
void control() {
	if (_kbhit) {      //判断是否有按下按键,记得加头文件#include <conio.h>
		char a = _getch();
		switch (a) {
		case 'w':
		case 'W':
		case 72:
			for (int t = 0; t < 3; t++) {      //重复三次,确保数字全部移动
				for (int i = 1; i < 4; i++) {
					for (int g = 0; g < 4; g++) {
						if (win.a[i][g] != 0) {
							if (i > 0 && win.a[i - 1][g] == 0) {        //数字移动
								win.a[i - 1][g] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;       //若有数字变化就变化节点
							}

							if (i >0 && win.a[i - 1][g] == win.a[i][g]) {    //数字加成
								win.a[i - 1][g] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							    if (win.a[i - 1][g] > win.max) { win.max = win.a[i - 1][g]; }
							}
						}
					}
			}
		}
			break;
		case 's':
		case 'S':
		case 80:
			for (int t = 0; t < 3; t++) {       //重复三次,确保数字全部移动
				for (int i = 3; i >=0; i--) {
					for (int g = 0; g < 4; g++) {
						if (win.a[i][g] != 0) {
							if (i < 3 && win.a[i + 1][g] == 0) {
								win.a[i + 1][g] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (i <3 && win.a[i + 1][g] == win.a[i][g]) {
								win.a[i + 1][g] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i + 1][g] > win.max) { win.max = win.a[i + 1][g]; }
							}
						}
					}
				}
			}
			break;
		case 'a':
		case 'A':
		case 75:
			for (int t = 0; t < 3; t++) {       //重复三次,确保数字全部移动
				for (int i = 0; i < 4; i++) {
					for (int g = 0; g<4; g++) {
						if (win.a[i][g] != 0) {
							if (g > 0 && win.a[i][g - 1] == 0) {
								win.a[i][g - 1] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (g > 0 && win.a[i][g - 1] == win.a[i][g]) {
								win.a[i][g - 1] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i ][g-1] > win.max) { win.max = win.a[i][g-1]; }
							}
						}
					}
				}
			}
			break;
		case 'd':
		case 'D':
		case 77:
			for (int t = 0; t < 3; t++) {      //重复三次,确保数字全部移动
				for (int i = 0; i < 4; i++) {
					for (int g = 3; g >=0; g--) {
						if (win.a[i][g] != 0) {
							if (g < 3 && win.a[i][g + 1] == 0) {
								win.a[i][g + 1] = win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
							}
							if (g<3 && win.a[i][g+1] == win.a[i][g]) {
								win.a[i][g+1] = 2 * win.a[i][g]; win.a[i][g] = 0;
								win.ch = FALSE;
								if (win.a[i][g+1] > win.max) { win.max = win.a[i][g+1]; }
							}
						}
					}
				}
			}
			break;
		}
	}

	if (win.ch == FALSE) {       //如果节点有变化
		int i = rand() % 4;      //设置一个随机格子
		int t = rand() % 4;
		while (win.a[i][t]!=0){    //注意要在空白格子出现随机数
		 i = rand() % 4;
		 t = rand() % 4;
		}
		int shu = rand() % 4;
		if (shu == 0) {     //随机出4的概率为1/4
			shu = 4;}
		else {
			shu = 2;}
		win.a[i][t] = shu;
		win.ch = TRUE;     //将节点改回去
	}
}

//游戏结束条件
void gameover() {
	for (int i = 0; i < 4; i++) {
		for (int g = 0; g < 4; g++) {
			if (win.a[i][g] == 2048) {   //当合成2048时游戏胜利
				settextcolor(WHITE);
				settextstyle(70, 0, "黑体");
				outtextxy(200, 150, "You win.");
				getchar();          //卡住页面,让玩家得意一会
				closegraph();    //关闭界面
			}
		}
	}

	int pan=1;          //设置节点(这里我不想用bool判定,临时设置一个节点)
	for (int i = 0; i < 4; i++) {
		if (pan == 0) { break; }      //节省时间,不重复判定
		for (int g = 0; g < 4; g++) {
			if (win.a[i][g] == 0) {    //只要还有空格不结束
				pan = 0;
				break;
			}
			if (win.a[i][g] == win.a[i + 1][g]||win.a[i][g]==win.a[i][g+1]) {       //只要数字能加和不结束
				pan = 0;
				break;
			}
		}
	}
	if (pan == 1) {      //如果节点不变游戏结束
		settextcolor(WHITE);
		settextstyle(70, 0, "黑体");
		outtextxy(200, 150, "GAMEOVER");
		getchar();    //卡住页面
		closegraph();
	}
}

//函数组装
int main() {
	prepare();
	while (1) {
		gamedraw();
		control();
		gameover();
	}
	return 0;
}

   使用函数可以使主函数部分极为简介,同时分区块解决问题也可以使你的思路更为清晰,但这样当你顺着主函数读代码时会比较麻烦。

背景分享(音乐可以自行下载)

  

本篇就这样,之后会不定时更新小游戏(就酱)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值