我根据老九学堂的小游戏改编了一个原神版笑傲江湖,
代码在后面
主要运用控制台界面,首先可以查看当前所在的地图位置
然后还用六个功能:
1.自我欣赏:可以查看玩家现在的状态,配备的武器,拥有的队伍
2.查找怪物:在不同的地图下可以查找到不同的怪物,输入怪物序号可以攻击它(我没有在所有地图设置怪物,主要在第一行有)
会出现一个根据自己血量和怪物血量动态的战斗过程:
3.祈愿:我写的是我做的时候卡池up的角色,可自行更改
4.纪行:这个没有实现,总不能把收款码放上让你们氪金吧(狗头)
5.背包:查看现在的装备
6.退出游戏:动态显示退出游戏
建议用终端直接运行,因为有的编译器不会弹出控制台比如Clion(悲);
代码:一共两个头文件和三个.c文件
/***************************************************
* 文件名:Game.c
* 描 述:实现Game.h中定义的操作函数 和导入一些基本数据
**************************************************/
#include "Game.h"
#include
#define SEP "----------------------------------------------------------------------------------------------"
#define MARGIN_X 15 //左边距
#define MAP_START_Y 3 //地图开始的Y坐标
#define MAP_END_Y 11 //地图结束的Y坐标
#define INFO_START_Y 12 //信息界面开始的Y坐标
#define INFO_END_Y 19 //信息界面的结束Y坐标
#define MAINMENU_START_Y 20 //主菜单开始的Y坐标
int GameState;
//假设当前用户的坐标是3,2
int X = 3, Y =2;
Player players[] = {
{9527, "纸飞机", "feiji.zhi", 100, 3, 1, 10000, 5000, 900000, 1000000, .coord.X=3, .coord.Y=1},
};
Role roles[] ={
{1, "温迪", "风", .hqCoord.X=1, .hqCoord.Y=4,},
{2, "钟离", "岩", .hqCoord.X=3, .hqCoord.Y=4, },
{3, "雷电将军","雷", .hqCoord.X=2, .hqCoord.Y=6, },
{4, "班尼特", "火", .hqCoord.X=2, .hqCoord.Y=3},
{5, "神里绫华","冰", .hqCoord.X=1, .hqCoord.Y=3},
{6, "夜兰", "水", .hqCoord.X=2, .hqCoord.Y=2},
};
Monster monsterArray[] = {
{1, "丘丘人", 1, 100, 5, 2, 5, 10, 5, 1, {1, 0}},
{2, "骗骗花", 2, 200, 8, 2, 5, 10, 5, 1, {6, 0}},
{3, "雷莹术士", 9, 100, 5, 2, 5, 10, 5, 1, {2, 0}},
{4, "愚人众", 8, 100, 5, 2, 5, 10, 5, 1, {3, 0}},
{5, "北风狼", 7, 100, 5, 2, 5, 10, 5, 1, {7, 0}},
{6, "急冻树", 6, 100, 5, 2, 5, 10, 5, 1, {4, 0}},
{7, "无相之风", 5, 100, 5, 2, 5, 10, 5, 1, {4, 0}},
{8, "风魔龙", 9, 100, 5, 2, 5, 10, 5, 1, {7, 1}}
};
Prop propArray[] = {
{1, "贯虹之槊", 1, 5, 5000, Weapon, .minAttack=1, .maxAttack=4, "或许能贯穿一切的锋利长枪。挥舞当中,仿佛能见到空气被枪划破的裂痕。"},
{2, "和璞鸢", 2, 5, 10000, Weapon, .minAttack=2, .maxAttack=6, "那是璃月初创的年代,海洋还是巨怪与魔神的园地。先民在对海洋的恐惧中度日,以微薄之力与海作战。"},
{3, "若水", 3, 5, 15000, Con, .minPower=1, .maxPower=5, "色泽流移难测的长弓,在光下显现着如水的润蓝。"},
};
Map mapArray[8][8] ={
{
{1, "蒙德城", 1, {0, 0}},
{2, "果酒湖", 1, {1, 0}},
{3, "鹰翔海滩", 1, {2, 0}},
{4, "誓言岬", 1, {3, 0}},
{5, "晨曦酒庄", 1, {4, 0}},
{6, "清泉镇", 1, {5, 0}},
{7, "千风神殿", 1, {6, 0}},
{8, "龙脊雪山", 1, {7, 0}}
},
{
{9, "璃月港", 1, {0, 1}},
{10, "港口", 1, {1, 1}},
{11, "天衡山", 1, {2, 1}},
{12, "荻花洲", 1, {3, 1}},
{13, "望舒客栈", 1, {4, 1}},
{14, "轻策庄", 1, {5, 1}},
{15, "绝云间", 1, {6, 1}},
{16, "层岩巨渊", 1, {7, 1}}
},
{
{17, "矿坑巨口", 1, {0, 2}},
{18, "地下矿区", 1, {1, 2}},
{19, "巨柱岩宫", 1, {2, 2}},
{20, "阻塞的矿道", 1, {3, 2}},
{21, "地下水泽", 1, {4, 2}},
{22, "崎岖石厅", 1, {5, 2}},
{23, "颠倒古城", 1, {6, 2}},
{24, "大蘑菇之地", 1, {7, 2}}
},
{
{25, "离岛", 1, {0, 3}},
{26, "稻妻城", 1, {1, 3}},
{27, "镇守之森", 1, {2, 3}},
{28, "鸣神大社", 1, {3, 3}},
{29, "神无冢", 1, {4, 3}},
{30, "九条阵屋", 1, {5, 3}},
{31, "无想刃狭间", 1, {6, 3}},
{32, "蛇神之首", 1, {7, 3}}
},
{
{33, "名椎滩", 1, {0, 4}},
{34, "海祇岛", 1, {1, 4}},
{35, "清籁岛", 1, {2, 4}},
{36, "鹤观", 1, {3, 3}},
{37, "渊下宫", 1, {4, 4}},
{38, "狭间之街", 1, {5, 4}},
{39, "大日御舆", 1, {6, 4}},
{40, "蛇心之地", 1, {7, 4}}
}
};
Player *currPlayer;
void Init()//初始化游戏数据
{
//设置当前登录玩家默认为玩家1
currPlayer = &players[0];
currPlayer->weapon[0] = propArray[1];
currPlayer->weapon[1] = propArray[2];
currPlayer->role = roles[0];
}
/*将文件中的地图信息导入*/
void TransMapInfo()
{
int i = 0;
FILE* fp=fopen("C:\\Users\\16622\\Desktop\\YuanShen_V0.1\\Details_Map.txt","r");
if(!fp){
return;
}
while(1)
{
//文件读取结束
if(EOF == fscanf(fp,"%s",&mapArray[i / 8][i % 8].name) ||EOF == fscanf(fp,"%s",&mapArray[i / 8][i % 8].desc))
break;
i++;
}
fclose(fp);
}
/*将文件中的角色信息导入*/
void TransRoleInfo()
{
int i = 0;
FILE* fp=fopen("C:\\Users\\16622\\Desktop\\YuanShen_V0.1\\Detail_Roles.txt","r");
if(!fp){
return;
}
while(1)
{
//文件读取结束
if(EOF == fscanf(fp,"%s",&roles->name) ||EOF == fscanf(fp,"%s",&roles->desc))
break;
i++;
}
fclose(fp);
}
/* 显示游戏的欢迎信息 */
void ShowWelcome()
{
SetPosition(MARGIN_X, 0);
printf("%s", SEP);
SetPosition(MARGIN_X, 1);
printf("|");
SetPosition(MARGIN_X + 35, 1);
printf("**!欢迎来到原神!**");
SetPosition(MARGIN_X + 93, 1);
printf("|");
SetPosition(MARGIN_X, 2);
printf("%s", SEP);
}
/* 显示游戏地图 */
void ShowMap()
{
//要根据当前玩家的坐标来显示地图的文字
int i, j;
printf("\n");
for(i = 0; i < 8; i++)
{
SetPosition(MARGIN_X, MAP_START_Y + i);
for(j = 0; j < 8; j++)
{
if(j == 0)
printf("| ");
if(i == Y && j == X)
{
//更改地图文字的颜色和背景色
SetColor(12, 15);
}
printf("%-11s", mapArray[i][j].name);
SetColor(9, 0);//打印完特殊地图后,将颜色变回默认颜色
}
SetPosition(MARGIN_X + 93, 3 + i);
printf("|");
}
SetPosition(MARGIN_X, MAP_END_Y);
printf(SEP);
ShowMapInfo();
}
/* 在信息界面显示当前地图的信息 */
void ShowMapInfo()
{
//1.清除信息窗的信息
Clear(MARGIN_X, INFO_START_Y, 7);
//2.显示当前玩家所在地图的信息
SetPosition(MARGIN_X + 30, INFO_START_Y);
printf("当前玩家所在地图:《%s》", mapArray[Y][X].name);
SetPosition(MARGIN_X + 10, INFO_START_Y + 1);
//需要控制文字显示的行
char * desc = mapArray[Y][X].desc;
int descLen = strlen(desc);
int i;
for(i = 0; i < descLen; i++)
{
if(i != 0 && i % 60 == 0)//控制此行只能打印60个中文字符
{
SetPosition(MARGIN_X + 10, INFO_START_Y + 1 + i / 60);
}
printf("%c", desc[i]);
}
}
/* 显示游戏地图下方的游戏信息 */
void ShowInfomation()
{
//信息窗口一共有7行
SetPosition(MARGIN_X, INFO_START_Y);
int i;
for(i = 0; i < 7; i++)
{
SetPosition(MARGIN_X, INFO_START_Y + i);
printf("|");
SetPosition(MARGIN_X + 93, INFO_START_Y + i);
printf("|");
}
SetPosition(MARGIN_X, INFO_START_Y + 7);
printf(SEP);
}
/* 显示游戏的主菜单 */
void ShowMainMenu()
{
SetPosition(MARGIN_X, MAINMENU_START_Y);
printf("游戏菜单:");
SetPosition(MARGIN_X, MAINMENU_START_Y + 1);
printf("1、自我欣赏");
SetPosition(MARGIN_X, MAINMENU_START_Y + 2);
printf("2、查找怪物");
SetPosition(MARGIN_X, MAINMENU_START_Y + 3);
printf("3、祈愿");
SetPosition(MARGIN_X, MAINMENU_START_Y + 4);
printf("4、纪行");
SetPosition(MARGIN_X, MAINMENU_START_Y + 5);
printf("5、背包");
SetPosition(MARGIN_X, MAINMENU_START_Y + 6);
printf("6、退出游戏");
}
void Showbag()//显示背包
{
Clear(MARGIN_X, INFO_START_Y, 7);
SetPosition(MARGIN_X + 25, INFO_START_Y);
int propCount = sizeof(propArray) / sizeof(Prop);
int i;
for(i = 0; i < propCount; i++)
{
printf("%d.\t%-12s%.0lf\n", propArray[i].id, propArray[i].name, propArray[i].price);
SetPosition(MARGIN_X + 25, INFO_START_Y + 1 + 2 * i);
if(propArray[i].type == Weapon)
{
printf("最小攻击力:%d\t最大攻击力:%d\n", propArray[i].minAttack, propArray[i].maxAttack);
SetPosition(MARGIN_X + 25, INFO_START_Y + 2 + 2 * i);
}
}
}
void ProcessMainMenu(char key)
{
switch(key)
{
case '1'://自我欣赏
ShowPlayerInfo();
break;
case '2'://查找怪物
ShowMonsters();
break;
case '3'://祈愿
ShowWish();
break;
case '4'://纪行
break;
case '5'://背包
Showbag();
break;
case '6'://退出游戏
ShowExit();
GameState = 0;
return;
}
}
void ShowPlayerInfo()
{
//1.清除信息窗的信息
Clear(MARGIN_X, INFO_START_Y, 7);
SetPosition(MARGIN_X + 20, INFO_START_Y);
printf("玩家_%s_的个人资料如下:", currPlayer->name);
SetPosition(MARGIN_X + 10, INFO_START_Y + 1);
printf("等级:%d\t血量:%d\t体力:%d\t经验值:%d", currPlayer->level, currPlayer->hp, currPlayer->mp, currPlayer->exp);
SetPosition(MARGIN_X + 10, INFO_START_Y + 2);
printf("当前武器:%s(%d/%d)\t", currPlayer->weapon[0].name, currPlayer->weapon[0].minAttack, currPlayer->weapon[0].maxAttack);
SetPosition(MARGIN_X + 35, INFO_START_Y + 2);
printf("%s(%d/%d)\t", currPlayer->weapon[1].name, currPlayer->weapon[1].minAttack, currPlayer->weapon[1].maxAttack);
SetPosition(MARGIN_X + 10, INFO_START_Y + 4);
printf("当前队伍角色: %s\t", roles[1].name);
printf("%s\t", roles[3].name);
printf(" %s\t", roles[4].name);
printf(" %s", roles[5].name);
}
void ShowMonsters()
{
//怪物级别的别称。例如:3级怪物,那么就显示这个怪物的描述为粗通皮毛
char *levelNames[] = {"LV1", "LV10", "LV20", "LV30", "LV40", "LV50", "LV60", "LV70", "LV80"};
//清除信息窗的信息
Clear(MARGIN_X, INFO_START_Y, 7);
//怪物总数
int monsterCount = sizeof(monsterArray) / sizeof(Monster);
//当前地图怪物下标数组-当前地图最多显示9个怪物
int monsterIndexs[9];
int currMapMonsterCount = 0; //当前地图的怪物总数
int i;
for(i = 0; i < monsterCount; i++)//查找所有怪物中,坐标是当前地图的怪物
{
if(monsterArray[i].coord.X == X && monsterArray[i].coord.Y == Y && monsterArray[i].state != 0)
{
//记录查找出的怪物下标
monsterIndexs[currMapMonsterCount] = i;
currMapMonsterCount++;
if(currMapMonsterCount == 9)
break;
}
}
//打印怪物
SetPosition(MARGIN_X + 10, INFO_START_Y);
if(currMapMonsterCount == 0)
{
printf("当前地图冷冷清清的!");
return;
}
printf("当前地图出现了如下的怪物:");
SetPosition(MARGIN_X + 5, INFO_START_Y + 2);
for(i = 0; i < currMapMonsterCount; i++)
{
if(i != 0 && i % 3 == 0)
{
SetPosition(MARGIN_X + 5, INFO_START_Y + 2 + i / 3);
}
int currIndex = monsterIndexs[i];
printf("%d.%s(%s)\t", monsterArray[monsterIndexs[i]].id, monsterArray[monsterIndexs[i]].name, levelNames[monsterArray[currIndex].level - 1]);
}
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
//下面就是让玩家选择要pk的怪物编号,调用Fight函数
int pkMonsterId = -1;
printf("请输入要攻击的对象:(按0返回)");
scanf("%d", &pkMonsterId);
//***********************************************
//需要验证用户的输入
//自行验证
//***********************************************
Fight(pkMonsterId);
}
/* 祈愿*/
void ShowWish()
{
//1.清除信息窗的信息
Clear(MARGIN_X, INFO_START_Y, 7);
//2.显示祈愿对象
SetPosition(MARGIN_X + 30, INFO_START_Y);
printf("本版本UP角色:");
SetPosition(MARGIN_X + 30, INFO_START_Y + 1);
printf("夜兰 芭芭拉 \t北斗\t重云");
SetPosition(MARGIN_X + 30, INFO_START_Y + 3);
printf("二卡池UP角色:");
SetPosition(MARGIN_X + 30, INFO_START_Y + 4);
printf("魈 芭芭拉 \t北斗\t重云");
}
void Fight(int monsterId)
{
//要先验证pk的怪物编号是否存在
int monsterIndex = -1; //要查找的怪物下标
int i;
for(i = 0; i < sizeof(monsterArray) / sizeof(Monster); i++)
{
if(monsterArray[i].id == monsterId)
{
monsterIndex = i;
break;
}
}
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf(" ");
if(monsterIndex == -1)//没有找到要pk的怪物
{
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf("要PK的怪物不存在,按任意键继续!");
return;
}
//如果怪物存在
int fightCount = 0; //pk的轮数
while(1)
{
srand(time(NULL));
//玩家和怪物互殴 a - b 5-15 % 11 + 5
//rand() % (b - a + 1) + a
int playerAttack = rand() % (currPlayer->weapon[0].maxAttack - currPlayer->weapon[0].minAttack + 1) + currPlayer->weapon[0].minAttack;
monsterArray[monsterIndex].hp -= playerAttack;
if(monsterArray[monsterIndex].hp <= 0)
{
break;//退出pk过程
}
//暂时忽视玩家的防御力
currPlayer->hp -= monsterArray[monsterIndex].att;
if(currPlayer->hp <= 0)
{
break;
}
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf(" ");
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
fightCount++;
printf("战斗第%d轮,%sHP:%d\t%sHP:%d", fightCount, currPlayer->name, currPlayer->hp, monsterArray[monsterIndex].name, monsterArray[monsterIndex].hp);
usleep(1000 * 200);
}
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf(" ");
if(currPlayer->hp <= 0)
{
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf("玩家《%s》在与《%s》的战斗中壮烈牺牲!按任意键继续");
currPlayer->hp = 100;
return;
}
SetPosition(MARGIN_X + 5, INFO_END_Y - 1);
printf("经过艰苦的战斗,《%s》被您杀死,获得%d经验,%d摩拉!", monsterArray[monsterIndex].name, monsterArray[monsterIndex].exp, monsterArray[monsterIndex].maxMoney);
currPlayer->exp += monsterArray[monsterIndex].exp;
currPlayer->gold += monsterArray[monsterIndex].maxMoney;
}
/*退出游戏*/
void ShowExit()
{
Clear(MARGIN_X, INFO_START_Y, 7);
SetPosition(MARGIN_X + 30, INFO_START_Y + 3);
char *a[]={"游","戏","已","退","出",",","欢","迎","再","来","!"};
for(int i=0;i<11;i++)
{
Sleep(100);
printf("%s",a[i]);
}
sleep(2);
}
#ifndef GAME_H_INCLUDED
#define GAME_H_INCLUDED
/***************************************************
* 文件名:Game.h
* 描 述:用来定义游戏的一些核心结构和函数
**************************************************/
#include
#include
#include
#include
#include
#include "GameLib.h"
/************* 游戏的结构类型定义 *****************/
//玩家、地图、装备、怪物
/* 游戏地图结构 游戏地图
编号、名称、介绍、玩家的进入等级 */
typedef struct _map{
int id; //地图编号
char name[50]; //地图名称
int minLevel; //玩家进入的最低等级
//坐标结构
COORD coord; //地图的坐标
char desc[500]; //地图的介绍
}Map;
/* 游戏道具类型枚举 - 武器、道具、材料、食物、圣遗物 */
typedef enum _proptype{
Weapon, Armor, Con, food, Holy_relic
}PropType;
/* 游戏道具 - 武器、道具、材料、食物、圣遗物 */
typedef struct _prop{
int id; //道具编号
char name[50]; //道具名称
int leve; //道具的级别
int stock; //道具的库存或玩家背包中的叠加数量
double price; //道具的单价
PropType type; //道具的类型
union{
int minAttack; //如果是武器,就对应攻击力
int minPower; //如果是食物等消耗品,就对应增加的能量值
};
union{
int maxAttack; //如果是武器,就对应攻击力
int maxPower; //如果是食物等消耗品,就对应增加的能量值
};
char desc[200]; //道具的功能描述
}Prop;
/* 角色结构 */
typedef struct _role{
int id;
char name[50];
char type[50]; //角色元素类型-雷、岩、水、冰、火、风
COORD hqCoord; //地图的坐标
char desc[1000];//角色描述
}Role;
/*玩家结构*/
typedef struct _player{
int id;
char name[50];
char pass[50];
int life; //玩家生命值
int level; //玩家级别
int exp; //玩家的经验值
int hp; //玩家的血量
int mp; //玩家的体力值
int mpMax; //当前级别玩家的最大体力值
int gold; //玩家的摩拉数量
Role role; //玩家的角色
COORD coord; //玩家当前所在地图的坐标
Prop weapon[2]; //玩家装备的武器
}Player;
typedef struct _monster{
int id;
char name[50];
int level; //怪物的级别
int hp; //怪物的生命值
int att; //怪物的攻击力
int diff; //怪物的防御力
int minMoney; //杀死怪物后掉落的最少金币值
int maxMoney;
int exp; //杀死怪物后玩家获得的经验值
//扩展:杀死怪物后,玩家可以获得的道具列表
int state; //怪物当前的状态,0表示怪物已死,非0表示怪物活着
COORD coord; //怪物的坐标
}Monster;
/******************* 游戏的核心函数的声明 **********************/
void Init();//初始化游戏数据
/* 显示游戏的欢迎信息 */
void ShowWelcome();
/* 显示游戏地图 */
void ShowMap();
/* 在信息界面显示当前地图的信息 */
void ShowMapInfo();
/* 显示游戏地图下方的游戏信息 */
void ShowInfomation();
/* 显示游戏的主菜单 */
void ShowMainMenu();
/* 在信息界面显示玩家的个人资料 */
void ShowPlayerInfo();
/* 在信息界面显示当前地图的怪物 */
void ShowMonsters();
/* 祈愿 */
void ShowWish();
/* 处理游戏主菜单的业务 */
void ProcessMainMenu(char key);
/* pk怪物的方法 */
void Fight(int monsterId);
/*将文件中的地图信息导入*/
void TransMapInfo();
/*将文件中的角色信息导入*/
void TransRoleInfo();
/*退出游戏*/
void ShowExit();
#endif // GAME_H_INCLUDED
/***************************************************
* 文件名:GameLib.c
* 描 述:实现GameLib.h中定义的操作函数
**************************************************/
#include "GameLib.h"
void SetTitle(char * title)
{
SetConsoleTitle(title);
}
void SetColor(int foreColor, int backColor)
{
HANDLE winHandle; //句柄
winHandle = GetStdHandle(STD_OUTPUT_HANDLE);
//设置文字颜色
SetConsoleTextAttribute(winHandle, foreColor + backColor * 0x10);
}
void SetPosition(int x, int y)
{
HANDLE winHandle; //句柄
COORD pos = {x, y};
winHandle = GetStdHandle(STD_OUTPUT_HANDLE);
//设置光标的坐标
SetConsoleCursorPosition(winHandle, pos);
}
/* 从x、y坐标开始,清rowCount行 */
void Clear(int x, int y, int rowCount)
{
//每行清除78个字符-打印78个空格
int i, j;
for(i = 0; i < rowCount; i++)
{
SetPosition(x, y + i);
for(j = 0; j < 78; j++)
{
printf(" ");
}
}
}
#ifndef GAMELIB_H_INCLUDED
#define GAMELIB_H_INCLUDED
/***************************************************
* 文件名:GameLib.h
* 描 述:用来定义游戏中常用的系统操作(更改文字颜色、清屏等)
**************************************************/
#include
#include
/* 设置控制台窗口的标题 */
void SetTitle(char *title);
/* 设置文字的前景色和背景色 */
void SetColor(int foreColor, int backColor);
/* 设置光标的位置 */
void SetPosition(int x, int y);
/* 从x、y坐标开始,清rowCount行 */
void Clear(int x, int y, int rowCount);
#endif // GAMELIB_H_INCLUDED
#include
#include
#include "GameLib.h"
#include "Game.h"
extern int X, Y;
extern int GameState;
int main()
{
char key; //接收到的用户按键
GameState = 1;
SetTitle("MiHoYo_原神");
SetColor(9, 0);
TransMapInfo();
TransRoleInfo();
Init();
ShowWelcome();
ShowMap();
ShowInfomation();
ShowMainMenu();
while(GameState != 0)
{
fflush(stdin);
//等待用户输入某个键
key = (char)getch();
fflush(stdin);
if(key == '1' || key == '2' || key == '3' || key == '4' || key == '5' || key == '6'){
//printf("1-5之间的游戏菜单");
ProcessMainMenu(key);//通过函数去处理用户的菜单选项
continue;
}
else if(key == VK_UP || key == 72)//用户按了上键
{
Y--;
}
else if(key == 39 || key == 77)//右
{
X++;
}
else if(key == 40 || key == 80)//下
{
Y++;
}
else if(key == 37 || key == 75)//左
{
X--;
}
if(X > 7) X = 0;
if(X < 0) X = 7;
if(Y > 4) Y = 0;
if(Y < 0) Y = 4;
ShowMap();//重新显示地图
}
return 0;
}