easyx游戏编程:魔塔(C++游戏开发)

easyx游戏编程:魔塔(C++游戏开发)

魔塔:

本游戏用到了图形界面库graphics.h,图形界面库下载安装:

下载链接: https://easyx.cn/downloads/.
下方有源码。

介绍:

关于魔塔我相信有很多的同学都玩过这款益智类的游戏,在开始的时候,我以为这个游戏应该会很难做出来,但经过学习了easyx后发现只要实现地图的绘画和键盘输入使得我们操控的小人可以动起来,并消灭怪物最后打败boss
在这里插入图片描述

在完成魔塔小游戏,我们要:

  • 游戏界面
  • 游戏场景绘制
  • 人物和怪物的定义
  • 玩家操作

具体实现:

我这里界面较为简单,自己可以自行定义
我们先设置窗口背景颜色,清理画布,然后设置文字颜色,设置窗口透明,设置文字大小,字体与内容
欢迎界面:

//游戏欢迎界面
void Welcome()
{

	initgraph(830,680);

	//输出魔塔
	settextstyle(150, 150, "楷体");
	settextcolor(RED);
	outtextxy(120, 100, "魔塔");

	//输出按回车键开始游戏
	settextstyle(40, 40, "黑体");
	settextcolor(WHITE);
	outtextxy(90, 450, "按任意键开始游戏");

	//输出作者
	settextstyle(32, 16, "华文琥珀");
	outtextxy(500, 630, "制作人: 奇·大大 ");

	_getch();
	
	cleardevice();
	settextstyle(16, 8, "黑体");
}

游戏场景绘制:

这里游戏场景绘制就比较笨,其实就是插入一张又一张的图片来构成一层魔塔地图:

分为图片的加载、设计、绘画

图片加载
//初始化游戏
void Init()
{
	//加载图片
	loadimage(&wall, "魔塔/墙.jpg", SIZE, SIZE);
	loadimage(&floor, "魔塔/地板.jpg", SIZE, SIZE);
	loadimage(&ydoor, "魔塔/黄门.jpg", SIZE, SIZE);
	loadimage(&bdoor, "魔塔/蓝门.jpg", SIZE, SIZE);
	loadimage(&ykey, "魔塔/黄钥匙.jpg", SIZE, SIZE);
	loadimage(&bkey, "魔塔/蓝钥匙.jpg", SIZE, SIZE);
	loadimage(&rstone, "魔塔/红水晶.jpg", SIZE, SIZE);
	loadimage(&bstone, "魔塔/蓝水晶.jpg", SIZE, SIZE);
	loadimage(&rliquid, "魔塔/红药水.jpg", SIZE, SIZE);
	loadimage(&bliquid, "魔塔/蓝药水.jpg", SIZE, SIZE);
	loadimage(&_gslime, "魔塔/绿史莱姆.jpg", SIZE, SIZE);
	loadimage(&_rslime, "魔塔/红史莱姆.jpg", SIZE, SIZE);
	loadimage(&_bat, "魔塔/蝙蝠.jpg", SIZE, SIZE);
	loadimage(&_skull, "魔塔/骷髅人.jpg", SIZE, SIZE);
	loadimage(&_bskull, "魔塔/骷髅士兵.jpg", SIZE, SIZE);
	loadimage(&_wizard, "魔塔/法师.jpg", SIZE, SIZE);
	loadimage(&roleup, "魔塔/角色上.jpg", SIZE, SIZE);
	loadimage(&roledown, "魔塔/角色下.jpg", SIZE, SIZE);
	loadimage(&roleleft, "魔塔/角色左.jpg", SIZE, SIZE);
	loadimage(&roleright, "魔塔/角色右.jpg", SIZE, SIZE);
	loadimage(&leader, "魔塔/指引者.jpg", SIZE, SIZE);
	loadimage(&helper, "魔塔/帮助者.jpg", SIZE, SIZE);
	loadimage(&suffering, "魔塔/狱友.jpg", SIZE, SIZE);
	loadimage(&store, "魔塔/商店.jpg", SIZE, SIZE);
	loadimage(&stairsup, "魔塔/上楼梯.jpg", SIZE, SIZE);
	loadimage(&stairsdown, "魔塔/下楼梯.jpg", SIZE, SIZE);
	loadimage(&cage, "魔塔/笼子.jpg", SIZE, SIZE);
	loadimage(&sword, "魔塔/剑.jpg", SIZE, SIZE);
	loadimage(&shield, "魔塔/盾.jpg", SIZE, SIZE);
	loadimage(&convey, "魔塔/传送道具.jpg", SIZE, SIZE);
	loadimage(&defend, "魔塔/守卫.jpg", SIZE, SIZE);
	loadimage(&_boss, "魔塔/BOSS.jpg", SIZE, SIZE);
	loadimage(&_sboss, "魔塔/boss侍卫.jpg", SIZE, SIZE);
	loadimage(&fire, "魔塔/岩浆.jpg", SIZE, SIZE);

	//背景音乐
	mciSendString("open 魔塔/背景音乐.mp3 alias BGM", 0, 0, 0);
	mciSendString("play BGM repeat", 0, 0, 0);

	//输出信息框及信息
	rectangle(680, 10, 820, 670);
	outtextxy(700, 75, "生命:");
	outtextxy(700, 100, "攻击:");
	outtextxy(700, 125, "防御:");
	outtextxy(700, 150, "金钱:");
	outtextxy(700, 210, "黄钥匙:");
	outtextxy(700, 235, "蓝钥匙:");
	outtextxy(700, 295, "当前层数:");
	outtextxy(690, 360, "当前武器:神圣剑");
	outtextxy(690, 385, "当前防具:神圣盾");
	
}

设计

设计上定义一个三维数组来进行构建,地图的异同怪物的位置来自于数组

int map[6][13][13]     //13是增加多余的墙,防止游戏过程中出现数组越界问题
{
	//第一层地图	
	{
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
		{ 0, 25, 1, 10, 11, 10, 1, 1, 1, 1, 1, 1, 0 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0 },
		{ 0, 8, 1, 1, 2, 1, 0, 6, 4, 1, 0, 1, 0 },
		{ 0, 1, 13, 1, 0, 1, 0, 7, 8, 1, 0, 1, 0 },
		{ 0, 0, 2, 0, 0, 1, 0, 0, 0, 2, 0, 1, 0 },
		{ 0, 4, 1, 1, 0, 1, 2, 12, 15, 12, 0, 1, 0 },
		{ 0, 1, 14, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0 },
		{ 0, 0, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0 },
		{ 0, 1, 1, 1, 0, 0, 2, 0, 0, 0, 2, 0, 0 },
		{ 0, 8, 1, 4, 0, 4, 1, 1, 0, 1, 12, 1, 0 },
		{ 0, 8, 30, 4, 0, 1, 17, 1, 0, 10, 9, 10, 0 },
		{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
	},
	//第二层地图
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 26, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
	{ 0, 17, 1, 0, 0, 1, 31, 1, 31, 1, 0, 0, 0 },
	{ 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
	{ 0, 1, 0, 4, 4, 0, 1, 1, 1, 0, 1, 21, 0 },
	{ 0, 1, 0, 4, 1, 27, 1, 1, 1, 27, 1, 1, 0 },
	{ 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0 },
	{ 0, 1, 0, 23, 1, 0, 1, 1, 1, 0, 1, 22, 0 },
	{ 0, 1, 0, 1, 1, 27, 1, 1, 1, 27, 1, 1, 0 },
	{ 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0 },
	{ 0, 1, 0, 9, 9, 0, 1, 1, 1, 0, 1, 1, 0 },
	{ 0, 25, 0, 9, 1, 27, 1, 1, 1, 27, 1, 1, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
},

//第三层地图
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 4, 7, 0, 4, 9, 4, 0, 1, 0, 1, 8, 0 },
	{ 0, 1, 8, 0, 9, 4, 9, 0, 1, 2, 12, 1, 0 },
	{ 0, 15, 1, 0, 4, 5, 4, 0, 1, 0, 0, 0, 0 },
	{ 0, 2, 0, 0, 0, 1, 0, 0, 1, 0, 1, 20, 0 },
	{ 0, 1, 1, 12, 1, 1, 1, 10, 1, 1, 1, 1, 0 },
	{ 0, 2, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0 },
	{ 0, 13, 1, 0, 0, 1, 0, 0, 1, 0, 1, 8, 0 },
	{ 0, 1, 4, 0, 1, 1, 1, 0, 1, 2, 15, 4, 0 },
	{ 0, 8, 6, 0, 1, 34, 1, 0, 1, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 1, 0, 0, 11, 0, 1, 1, 0 },
	{ 0, 26, 16, 1, 1, 1, 1, 0, 1, 2, 1, 25, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

},
//第四层地图
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 1, 5, 1, 0, 24, 24, 24, 0, 1, 1, 1, 0 },
	{ 0, 8, 1, 4, 0, 1, 1, 1, 0, 4, 1, 9, 0 },
	{ 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 14, 1, 0 },
	{ 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0 },
	{ 0, 1, 15, 1, 2, 1, 11, 1, 1, 13, 1, 1, 0 },
	{ 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 11, 1, 10, 1, 1, 1, 1, 1, 1, 1, 1, 0 },
	{ 0, 2, 0, 0, 2, 0, 0, 0, 2, 0, 0, 2, 0 },
	{ 0, 1, 0, 1, 15, 1, 0, 1, 15, 1, 0, 1, 0 },
	{ 0, 1, 0, 10, 1, 4, 0, 6, 1, 8, 0, 16, 0 },
	{ 0, 25, 0, 4, 10, 4, 0, 1, 10, 1, 0, 26, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
},
//第五层地图
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 33, 0, 1, 11, 2, 1, 0, 1, 1, 2, 1, 0 },
	{ 0, 2, 0, 1, 1, 0, 4, 0, 10, 10, 0, 11, 0 },
	{ 0, 2, 2, 12, 1, 0, 1, 0, 4, 4, 0, 1, 0 },
	{ 0, 0, 0, 0, 2, 0, 12, 0, 4, 4, 0, 1, 0 },
	{ 0, 4, 1, 15, 1, 0, 1, 0, 0, 0, 0, 1, 0 },
	{ 0, 4, 1, 1, 12, 0, 1, 10, 1, 1, 1, 1, 0 },
	{ 0, 0, 14, 0, 0, 0, 1, 0, 0, 0, 0, 11, 0 },
	{ 0, 1, 1, 1, 1, 0, 10, 0, 1, 1, 1, 1, 0 },
	{ 0, 9, 4, 8, 1, 0, 1, 0, 10, 0, 0, 0, 0 },
	{ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 29, 0 },
	{ 0, 26, 19, 1, 1, 1, 1, 0, 1, 2, 1, 28, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
},
//boss地图
{
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
	{ 0, 36, 36, 36, 36, 0, 32, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 35, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 35, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 35, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 1, 0, 36, 36, 36, 36, 0 },
	{ 0, 36, 36, 36, 36, 0, 16, 0, 36, 36, 36, 36, 0 },
	{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
}
};

绘画
//画地图以及输出信息
void Draw()
{
	int j, i;

	for (j = 1; j <= 11; j++)
	{
		for (i = 1; i <= 11; i++)
		{
			switch (map[level][j][i])
			{
			case 0: putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &wall); break;
			case 1:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &floor); break;
			case 2:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &ydoor); break;
			case 3:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &bdoor); break;
			case 4:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &ykey); break;
			case 5:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &bkey); break;
			case 6:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &rstone); break;
			case 7:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &bstone); break;
			case 8:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &rliquid); break;
			case 9:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &bliquid); break;
			case 10:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_gslime); break;
			case 11:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_rslime); break;
			case 12:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_bat); break;
			case 13:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_skull); break;
			case 14:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_bskull); break;
			case 15:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_wizard); break;
			case 16:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &roleup); break;
			case 17:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &roledown); break;
			case 18:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &roleleft); break;
			case 19:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &roleright); break;
			case 20:
			case 21:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &leader); break;
			case 22:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &helper); break;
			case 23:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &suffering); break;
			case 24:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &store); break;
			case 25:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &stairsup); break;
			case 26:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &stairsdown); break;
			case 27:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &cage); break;
			case 28:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &sword); break;
			case 29:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &shield); break;
			case 30:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &convey); break;
			case 31:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &defend); break;
			case 32:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_boss); break;
			case 33:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_sboss); break;
			case 34:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &floor); break;
			case 35:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &_sboss); break;
			case 36:putimage((i - 1) * SIZE + 10, (j - 1) * SIZE + 10, &fire); break;
			}
		}
	}

	//画游戏框
	rectangle(10, 10, 670, 670);

	//消除之前的信息
	setfillcolor(BLACK);
	solidrectangle(740, 75, 772, 91);		//生命
	solidrectangle(740, 100, 772, 116);		//攻击
	solidrectangle(740, 125, 772, 141);		//防御
	solidrectangle(740, 150, 772, 166);		//金钱
	solidrectangle(756, 210, 772, 226);		//黄钥匙
	solidrectangle(756, 235, 772, 251);		 //蓝钥匙

	//输出信息
	outtextxy(740, 75, turn(roleman.HP));      //生命值
	outtextxy(740, 100, turn(roleman.att));     //攻击
	outtextxy(740, 125, turn(roleman.def));    //防御
	outtextxy(740, 150, turn(roleman.money));  //金钱
	outtextxy(756, 210, turn(roleman.ykey));   //黄钥匙
	outtextxy(756, 235, turn(roleman.bkey));   //蓝钥匙
	outtextxy(772, 295, turn(level + 1));        //当前层数
}

人和怪物的定义:

使用结构体来定义

//角色结构体
typedef struct _ROLEMAN
{
	int HP;          //血量
	int att;         //攻击力
	int def;         //防御力
	int money;       //金钱
	int ykey;        //黄钥匙
	int bkey;        //蓝钥匙
}ROLEMAN;

//怪物结构体
typedef struct _MONSTER
{
	int HP;      //血量
	int att;     //攻击力
	int def;     //防御力
	int money;   //掉落金钱
}MONSTER;


}

玩家操作:

定位,获取玩家位置:

//寻找人物位置
void FindRole(int* prow, int* pcol)
{
	for (*prow = 1; *prow <= 13; (*prow)++)
	{
		for (*pcol = 1; *pcol <= 13; (*pcol)++)
		{
			switch (map[level][*prow][*pcol])
			{
			case 16:
			case 17:
			case 18:
			case 19: return;
			}
		}
	}
}

玩家移动:
在这里我就介绍其中一种怪物,其他的其实都是类似的,你明白了其中一种,其他的自然就明白了

	void Game(int row, int col, int x, int y)
{
	int count, loss, ID, HP;      //攻击次数与角色损失血量,弹框返回值,商店购买增加的血量
	int c = 0;						  //人物运动状态
	char con;
	hwnd = GetHWnd();    //弹窗前置
	if (x < 0 && y == 0)
		c = 17;
	if (x > 0 && y == 0)
		c = 16;
	if (y < 0 && x == 0)
		c = 18;
	if (y > 0 && x == 0)
		c = 19;
	switch (map[level][row + x][col + y]){
	······
	case 10: //人的前面是绿史莱姆
		map[level][row][col] = c;
		//角色攻击小于怪物防御
		if (roleman.att <= gslime.def)
		{
			MessageBox(hwnd, "打不过!", "", MB_OK);
		}

		else
		{
			//怪物攻击小于角色防御
			if (gslime.att - roleman.def <= 0)
			{
				loss = 0;
			}
			else
			{
				count = gslime.HP / (roleman.att - gslime.def);
				loss = count * (gslime.att - roleman.def);
			}

			if (loss >= roleman.HP)
			{
				MessageBox(hwnd, "打不过!", "", MB_OK);
			}
			else
			{
				roleman.HP -= loss;
				roleman.money += gslime.money;
				map[level][row + x][col + y] = 1;
			}
		}

		break;
	}

在这里还有一点需要说明

使用easyx中outtextxy(x,y,str)时其参数需要是字符串,要不然会出现显示错误,将数字改成字符串输出即可
//数字转化为字符串
char* turn(int num)
{
	sprintf_s(str, "%d", num);
	return str;
}

源码

学习之路不孤单

  • 10
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值