把以前写的魔塔游戏完善了一下
之前的魔塔游戏博客链接:https://blog.csdn.net/qq_41505957/article/details/103138305
代码及所有图片,音乐等资源:https://download.csdn.net/download/qq_41505957/12287289
增加内容如下:
1.增加了背景音乐(其实这个音乐我是不想加的,因为我感觉无所谓)
2.运行之后不会直接开始游戏了,而是有一个选择的画面
N 新的游戏
J 继续游戏
C 游戏说明
E 退出游戏
不同的按键会转换到不同的界面
开始游戏就是重新开始游戏了
继续游戏是当你在游戏过程中有保存过游戏的话,就按照这个进度来玩,如果没有保存过游戏呢,就是重新开始游戏了。
游戏说明就是游戏中的一些按键的操作,本来这个图我是准备做上面那个界面的,但是有点丑,后来我就改了一下,做这个了,反正这个也没人看。
3.增加了保存游戏的功能,在游戏中按Q键会跳出是否保存的界面,选择是会保存游戏,之后再次打开游戏的时候可以加载上次的游戏。
4.增加了9层地图,加上第一层一共10层地图,地图真的是难搞,下面是各个数字代表的东西。
0 墙
1 地板
2 蓝门
3 黄门
4 蓝水晶
5 红水晶
6 蓝钥匙
7 红钥匙
8 红药水
9 蓝药水
10 小蝙蝠
11 小巫师
12 小骷髅
13 大骷髅
14 绿史莱姆
15 红史莱姆
97 下楼梯子
98 上楼梯子
99 玩家
5.增加了玩家可以升级的功能,每次升级所需经验值=当前等级*1000。
6.修复了当我方防御大于敌方攻击的时候,战斗加血的bug,这个bug是由于我的计算减血量等于敌方攻击减我方防御,当敌方攻击
小于我方防御的时候,减的是一个负数,所以就加血了。
下面我来说一下我实现的过程和代码
开始游戏时的菜单:
最开始我做的比较简陋,后来就搜了一个图片,然后我用画图软件加了点字,然后把图片贴到画布上就可以了,再写一个函数用来接收键盘的输入,对应不同的键再有不同的处理
背景音乐:
一行代码,非常简单,注意音乐只能是wav格式,如果想要修改,把音乐复制到文件夹中,修改代码中的文件名就行了。如果没有wav格式的音乐,可以在网上搜一下在线MP3转wav。
void Music()
{
PlaySound(TEXT("1.wav"), 0, SND_FILENAME|SND_ASYNC|SND_LOOP);
}
地图的实现:
在最开始写的时候我的地图是存储在二维数组里面的,因为只有一层,所以用二维数组是比较方便的,现在由于增加的地图,而且还要有保存游戏的功能,所以二维数组是不够用的。
新的程序我使用的三维数组,分别代表层数,行,列。同时把地图存储在txt文件中,在开始游戏的时候读取文件中的地图存储在三维数组中。开始游戏的时候调用函数就可以了。
使用C语言中文件的读取功能,代码:
void NewGame()
{
initPlayer(); //初始化游戏角色信息
FILE *fp; //读取保存在map.txt中的地图
fp = fopen("map.txt", "r");
for(int k=0; k<10; k++)
for (int i = 0; i < 13; i++)
for(int j = 0; j < 13; j++)
fscanf(fp, "%d", &map[k][i][j]);
fclose(fp);
}
保存游戏
游戏中按Q键可以保存游戏。
保存游戏其实是和地图差不多,在我游戏的过程中三维数组的值是在不断改变的,当我保存游戏的时候,把三维数组中的值保存到txt文件中即可,需要一起保存的还有玩家的各项属性和位置。
void SaveGame()
{
FILE *fp;
fp = fopen("keepmap.txt", "w");
for (int k = 0; k < 10; k++) {
for (int i = 0; i < 13; i++) {
for (int j = 0; j < 13; j++)
fprintf(fp, "%d ", map[k][i][j]);
fprintf(fp, "\n");
}
fprintf(fp, "\n");
}
fprintf(fp, "%d\n", playerh);
fprintf(fp, "%d\n", playerx);
fprintf(fp, "%d\n", playery);
fprintf(fp, "%s\n", player.name);
fprintf(fp, "%d\n", player.HP);
fprintf(fp, "%d\n", player.MP);
fprintf(fp, "%d\n", player.DEF);
fprintf(fp, "%d\n", player.ATT);
fprintf(fp, "%d\n", player.Lv);
fprintf(fp, "%d\n", player.Exp);
fprintf(fp, "%d\n", player.Num_Blue_Key);
fprintf(fp, "%d\n", player.Num_Yellow_Key);
fclose(fp);
}
继续游戏
继续游戏可以继续上次的游戏,保存游戏后,即使关闭运行窗口,下次游戏将会重保存游戏的地方开始游戏。继续游戏后会读取keepmap.txt中的地图和人物属性。
void KeepGame()
{
FILE *fp; //读取保存在keepmap.txt中的地图
fp = fopen("keepmap.txt", "r");
for (int k = 0; k < 10; k++)
for (int i = 0; i < 13; i++)
for (int j = 0; j < 13; j++)
fscanf(fp, "%d", &map[k][i][j]);
fscanf(fp, "%d", &playerh);
fscanf(fp, "%d", &playerx);
fscanf(fp, "%d", &playery);
fscanf(fp, "%s", &player.name);
fscanf(fp, "%d", &player.HP);
fscanf(fp, "%d", &player.MP);
fscanf(fp, "%d", &player.DEF);
fscanf(fp, "%d", &player.ATT);
fscanf(fp, "%d", &player.Lv);
fscanf(fp, "%d", &player.Exp);
fscanf(fp, "%d", &player.Num_Blue_Key);
fscanf(fp, "%d", &player.Num_Yellow_Key);
fclose(fp);
}
上下楼的处理
在上下楼的时候,将会更改整个地图,相应的,人物的位置都将改变,这里我用一个函数来解决这个问题。
我用h代表层数,用0代表这层是下楼梯来的,1代表这层是上楼梯来的,记录上下楼梯的位置,之后就可以对玩家的x和y的坐标进行改变。
//根据不同楼层显示角色的初始位置
void Change(int h, int temp)
{
switch (h)
{
case 0:
if (temp == 0) {
playerx = 1;
playery = 2;
map[playerh][playerx][playery] = 99;
}
break;
case 1:
if (temp == 1) {
playerx = 11;
playery = 10;
map[playerh][playerx][playery] = 99;
}
else {
playerx = 2;
playery = 1;
map[playerh][playerx][playery] = 99;
}
break;
case 2:
if (temp == 1) {
playerx = 7;
playery = 2;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 8;
playery = 10;
map[playerh][playerx][playery] = 99;
}
break;
case 3:
if (temp == 1) {
playerx = 11;
playery = 2;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 4;
playery = 11;
map[playerh][playerx][playery] = 99;
}
break;
case 4:
if (temp == 1) {
playerx = 11;
playery = 5;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 1;
playery = 2;
map[playerh][playerx][playery] = 99;
}
break;
case 5:
if (temp == 1) {
playerx = 6;
playery = 7;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 4;
playery = 7;
map[playerh][playerx][playery] = 99;
}
break;
case 6:
if (temp == 1) {
playerx = 10;
playery = 6;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 2;
playery = 6;
map[playerh][playerx][playery] = 99;
}
break;
case 7:
if (temp == 1) {
playerx = 3;
playery = 8;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 3;
playery = 4;
map[playerh][playerx][playery] = 99;
}
break;
case 8:
if (temp == 1) {
playerx = 2;
playery = 11;
map[playerh][playerx][playery] = 99;
}
else
{
playerx = 10;
playery = 11;
map[playerh][playerx][playery] = 99;
}
break;
case 9:
if (temp == 1) {
playerx = 10;
playery = 6;
map[playerh][playerx][playery] = 99;
}
break;
}
}
战斗升级
这个没什么好说的,每次战斗结束后调用一下函数就可以了。
void CaLv()
{
if (player.Exp >= player.Lv * 1000) {
player.Exp -= player.Lv * 1000;
player.Lv++;
player.ATT += 10;
player.DEF += 10;
player.HP += 100;
}
}
修改了bug
一个小错误,在VS函数中加一个小判断
if (playDEF > monATT)
return 1;
部分游戏截图
注意,如果出现
error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
1>g:\windows kits\10\include\10.0.17763.0\ucrt\stdio.h(208): note: 参见“fopen”的声明
错误,尝试以下操作:
项目 > 属性>C/C++ --> 预处理器 --> 预处理器定义 添加:_CRT_SECURE_NO_WARNINGS