C++魔塔基础版

        魔塔是一款经典的策略类游戏。本文将基于C++与EasyX图形库,实现魔塔的基础改编版,相较于原版,增加了升级、血量上限等功能,设计了四层地图与出乎意料的结局,并合理安排数值,使游戏趣味性与挑战性兼备。

        一点小小的建议:如果想要自己独自实现魔塔,可以先实现控制台版本,再图形化、插入音乐。文章难免有疏漏失误,还请读者指出。

        本文重点不在于详细介绍实现魔塔的各种技术细节,想要根据本文实现自己的魔塔,必然需要进一步查阅相关知识,比如头文件的引用与函数声明,防止控制台弹出,EasyX各种库函数的使用,mciSendString的运用等。

魔塔基础改编版展示

一 资源准备

1.下载EasyX。这是一个基于C++的图形库,针对Windows平台,易于上手。

2.图片素材准备。在网上搜索相应资源,将需要的图片依次截取下来并保存,注意素材最好用数字编号,便于后期图形化加载图片,以下是我图片的编号。

C++魔塔基础版_第1张图片

3.音频准备。请读者选择自己喜欢的音效与背景音乐,我的魔塔音效全部来源于塞尔达。下面介绍几个有用的关于音频处理的免费网站

       在线转换MP3文件(无限制!) - ezyZip,可以实现多种文件格式的转换

        Online MP3 Cutter - Cut Songs, Make Ringtones,剪切音频、设置淡入淡出等

        在线音频剪辑丨剪切丨编辑-100Audio音频工具站

二 思路

        游戏实现的核心在于读取玩家操作并进行相应处理。player与monster可以用class创建,地图采用三维数组,每次有效操作后函数都会返回一个值,根据值判断游戏是否结束

        创立多个源文件,分别对应main body, functions, audio, visualization, data,创建头文件联系各个源文件。这样做的好处在于使每个源文件都对应相应功能,实现模块化,便于管理

        游戏核心代码完成后再增加图鉴、npc对话等拓展功能。

三 实现

1.头文件

#pragma once
#undef UNICODE    //这个东西非常重要,不加的话easyX中
                  //关于字符串的几乎都要报错,然后超级麻烦
#define _CRT_NONSTDC_NO_DEPRECATE
#define _CRT_SECURE_NO_WARNINGS
#define ROW 13
#define COL 13
#define FLOOR 4
#include
#include
#include
#include 
#include
#pragma comment(lib,"winmm.lib")
#include
#include
#include 

//map
extern int Map[FLOOR][ROW][COL];

//类
class Player {
public:
    // 构造函数
    Player();
    int position[3]; // 位置数组
    int hp;         // 生命值
    int hp_limit;   // 生命值上限
    int atk;        // 攻击力
    int def;        // 防御力
    int money;      // 金钱
    int Lv;         // 等级
    int Exp;        // 经验值
    int yellow_key; // 黄钥匙
    int blue_key;   // 蓝钥匙
    int red_key;    // 红钥匙
    int pickaxe;    //镐子
};

class Monster {
public:
    Monster(int hp, int atk, int def, int exp,int gold/*, char* name*/);
    int hp; // 生命值
    int atk; // 攻击力
    int def; // 防御力
    int exp; // 经验值
    int money;
};
//对象
extern Monster GreenSlime; extern Monster RedSlime;
extern Monster Skeleton;  extern Monster SkeletonSoldier;
extern Monster Bat;
extern Monster Wizard;
extern Monster DemonKing;
extern Monster DemonEmperor;

//函数
//void display_map(int map[][COL]);   //控制台版本
int play(int map[][COL], Player &p);
void ChangeFloor(int Map[FLOOR][ROW][COL], Player& P, int ret);
int Damage(Player& p, const Monster& m);

void LoadImages();
void StartImage();
void InventInfor();
void InitImage();
void MonsterEncyclopedia(Player& p);
void PrintMap(int map[][COL], Player& p);    //图形化
void PrintInfor(char* name, int d_hp, int money, int exp);
void PrintInfor(char* name, int addHP);
void PrintMessage(const char* message);
void PrintNoKey();
void PrintLvUp();
void PrintShield(char* name, int defence);
void PrintSword(char* name, int attack);
void PrintLifeGem(int defence);
void PrintAttackGem(int attack);
void PrintSpecialInfor(const char* name);
void PrintFalsePrincess();
void PrintLose();
void PrintWin();
void exit();
void PrintUsePickaxe();

//audio
void musicGameLoading();
void musicPickup();
void musicBattle();
void musicEnter();
void musicLvUp();
void musicMeet();
void closeMusic();
void musicDie();
void musicWin();
void musicEncyclopedia();

2.mainbody源文件

        顾名思义,此文件负责游戏主体逻辑,而不负责具体实现

技术细节

1. 地图所用的三维数组第三个维度表示楼层

2.Playsound函数只能播放wav格式的音频,且无法同时播放多个音频,所以此处用于循坏播放背景音乐。audio源文件使用mciSendString来实现播放多个音频。

#include"head.hpp"
int main()
{
		Player P;            //初始化
		initgraph(850, 650, EX_NOCLOSE); // 初始化一个窗口
		LoadImages();        // 加载图片素材
		StartImage();        // 游戏开始画面
		InventInfor();       //制作者信息
		背景音乐
		PlaySound(TEXT("ZeldaBackground.wav"), 0, SND_FILENAME | SND_ASYNC | SND_LOOP); //这个函数只适用于处理单个音频!
		InitImage();         // 打印游戏过程中始终不变的图片
		int ret;
		int f = P.position[0];
		while(P.position[0]

3.functions源文件

1. 角色移动

        使用上下左右以及WSAD控制角色移动,GetAsyncKeyState读取玩家操作,至于如何实现一键一动,请参考GetAsyncKeyState函数实现一键一动-CSDN博客

2.操作判断

        用玩家试图移动到的位置对应地图上的值进行判断。比如遇到monster,则调用Battle函数;遇到门要判断有无相应颜色的钥匙,打开要消耗一把钥匙。有效操作后要把相应位置换为空地,所有无效操作后比如撞墙,都要把玩家坐标重置回操作前的坐标。

3.Battle函数

        采用回合制,玩家先攻击,然后怪物,直至一方生命值变为0。造成的伤害为  己方攻击 - 对方防御。杀死怪物后会获得经验、金币

4.特殊物品和功能

        防御宝石(红)、攻击宝石(蓝),剑,盾,可以增加玩家属性。经验值大于当前等级*50即可升级,升级会消耗经验增加生命上限及攻击和防御。两种恢复药水分别加20和50的血,但血量不能超过上限,溢出的会被浪费。钥匙分为黄钥匙和蓝钥匙。

        上下楼梯需判断玩家试图走的位置有无障碍物,如果有,则玩家从其他方向出来

        只能用ESC键退出游戏

4.使游戏更有趣的一些函数

        与贤者(Saint)、女神、或公主的对话,镐子,怪物之书(可计算怪物对玩家造成的伤害)。此处隐藏着我设计的几个彩蛋:与贤者的对话中有着结局的伏笔与游戏的部分攻略;向女神供奉需要金币,并且第一次供奉没有任何奖励;第三层的公主是假的,必须在遇到她后通过再次向女神供奉才能打开通往第四层的楼梯,从而拯救真正的公主;镐子前面不能用,要救出公主必须要用镐子

#include"head.hpp"
int OfferMoneyTimes = 0;//供奉给女神像的次数
int meetSage = 0;
int meetPrincess = 0;

//撞墙与否
int judge_hit(int value)
{
	if (value == 0 || value == 1 || value == 52 || value == 53)
	{
		return 0;
	}
	return 1;
}
//没撞墙时
// 设置新坐标
void set_new_position(int position[], int r, int c)
{
	position[1] = r;
	position[2] = c;
}

//对战
void PK(Player& p, const Monster& m)
{
	p.hp -= Damage(p, m);
}

//计算怪物对玩家伤害
int Damage(Player& p, const Monster& m)
{
	int hp = p.hp;
	int l = m.hp;
	if (p.atk - m.def >= l)  //一击毙命
		return 0;
	while (hp > 0 && l > 0)
	{
		if (p.def < m.atk)
			hp -= m.atk - p.def;
		if (m.def < p.atk)
			l -= p.atk - m.def;
	}
	if (hp <= 0)
		return p.hp; //死亡
	else
		return p.hp - hp;
}

//升级
//经验要求暂定为,50*Lv;   注意连续升级的情况!
//提升:血量加 100, 攻击 加5,防御加 5
void LvUp(Player& p)
{
	p.hp_limit += 50;
	p.atk += 2;
	p.def += 2;
	p.Lv += 1;
	musicLvUp();
	PrintLvUp();
}

void Judge_and_LvUp(Player& p)
{
	while (p.Exp >= p.Lv * 50)
	{
		p.Exp -= p.Lv * 50;
		LvUp(p);
	}
}


//战斗
int Battle(int map[][COL], Player& p, Monster& m, char* name, \
	int r1, int c1, int r, int c, int hp,int direction_picture_number)//传入名字
{
	PK(p, m);
	if (p.hp)//还有血量则继续执行
	{
		//改地图
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		PrintMap(Map[p.position[0]],p);
		PrintInfor(name, hp - p.hp, m.money, m.exp); //图形化展示信息
		p.money += m.money;
		p.Exp += m.exp;
		Judge_and_LvUp(p);
		return 0;
	}
	//坐标重置回来
	set_new_position(p.position, r1, c1);
	return 2; //死亡

}

void MeetGodness(Player& p, int map[][COL], int r1,int c1,int r,int c)   //遇见后要消失!
{
	if (OfferMoneyTimes == 2 && meetPrincess==0)
	{
		//玩家坐标重置回来 //女神像不消失!
		set_new_position(p.position, r1, c1);
		return;
	}
	musicMeet();
	int cost = 50* (OfferMoneyTimes + 1);
	std::string message1 = "\n\nWould you like to offer \n" + std::to_string(cost) + " gold coins to the goddess?\n\nYes: 1  NO: 2";
	std::string message2 = "\n\nWould you offer all your money\nto the goddess for a miracle?\n\nYes: 1  NO: 2";
	char message3[] = "\n\n\nA new entrance is now opened";
	if (OfferMoneyTimes < 2)
		PrintSpecialInfor(message1.c_str());
	//else if (OfferMoneyTimes == 2 && meetPrincess) //已经供奉了两次,必须在遇到公主之后
	//	PrintSpecialInfor(message2.c_str());

	if (OfferMoneyTimes == 2 && meetPrincess)//第三次供奉,必须在遇到公主之后
	{
		PrintSpecialInfor(message2.c_str());
		while (1)
		{
			Sleep(70);
			if (GetAsyncKeyState(VK_NUMPAD1) & 0x8000) //同意
			{
				while (GetAsyncKeyState(VK_NUMPAD1) & 0x8000)
					Sleep(30);
				OfferMoneyTimes += 1;
				map[r][c] = 7;   //女神像消失
				//玩家坐标重置回来 
				set_new_position(p.position, r1, c1);
				p.money = 0;
				musicLvUp();
				Map[2][8][11] = 11;//第三楼出现楼梯,需要三维数组!
				PrintSpecialInfor(message3);
				exit();
				return;
			}

			if (GetAsyncKeyState(VK_NUMPAD2) & 0x8000) //不同意
			{
				while (GetAsyncKeyState(VK_NUMPAD2) & 0x8000)
					Sleep(30);
				//玩家坐标重置回来
				set_new_position(p.position, r1, c1);
				return;
			}
		}
	}

	while (1)  //前两次供奉
	{
		Sleep(70);
		if (GetAsyncKeyState(VK_NUMPAD1) & 0x8000) //同意
		{
			while (GetAsyncKeyState(VK_NUMPAD1) & 0x8000)
				Sleep(30);
			if (p.money >=  cost)
			{
				p.money -=  cost;
				OfferMoneyTimes += 1;
				if (OfferMoneyTimes == 1)
				{
					map[r][c] = 7;   //女神像消失
					//玩家坐标重置回来
					set_new_position(p.position, r1, c1);
					PrintSpecialInfor("\n\n\nYou get nothing!");
					Sleep(600);
					return;
				}//啥都没有,哈哈哈
				else if (OfferMoneyTimes == 2)//得一个生命宝石
				{
					musicLvUp();
					int defence = 2;
					p.def += defence;
					PrintLifeGem(defence);
					//女神像不消失!
					//玩家坐标重置回来
					set_new_position(p.position, r1, c1);
					return;
				}
				else
					return;
			}
			else
			{
				//玩家坐标重置回来
				set_new_position(p.position, r1, c1);
				PrintSpecialInfor("\n\n\nYour money is not enough!");
				Sleep(600);
				return;
			}
		}
		if (GetAsyncKeyState(VK_NUMPAD2) & 0x8000) //不同意
		{
			while (GetAsyncKeyState(VK_NUMPAD2) & 0x8000)
				Sleep(30);
			//玩家坐标重置回来
			set_new_position(p.position, r1, c1);
			return;
		}
	}
}

int ValidMove(int map[][COL], Player& p, int r, int c, int r1, int c1, \
	int direction_picture_number,int direction) //direction 4 5 6 7分别表示上下左右
{
	int hp = p.hp;

	if (map[r][c] == 39)  //找到公主——胜利
	{
		meetPrincess += 1;
		set_new_position(p.position, r1, c1);//坐标重置回来
		if (meetPrincess == 1)
		{
			musicMeet();
			PrintFalsePrincess();
			map[r][c] = 7;//假公主消失
			return 0;
		}
		return 3;//胜利
	}

	//空地
	if (map[r][c] == 7)
	{
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		return 0;
	}

	if (map[r][c] == 51) //贤者
	{
		meetSage += 1;
		set_new_position(p.position, r1, c1);//坐标重置回来
		musicMeet();
		if(meetSage==1)
		{
			char message1[] = "\n\nThe tower seems a bit strange\n\nI'm not sure if Princess is here";
			char message2[] = "\n\nThe tower is extremely dangerous\n\nThis is the Magic Book";
			char message3[] = "\n\nIt can turn souls of the monsters \n\nkilled into Exp to strengthen you";
			char message4[] = "\n\nThe Monster Encyclopedia in it \n\ncontains the information I know\n(Press e to open or close)";
			char message5[] = "\nAlso\n\nthere might be something good\n\n on the third floor";
			char message6[] = "\n\nRemember,solving a problem is  \n\nnever confined to a single way";
			char message7[] = "\n\n\nGood luck to you!";
			PrintSpecialInfor(message1);
			exit();
			PrintSpecialInfor(message2);
			exit();
			PrintSpecialInfor(message3);
			exit();
			PrintSpecialInfor(message4);
			exit();
			PrintSpecialInfor(message5);
			exit();
			PrintSpecialInfor(message6);
			exit();
			PrintSpecialInfor(message7);
			exit();
		}
		else
		{
			//char message1[] = "\n\nGood job!\n\nYou've made it to the second floor";
			char message1[] = "\n\nI've found Princess is here,\n\nbut I'm little confused...";
			char message2[] = "\n\nBy the way,\n\nDef may weigh more than Ack";
			char message3[] = "\n\nHere is a Moderate Healing Potion.\n\nGood luck!";
			PrintSpecialInfor(message1);
			exit();
			PrintSpecialInfor(message2);
			exit();
			PrintSpecialInfor(message3);
			exit();
			//获得中等恢复药水
			musicPickup();
			if (p.hp + 50 > p.hp_limit)
			{
				p.hp = p.hp_limit;
			}
			else
			{
				p.hp += 50;
			}
			char name[] = "Moderate Healing Potion";
			PrintInfor(name, p.hp - hp);
		}
		map[r][c] = 7;//贤者消失
		return 0;
	}
	//钥匙
		//黄色
	if (map[r][c] == 4)
	{
		musicPickup();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.yellow_key += 1;
		return 0;
	}

	if (map[r][c] == 17)  //蓝色钥匙
	{
		musicPickup();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.blue_key += 1;
		return 0;
	}
	//门:有没有钥匙  
		// 5——黄色门
	if (map[r][c] == 5)
	{
		if (p.yellow_key < 1)
		{
			//坐标重置回来
			set_new_position(p.position, r1, c1);
			PrintNoKey();
			return 0;
		}
		//有钥匙
		musicEnter();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.yellow_key -= 1;
		return 0;
	}

	if (map[r][c] == 18)   //蓝色门
	{
		if (p.blue_key < 1)
		{
			//坐标重置回来
			set_new_position(p.position, r1, c1);
			PrintNoKey();
			return 0;
		}
		//有钥匙
		musicEnter();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.blue_key -= 1;
		return 0;
	}

	//怪物:死亡或击败,击败会获得经验与金币   判断血量
		//绿色史莱姆酱 6
	if (map[r][c] == 6)
	{
		musicBattle();
		char name[] = "Green Slime";//传入名字
		return Battle(map, p, GreenSlime, name, r1, c1, r, c, hp, direction_picture_number);
	}

	//红色史莱姆酱 9
	if (map[r][c] == 9)
	{
		musicBattle();
		char name[] = "Red Slime";//传入名字
		return Battle(map, p, RedSlime, name, r1, c1, r, c, hp, direction_picture_number);
	}

	//蝙蝠   30 bat B   
	if (map[r][c] == 30)
	{
		musicBattle();
		char bt[] = "Bat";//传入名字
		return Battle(map, p, Bat, bt, r1, c1, r, c, hp, direction_picture_number);
	}
	//骷髅  31 骷髅 S 
	if (map[r][c] == 31)
	{
		musicBattle();
		char name[] = "Skeleton";//传入名字
		return Battle(map, p, Skeleton, name, r1, c1, r, c, hp, direction_picture_number);
	}
	//骷髅士兵  32  
	if (map[r][c] == 32)
	{
		musicBattle();
		char name[] = "Skeleton Soldier";//传入名字
		return Battle(map, p, SkeletonSoldier, name, r1, c1, r, c, hp, direction_picture_number);
	}
	//巫师  33  
	if (map[r][c] == 33)
	{
		musicBattle();
		char name[] = "Wizard";//传入名字
		return Battle(map, p, Wizard, name, r1, c1, r, c, hp, direction_picture_number);
	}
	//魔王  38  
	if (map[r][c] == 38)
	{
		musicBattle();
		char name[] = "Demon King";//传入名字
		return Battle(map, p, DemonKing, name, r1, c1, r, c, hp, direction_picture_number);
	}
	//不可战胜的魔王 54
	if (map[r][c] == 54)
	{
		musicBattle();
		char name[] = "Demon Emperor";//传入名字
		return Battle(map, p, DemonEmperor, name, r1, c1, r, c, hp, direction_picture_number);
	}
	// 药水   2 - minor_healing_potion h  3 - moderate_healing_potion H
		//minor
	if (map[r][c] == 2)
	{
		musicPickup();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		if (p.hp + 20 > p.hp_limit)
		{
			p.hp = p.hp_limit;
		}
		else
		{
			p.hp += 20;
		}
		PrintMap(Map[p.position[0]], p);
		char name[] = "Minor Healing Potion";
		PrintInfor(name, p.hp - hp);
		_kbhit();
		return 0;
	}
	//moderate
	if (map[r][c] == 3)
	{
		musicPickup();
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		if (p.hp + 50 > p.hp_limit)
		{
			p.hp = p.hp_limit;
		}
		else
		{
			p.hp += 50;
		}
		PrintMap(Map[p.position[0]], p);
		char name[] = "Moderate Healing Potion";
		PrintInfor(name, p.hp - hp);
		return 0;
	}

	if (map[r][c] == 22)//盾
	{
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.def += 10;
		musicPickup();
		PrintMap(Map[p.position[0]], p);
		char name[] = "Boko Shield";
		PrintShield(name,10); //防御加10
		return 0;
	}

	if (map[r][c] == 21)//剑
	{
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.atk += 10;
		musicPickup();
		PrintMap(Map[p.position[0]], p);
		char name[] = "Boko Sword";
		PrintSword(name, 10); //攻击加10
		return 0;
	}

	if (map[r][c] == 24)//镐子
	{
		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.pickaxe += 1;
		musicPickup();
		PrintMap(Map[p.position[0]], p);
		char message[] = "\n\n\nYou get a Pickaxe!";
		PrintSpecialInfor(message);
		exit();
		return 0;
	}

	if (map[r][c] == 20)//防御宝石
	{
		int defence = 2;

		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.def += defence;
		musicPickup();
		PrintMap(Map[p.position[0]], p);
		PrintLifeGem(defence);
		return 0;
	}

	if (map[r][c] == 19)//攻击宝石
	{
		int attack = 2;

		map[r1][c1] = 7;
		map[r][c] = direction_picture_number;
		p.atk += attack;
		musicPickup();
		PrintMap(Map[p.position[0]], p);
		PrintAttackGem(attack);
		return 0;
	}
	
	if (map[r][c] == 50) //女神像
	{
		MeetGodness(p,map,r1,c1,r,c);
		return 0;
	}
	//上楼或下楼  11 upstairs +   12 downstairs -
	  //上
	if (map[r][c] == 11)
	{
		map[r1][c1] = 7;
		p.position[0] += 1; //加一层
		return direction;
	}
	//下
	if (map[r][c] == 12)
	{
		map[r1][c1] = 7;
		p.position[0] -= 1; //加一层
		return direction;
	}
	
	return 0;
}

int afterPress(int map[][COL], Player& p,int r,int c,int r1,int c1,\
	int direction_picture_number,int direction)//4 5 6 7分别表示上下左右
{
	if (judge_hit(map[r][c]))//没撞墙则执行
	{
		set_new_position(p.position, r, c);
		return ValidMove(map, p, r, c, r1, c1, direction_picture_number,direction);
	}
	//重置
	r = r1;c = c1;
	return 19;//表示无效输入
}

int play(int map[][COL],Player &p)    //玩家移动
{
	int r = p.position[1];
	int c = p.position[2];
	//direction 
	int up = 4;int down = 5;int left = 6;int right = 7;
	//备份
	int r1 = r; 
	int c1 = c;
	int hp = p.hp;
	int ret;   //接收afterPress的值,并判断

	//按一个键走好几步——通过sleep解决
	while (true)
	{
		Sleep(70);
		if ((GetAsyncKeyState(VK_LEFT) & 0x8000) ||(GetAsyncKeyState('A') & 0x8000))
		{ // 检测左键,a不分大小写,都可以实现。注意(GetAsyncKeyState('a')有问题,不起作用!
			while ((GetAsyncKeyState(VK_LEFT) & 0x8000) || (GetAsyncKeyState('A') & 0x8000))
			{
				Sleep(30);
			}//实现一键一动,松开时才移动
			ret=afterPress(map, p, r, c - 1, r1, c1,35,left);//35是向左的素材的编号
			if (ret != 19)
				return ret;
		}
		else if ((GetAsyncKeyState(VK_RIGHT) & 0x8000) || (GetAsyncKeyState('D') & 0x8000))
		{ // 检测右键
			while ((GetAsyncKeyState(VK_RIGHT) & 0x8000) || (GetAsyncKeyState('D') & 0x8000))
			{
				Sleep(30);
			}
			ret = afterPress(map, p, r, c + 1, r1, c1,36,right);//向右
			if (ret != 19)
				return ret;
		}
		else if ((GetAsyncKeyState(VK_UP) & 0x8000) || (GetAsyncKeyState('W') & 0x8000))
		{ // 检测上键
			while ((GetAsyncKeyState(VK_UP) & 0x8000) || (GetAsyncKeyState('W') & 0x8000))
			{
				Sleep(30);
			}
			ret = afterPress(map, p, r-1, c , r1, c1,37,up);
			if (ret != 19)
				return ret;
		}
		else if ((GetAsyncKeyState(VK_DOWN) & 0x8000) || (GetAsyncKeyState('S') & 0x8000))
		{ // 检测下键
			while ((GetAsyncKeyState(VK_DOWN) & 0x8000) || (GetAsyncKeyState('S') & 0x8000))
			{
				Sleep(30);
			}
			ret = afterPress(map, p, r + 1, c, r1, c1,8,down);
			if (ret != 19)
				return ret;
		}

		//镐子 p
		else if (GetAsyncKeyState('P') & 0x8000)
		{ // 检测p键
			while (GetAsyncKeyState('P') & 0x8000)
			{
				Sleep(30);
			}
			if (p.pickaxe <= 0)
				continue;
			char message[] = "\n\n\nYou have destroyed a wall!";
			PrintUsePickaxe();
			//Sleep(200);
			while (true)
			{
				if (GetAsyncKeyState('P') & 0x8000)
				{//再次按 p 取消
					while (GetAsyncKeyState('P') & 0x8000)
					{
						Sleep(30);
					}
					return 0;
				}
				else if ((GetAsyncKeyState(VK_LEFT) & 0x8000)|| (GetAsyncKeyState('A') & 0x8000))
				{ // 镐子 左键
					while ((GetAsyncKeyState(VK_LEFT) & 0x8000)|| (GetAsyncKeyState('A') & 0x8000))
					{
						Sleep(30);
					}
					if (map[r][c - 1] == 1)
					{
						PrintMessage(message);
						map[r][c - 1] = 7;
						p.pickaxe -= 1;
					}
					return 0;
				}

				else if ((GetAsyncKeyState(VK_RIGHT) & 0x8000) ||(GetAsyncKeyState('D') & 0x8000))
				{ // 镐子 右键
					while ((GetAsyncKeyState(VK_RIGHT) & 0x8000) || (GetAsyncKeyState('D') & 0x8000))
					{
						Sleep(30);
					}
					if (map[r][c + 1] == 1)
					{
						PrintMessage(message);
						map[r][c + 1] = 7;
						p.pickaxe -= 1;
					}
					return 0;
				}

				else if ((GetAsyncKeyState(VK_UP) & 0x8000)|| (GetAsyncKeyState('W') & 0x8000))
				{ // 镐子 上键
					while ((GetAsyncKeyState(VK_UP) & 0x8000)|| (GetAsyncKeyState('W') & 0x8000))
					{
						Sleep(30);
					}
					if (map[r - 1][c] == 1)
					{
						PrintMessage(message);
						map[r - 1][c] = 7;
						p.pickaxe -= 1;
					}
					return 0;
				}

				else if ((GetAsyncKeyState(VK_DOWN) & 0x8000) || (GetAsyncKeyState('S') & 0x8000))
				{ // 镐子 下键
					while ((GetAsyncKeyState(VK_DOWN) & 0x8000) || (GetAsyncKeyState('S') & 0x8000))
					{
						Sleep(30);
					}
					if (map[r + 1][c] == 1)
					{
						PrintMessage(message);
						map[r + 1][c] = 7;
						p.pickaxe -= 1;
					}
					return 0;
				}
			}
		}

		//图鉴 e
		else if ((GetAsyncKeyState('E') & 0x8000) && meetSage)
		{ // 检测e键
			while (GetAsyncKeyState('E') & 0x8000)
			{
				Sleep(30);
			}
			musicEncyclopedia();
			MonsterEncyclopedia(p);
			return 0;
		}
		//退出!
		else if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
		{
			return -12;
		}
	}
	return 0;
}

 //此处传进来的map是所有楼层的!
void ChangeFloor(int Map[FLOOR][ROW][COL],Player& P,int ret)
{
	musicEnter();
	if (ret == 4 && Map[P.position[0]][P.position[1] - 1][P.position[2]] == 7)//向上并且楼梯上一格是空
	{
		P.position[1] -= 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else if (ret == 5 && Map[P.position[0]][P.position[1] + 1][P.position[2]] == 7)
	{
		P.position[1] += 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else if (ret == 6 && Map[P.position[0]][P.position[1]][P.position[2] - 1] == 7)
	{
		P.position[2] -= 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else if (ret == 7 && Map[P.position[0]][P.position[1]][P.position[2] + 1] == 7)
	{
		P.position[2] += 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}

	//默认位置:门上一格是空,门上,否则去其他的空地
	else if (Map[P.position[0]][P.position[1] - 1][P.position[2]] == 7)
	{
		P.position[1] -= 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else if (Map[P.position[0]][P.position[1] + 1][P.position[2]] == 7)
	{
		P.position[1] += 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else if (Map[P.position[0]][P.position[1]][P.position[2] + 1] == 7)
	{
		P.position[2] += 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
	else
	{
		P.position[2] -= 1;
		Map[P.position[0]][P.position[1]][P.position[2]] = 8;
	}
}

 4.visualization源文件

1.使用BeginBatchDraw() 与 EndBatchDraw()减少绘图过程中的屏幕刷新次数,从而提高性能。

2.RGB用来控制颜色,代码中使用它来实现颜色渐变

#include"head.hpp"
IMAGE images[60];

void LoadImagesHelper(int n,int Width,int Height)
{
	//std::string location = "D:\\Merrik\\code\\小游戏\\Tower of the Sorcerer\\materials\\" + std::to_string(n) + ".png";
	std::string location = std::to_string(n) + ".png";

	loadimage(&images[n], location.c_str(), Width, Height);  //最后两个数字表示缩放后的大小
}

void LoadImages()       // 加载图片素材
{
	for (int i = 0;i <= 40;i++)
		LoadImagesHelper(i,50,50);
	//大图标,用于显示
	//loadimage(&images[49],  "D:\\Merrik\\code\\小游戏\\Tower of the Sorcerer\\materials\\8.png", 100, 100);
	for (int i = 41;i <= 48;i++)
		LoadImagesHelper(i, 100, 100);

	for (int i = 50;i <= 54;i++)
		LoadImagesHelper(i, 50, 50);
	//开始界面
	loadimage(&images[49], "49.jpg", 850, 650);
}

RECT R = { 0, 00, 850, 650 };//矩形指针,用于打印游戏开始画面
void StartImage()
{
	BeginBatchDraw();
	//setbkcolor(BLACK);
	setfillcolor(BLACK);
	setbkmode(TRANSPARENT);
	//solidrectangle(0, 00, 850, 650); // 填充矩形

	putimage(0, 0, &images[49]);//

	settextstyle(70, 0, "Consolas");
	drawtext("\nTower of Sorcerer", &R, DT_CENTER);

	EndBatchDraw();
	BeginBatchDraw();
	while (1)
	{
		Sleep(70);
		if ((GetAsyncKeyState(VK_SPACE) & 0x8000) || (GetAsyncKeyState(VK_RETURN) & 0x8000))
			break;
	}

	settextstyle(30, 0, "Consolas");
	drawtext(\
		"\n\n\n\n\n\n\n\n\n\n\n\n\n\nThe princess has been captured and imprisoned by the Demon.\nBut nobody knows where she is.\nYou've found clues leading to this tower\n so you come here ..."\
		, &R, DT_CENTER);       //The princess has been captured by the devil You found clues about her that led to this tower ,       Please use your wisdom and courage                                //删除了\n\n(Press space key to continue)                                         
	EndBatchDraw();
	Sleep(500);
	while (1)
	{
		Sleep(70);
		if ((GetAsyncKeyState(VK_SPACE) & 0x8000) || (GetAsyncKeyState(VK_RETURN) & 0x8000))
			break;
	}
}

void InventInfor()   //打印制作信息
{
	BeginBatchDraw();
	cleardevice();
	settextstyle(70, 0, "Consolas");
	drawtext("\n\n Designed by Merrik.", &R, DT_CENTER);
	settextstyle(40, 0, "Consolas");
	drawtext("\n\n\n\n\n\n\n\n\n\nThis game would not have been possible\n without the support of my dear roomates\nor the advice of Leanne", &R, DT_CENTER);//
	EndBatchDraw();
	//musicGameLoading();
	Sleep(5000);
	//mciSendString("close GameLoading ", NULL, 0, NULL);
}

void InitImage()
{
	BeginBatchDraw();
	cleardevice();
	//边框上的图片
	for (int i = 0; i < ROW + 4; ++i)  //上边框
		putimage(i * 50, 0, &images[0]);
	for (int i = 0; i < ROW + 4; ++i)  //下边框
		putimage(i * 50, 600, &images[0]);
	for (int i = 1; i <= COL -1; ++i)  //左边框
		putimage(0, i * 50, &images[0]);
	for (int i = 1; i <= COL - 1; ++i)  //右边框
		putimage(800, i * 50, &images[0]);
	//for (int i = 1; i <= COL - 1; ++i)  //地图左框
	//	putimage(200, i * 50, &images[0]);
	putimage(50, 50, &images[48]); //人
	putimage(50, 150, &images[14]); //hp
	putimage(50, 200, &images[40]); //hp_limit
	putimage(50, 250, &images[13]); //atk
	putimage(50, 300, &images[15]); //def
	putimage(50, 350, &images[16]); //money
	putimage(50, 400, &images[4]); // yellow key
	putimage(50, 450, &images[17]);//blue key
	putimage(50, 500, &images[25]);// red key
	putimage(50, 550, &images[24]); //镐子
	EndBatchDraw();
}
//辅助函数,用于右对齐
int countDigits(int number) {
	if (number == 0) return 1; // 0是一个特殊情况,它有1位

	int count = 0;
	while (number > 0) {
		number /= 10;
		++count;
	}
	return count;
}

void PrintMap(int map[][COL], Player& p)
{
	BeginBatchDraw();
	for (int i = 1; i < ROW-1; ++i) {  //边框都是固定的,不用重复打印
		for (int j = 1; j < COL-1; ++j)
		{
			putimage(200+j * 50, i * 50, &images[map[i][j]]); // 显示图像
		}
	}
	for (int i = 1; i <= COL - 1; ++i)  //地图左框
		putimage(200, i * 50, &images[0]);

	settextcolor(WHITE);
	settextstyle(40, 0,  "Consolas");
	outtextxy(155, 50,  "Lv");
	settextstyle(30, 0,  "Consolas");
	setfillcolor(getbkcolor());
	solidrectangle(150, 100, 200, 150);
	solidrectangle(100, 150, 165, 600); //先清空之前打印的数据
	outtextxy(190 - 15 * countDigits(p.Lv), 100, std::to_string(p.Lv).c_str());	//把数字转化成字符串
	outtextxy(165 - 15 * countDigits(p.hp), 160, std::to_string(p.hp).c_str());

	outtextxy(165 - 15 * countDigits(p.hp_limit), 210, std::to_string(p.hp_limit).c_str());
	outtextxy(165 - 15 * countDigits(p.atk), 260, std::to_string(p.atk).c_str());
	outtextxy(165 - 15 * countDigits(p.def), 310, std::to_string(p.def).c_str());
	outtextxy(165 - 15 * countDigits(p.money), 360, std::to_string(p.money).c_str());
	outtextxy(165 - 15 * countDigits(p.yellow_key), 410, std::to_string(p.yellow_key).c_str());
	outtextxy(165 - 15 * countDigits(p.blue_key), 460, std::to_string(p.blue_key).c_str());
	outtextxy(165 - 15 * countDigits(p.red_key), 510, std::to_string(p.red_key).c_str());
	outtextxy(165 - 15 * countDigits(p.pickaxe), 560, std::to_string(p.pickaxe).c_str());
	EndBatchDraw();
}

RECT R1 = { 220,230,720, 450 };//矩形指针R1,用于打印游戏进程中信息
void PrintMessage(const char* message)
{
	setbkmode(TRANSPARENT);				//设置字体为透明
	settextcolor(BLACK);
	for (int i = 256;i > 64;i -= 5)
	{                                   //双缓冲技术来避免绘制时图像闪烁,效果显著
		BeginBatchDraw();               //与下面的EndBatchDraw();必须成对出现
		settextstyle(30, 0, "Consolas");
		setfillcolor(RGB(i, 0, 0));//第一个数字表示红色
		solidrectangle(220, 230, 720, 450); // 填充矩形
		drawtext(message, &R1, DT_CENTER);
		//在矩形区域R1内输入文字,水平居中,垂直居中
		Sleep(30);
		EndBatchDraw();
	}
}

void PrintInfor(char*name,int d_hp,int money,int exp) //Battle
{
	
	std::string n = name; // 将字符指针转换为std::string
	std::string message = "\n\nYou've beaten the " + n + "\nYou lost " + std::to_string(d_hp) + \
		" HP in the battle\nYou get " + std::to_string(money) + " gold coins\n";
	PrintMessage(message.c_str());
}

void PrintInfor(char* name, int addHP) //potion
{
	//"You find a minor healing potion and get 20 hp"
	std::string n = name; // 将字符指针转换为std::string
	std::string message = "\n\nYou find a\n" + n + "\nand get " + std::to_string(addHP) + " HP";
	PrintMessage(message.c_str());
}

void PrintNoKey()//no enough key
{
	std::string message = "\n\nYou don't have enough keys! \nGo around and find one!";
	PrintMessage(message.c_str());
}

void PrintLvUp()
{
	setbkmode(TRANSPARENT);				//设置字体为透明
	settextcolor(RED);
	for (int i = 256;i > 64;i -= 5)
	{                                   //双缓冲技术来避免绘制时图像闪烁,效果显著
		BeginBatchDraw();               //与下面的EndBatchDraw();必须成对出现
		setfillcolor(RGB(i, i, 0));
		solidrectangle(220, 230, 720, 450); // 填充矩形
		settextstyle(50, 0, "Consolas");
		drawtext("\nLv up!", &R1, DT_CENTER);

		settextstyle(30, 0, "Consolas");
		drawtext("\n\n\n\nYou get 2 Atk  2 Def!\nMax HP limit increased by 100", &R1, DT_CENTER);
		Sleep(30);
		EndBatchDraw();
	}
}

void PrintLifeGem(int defence)
{
	std::string message = "\n\nYou get a Life Gem \n\nand get " + std::to_string(defence)+" Def";
	PrintMessage(message.c_str());
}

void PrintAttackGem(int attack)
{
	std::string message = "\n\nYou get an Attack Gem \n\nand get "+ std::to_string(attack) + " Atk";
	PrintMessage(message.c_str());
}

void  PrintSpecialInfor(const char* name)
{
	BeginBatchDraw();
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);

	setfillcolor(RGB(255, 255, 0));
	solidrectangle(220, 230, 720, 450); // 填充矩形
	settextstyle(30, 0, "Consolas");
	drawtext(name, &R1, DT_CENTER);
	EndBatchDraw();
}
void exit()
{
	Sleep(500);
	while (1)
	{
		Sleep(70);
		if (GetAsyncKeyState(VK_SPACE) & 0x8000)
			break;
	}
}

void PrintFalsePrincess()
{
	char message[] = "\n\n You reached here in a good mood\n\nthinking you've made it...";
	char message2[] = "\n\n\nbut...";
	char message3[] = "\n\nThe princess is fake.\n\n The true one is hided elsewhere!";
	char message4[] = "\n\nYou have to utilize your wisdom\n\nto find the true one";

	PrintSpecialInfor(message);
	exit();
	PrintSpecialInfor(message2);
	exit();
	PrintSpecialInfor(message3);
	exit();
	PrintSpecialInfor(message4);
	exit();
}

void PrintLose()
{
	char message[] = "\n\nIt's a reget that\n\n you have lost your life.";
	PrintSpecialInfor(message);
	exit();
}

void PrintWin()
{
	char message[] = "\nCongratulations!\n\n With your great effort\n you've saved the true princess!";
	PrintSpecialInfor(message);
	exit();
}

void PrintShield(char* name, int defence)
{
	std::string n = name;
	std::string message = "\n\nYou get a " + n + "\n\nand get " + std::to_string(defence) + " Def";
	PrintSpecialInfor(message.c_str());
	exit();
}

void PrintSword(char* name, int attack)
{
	std::string n = name;
	std::string message = "\n\nYou get a " + n + "\n\nand get " + std::to_string(attack) + " Atk";
	PrintSpecialInfor(message.c_str());
	exit();
}

void PrintUsePickaxe()
{
	setbkmode(TRANSPARENT);
	settextcolor(WHITE);
	settextstyle(40, 0, "Consolas");
	drawtext("\n\nUsing Pickaxe", &R1, DT_CENTER);
}
//图鉴
RECT R2 = { 300, 100, 750, 550 };
void MonsterEncyclopedia(Player& p)
{
	BeginBatchDraw();
	setbkmode(TRANSPARENT);
	settextcolor(BLACK);

	setfillcolor(RGB(255, 255, 0));
	solidrectangle(300, 80, 750, 580); // 填充矩形
	settextstyle(35, 0, "Consolas");

	drawtext("Monster Encyclopedia", &R2, DT_CENTER);

	putimage(320, 150, &images[41]); //绿色史莱姆
	putimage(320, 250, &images[42]); //红色史莱姆
	putimage(320, 350, &images[43]); //蝙蝠
	putimage(320, 450, &images[47]); //骷髅
	putimage(540, 150, &images[46]); //巫师
	putimage(540, 250, &images[44]); //骷髅士兵
	putimage(540, 350, &images[45]); //魔王

	settextstyle(30, 0, "Consolas");
	for(int i=0;i<4;i++)
		outtextxy(430, 160+100*i, "Damage");
	for (int i = 0;i < 3;i++)
		outtextxy(650, 160 + 100 * i, "Damage");
	
	int d = Damage(p, GreenSlime);    //打印数值
	outtextxy(500 - 15 * countDigits(d), 210, std::to_string(d).c_str());
	d = Damage(p, RedSlime);
	outtextxy(500 - 15 * countDigits(d), 310, std::to_string(d).c_str());
	d = Damage(p, Bat);
	outtextxy(500 - 15 * countDigits(d), 410, std::to_string(d).c_str());
	d = Damage(p, Skeleton);
	outtextxy(500 - 15 * countDigits(d), 510, std::to_string(d).c_str());
	d = Damage(p, Wizard);
	outtextxy(720 - 15 * countDigits(d), 210, std::to_string(d).c_str());
	d = Damage(p, SkeletonSoldier);
	outtextxy(720 - 15 * countDigits(d), 310, std::to_string(d).c_str());
	//d = Damage(p, DemonKing);
	outtextxy(720 - 45, 410,"???");

	EndBatchDraw();
	while (1)
	{
		Sleep(70);
		if ((GetAsyncKeyState(VK_SPACE) & 0x8000)|| (GetAsyncKeyState('e') & 0x8000)\
			|| (GetAsyncKeyState('E') & 0x8000)) 
		{
			while ((GetAsyncKeyState(VK_SPACE) & 0x8000) || (GetAsyncKeyState('e') & 0x8000)\
				|| (GetAsyncKeyState('E') & 0x8000))
			{
				Sleep(30);
			}
			break;
		}
	}
}

5.audio源文件

#include"head.hpp"
void musicGameLoading()  //真奇怪了,播放有卡顿?难道长一点的音频都不行吗
{
	mciSendString("open GameLoading.mp3 alias GameLoading", NULL, 0, NULL);
	mciSendString("play GameLoading wait", NULL, 0, NULL);
	mciSendString("close GameLoading ", NULL, 0, NULL);

}
void musicPickup()
{
	mciSendString("close pickup", NULL, 0, NULL);
	mciSendString("open pickup.mp3 alias pickup", NULL, 0, NULL);
	mciSendString("play pickup ", NULL, 0, NULL);
}

void musicBattle()
{
	mciSendString("open battle.mp3 alias battle", NULL, 0, NULL);
	mciSendString("play battle wait", NULL, 0, NULL);
	mciSendString("close battle", NULL, 0, NULL);
}

void musicEnter()
{
	mciSendString("close enter", NULL, 0, NULL);
	mciSendString("open in.mp3 alias enter", NULL, 0, NULL);
	mciSendString("play enter", NULL, 0, NULL);
}

void musicLvUp()
{
	mciSendString("close LvUp", NULL, 0, NULL);
	mciSendString("open LvUp.mp3 alias LvUp", NULL, 0, NULL);
	mciSendString("play LvUp", NULL, 0, NULL);
}

void musicDie()
{
	mciSendString("close die", NULL, 0, NULL);
	mciSendString("open die.mp3 alias die", NULL, 0, NULL);
	mciSendString("play die", NULL, 0, NULL);
}

void musicWin()
{
	mciSendString("close win", NULL, 0, NULL);
	mciSendString("open win.mp3 alias win", NULL, 0, NULL);
	mciSendString("play win", NULL, 0, NULL);
}

void musicEncyclopedia()
{
	mciSendString("close Encyclopedia", NULL, 0, NULL);
	mciSendString("open Encyclopedia.mp3 alias Encyclopedia", NULL, 0, NULL);
	mciSendString("play Encyclopedia", NULL, 0, NULL);
}

void musicMeet()
{
	mciSendString("close Godness", NULL, 0, NULL);
	mciSendString("open Godness.mp3 alias Godness", NULL, 0, NULL);
	mciSendString("play Godness", NULL, 0, NULL);
}

void closeMusic()
{
	mciSendString("close GameLoading ", NULL, 0, NULL);
	mciSendString("close pickup", NULL, 0, NULL);
	mciSendString("close battle", NULL, 0, NULL);
	mciSendString("close enter", NULL, 0, NULL);
	mciSendString("close LvUp", NULL, 0, NULL);
	mciSendString("close die", NULL, 0, NULL);
	mciSendString("close win", NULL, 0, NULL);
	mciSendString("close Encyclopedia", NULL, 0, NULL);
	mciSendString("close Godness", NULL, 0, NULL);

	mciSendString("close background", NULL, 0, NULL);
}

6.data源文件

        储存玩家、怪物属性,以及地图。玩家和怪物属性改动一定要谨慎,否则游戏难度会失衡

#include"head.hpp"
//可以考虑把地图放进文档中,通过读文档来进行地图生成

Monster::Monster(int hp, int atk, int def, int exp, int gold/* char* name*/) : hp(hp), atk(atk), def(def), exp(exp), money(gold) {

	// 这里可以添加一些初始化代码,如果需要的话
}

//创建对象
Monster GreenSlime(10, 7, 1, 5, 1);
Monster RedSlime(10, 10, 2, 10, 2);
Monster Bat(15, 15, 2, 15, 3);
Monster Skeleton(50, 20, 3, 20, 5);
Monster Wizard(50, 25, 3, 25, 7);
Monster SkeletonSoldier(60, 50, 5, 35, 10);
Monster DemonKing(400, 50, 5, 100, 30);
Monster DemonEmperor(1000, 100, 20, 500, 100);
//Monster Sele();


Player::Player()
{                    //初始:第一层 第六行 第二列 position[0] = 0; position[1] = 11;  position[2] = 7;
	                 //测试位置,公主房间 position[0] = 2; position[1] = 8;  position[2] = 10;
	position[0] = 0; position[1] = 11;  position[2] = 7;
	hp = 100;	hp_limit = hp;  atk = 5;	def = 0;	money = 0;
	Lv = 1;		Exp = 0;	yellow_key = 0;	blue_key = 0;
	red_key = 0; pickaxe = 0;
}


//地图,13*13,周围一圈为边界,中间的11*11为主地图r
//0 - border # 1 - wall # 2 - minor_healing_potion h  3 - modera_healing_potion H
// 4 - yellow key 'k'  5 - yellow door  'd' 
//6 - green slime  's '   7 - area	' '   8 - player P  
//10 magma M  11 upstairs +   12 downstairs -
//30及以后全是怪物  30 bat B   31 骷髅 S 

int Map[FLOOR][ROW][COL] = {
	{//1
			{0,0,0,0,0,0,0,0,0,0,0,0,0},
			{0,7,31,5,7,7,7,32,5,7,30,4,0},
			{0,2,7,1,22,7,1,1,1,11,1,5,0},
			{0,1,5,1,19,3,1,3,1,30,1,19,0},
			{0,20,7,1,4,4,1,5,1,30,1,5,0},
			{0,7,30,1,1,1,1,7,5,7,2,7,0},
			{0,1,5,1,4,7,6,7,1,1,1,1,0},
			{0,9,7,1,7,1,1,1,1,4,4,20,0},
			{0,7,1,1,6,1,3,30,9,7,7,9,0},
			{0,51,7,7,7,1,1,7,1,1,7,7,0},
			{0,4,1,7,1,1,4,7,7,7,6,7,0},
			{0,3,1,6,9,7,7,8,4,1,2,3,0},
			{0,0,0,0,0,0,0,0,0,0,0,0,0}
	},

	{//2
			{0,0,0,0,0,0,0,0,0,0,0,0,0},
			{0, 7,30,6, 7,7,7,9,7, 7,7,4,0},
			{0, 7, 1,1,32,1,5,1,1,12,7,51,0},
			{0, 7,19,1,19,1,6,7,1, 1,1,1,0},
			{0,31, 7,1,20,1,1,5,1,20,7,50,0},
			{0, 7,9,1, 7,3,1,7,5, 7,11, 7,0},
			{0, 1,5,1,1,1,1,30,1,1,1,5,0},
			{0, 7,7,1,3,7,1,17,1,2,7,6,0},
			{0, 7,1,1,1,5,1,1,1,7,9,7,0},
			{0, 7,1,30,30,19,1,20,33,30,7,7,0},
			{0, 7,7,7,1,7,1,5,1,7,7,31,0},
			{0,4,3,7,5,7,6,7,7,7,9,2,0},
			{0,0,0,0,0,0,0,0,0,0,0,0,0}
	},

	{//3
			{ 0,0,0,0,0,0,0,0,0,0,0,0,0 },
			{0,3,33,7,7,5,9,7,30,2,1,3,0},
			{0,33,7,7,7,1,7,9,7,7,1,21,0},
			{0,7,7,7,33,1,5,1,1,31,1,18,0},
			{0,31,33,31,17,1,30,19,1,7,7,7,0},
			{0,1,5,1,1,1,19,3,1,7,12,7,0},
			{0,2,7,20,19,1,53,53,53,53,53,53,0},
			{0,7,7,7,4,4,53,7,7,39,7,7,0},
			{0,33,7,24,7,50,53,7,7,7,7,7,0},//改回来!
			{0,18,1,1,7,7,53,53,53,38,53,53,0},
			{0,3,3,1,31,31,1,32,32,7,32,33,0},
			{0,3,22,1,31,32,18,7,7,7,32,33,0},
			{0,0,0,0,0,0,0,0,0,0,0,0,0}
	},
		
	{//4
			{0,0,0,0,0,0,0,0,0,0,0,0,0},
			{0, 38,54,18, 7,7,7,7,7, 1,32,7,0},
			{0, 7, 38,1,7,7,7,7,7,52,32,7,0},
			{0, 7, 32,1,7,7,39,7,7,1,32,7,0},
			{0, 7, 32,52,7,7,7,7,7,52,32,7,0},
			{0, 7,32,1, 52,1,52,1,52, 1,32, 7,0},
			{0, 7,32,32,32,32,32,32,32,32,32,7,0},
			{0, 7,7,7,7,7,7,7,7,7,7,7,0},
			{0, 32,7,7,7,7,7,7,7,7,7,12,0},
			{0, 38,32,7,7,7,7,7,7,7,7,7,0},
			{0, 38,38,32,7,7,7,7,7,3,7,7,0},
			{0, 17,38,38,32,7,7,7,7,7,7,7,0},
			{0,0,0,0,0,0,0,0,0,0,0,0,0}
	}
};

四 结语

        如果还想让游戏更有趣味性,可以参考以下意见:创建不同属性的角色? 增加宝箱,随机生成效果? 增加解谜?存档? 副手武器?  武器效果?  炸弹?  技能?职业? 魔药? 多门? 隐藏地图? 多地图?

        最后,祝大家顺利完成属于自己的独特魔塔!

你可能感兴趣的:(c++,游戏)