【C++】<应用> 小游戏:怪物英雄

目录

一、游戏需求

二、程序架构

三、代码实现

四、实现效果


一、游戏需求

有一个英雄,和一个怪物:
1. 我们可以在终端初始化英雄的血量、蓝量,和攻击力,以及怪物的血量和攻击力。
2. 英雄有 4 个技能,每个技能都有一定的伤害(或者能够加血),但是需要消耗一定的蓝量(可
以在代码中写死)。(可以考虑冷却时间,比如说,第一个技能 3 个回合才能放一次)。
3. 游戏是回合制游戏,英雄可以放技能以及普通攻击,怪物只能普通攻击。 首先是英雄攻击,然
后是怪物攻击。然后再是英雄攻击,接着是怪物攻击。依次循 环。 英雄可以通过键盘的输入
来选择技能还是普通攻击,但是如果英雄蓝量不够的话,就 没法放技能,因此攻击失败,此回
合不会造成任何伤害。 每个回合结束后英雄会回复一定的蓝量。(随着回合的增加,英雄的蓝
量回复能力增 强)
4. 输出最终获胜的结果。
5. 可以通过输入 q ,结束游戏。 在回合中,可以输入某个命令来查看双方的信息(英雄的血量、
蓝量,攻击力、回复能力以及怪物 的血量,攻击力)

二、程序架构

(1) 文件分析:构建People类、Monster类、Hero类和Menu类。其中Monster类和Hero类继承People类,并实现People类中的“普通攻击”函数。因此,存在"People.h"、 "Monster.h"、 "Hero.h"、 "People.cpp"、 "Monster.cpp"、"Hero.cpp"、 "Menu.h"、 "Menu.cpp"、"main.cpp"九个文件。
(2) 对象分析:
  • People:【属性】血量HP、攻击力attackPower【方法】普通攻击
  • Monster:【新增属性】无【新增方法】受伤
  • Hero:【新增属性】蓝量MP【新增方法】其他技能
  • Menu:【属性】回合数total【方法】显示界面、其他选项的界面

三、代码实现

【1】People.h如下:

#pragma once

/***********************************************************
  * @类名:	People
  * @摘要:	是Monster和Hero的父类
  * @作者:	柯同学
  * @注意:	抽象类,不可实例化
  *********************************************************/
class People
{
protected:
	int HP;				//血量
	int attackPower;	//攻击力
public:
	void setHP(int HP);

	int getHP();

	void setAttackPower(int attackPower);

	int getAttackPower();

	void hurt(int hurtValue);	//受伤:血量减少hurtValue

	virtual void normalAttack(class People &people) = 0;	//虚函数:普通攻击

    virtual ~People() {}		//虚析构函数:防止内存泄露
};

【2】People.cpp如下:

#include "People.h"

/***********************************************************
  * @函数名:setHP
  * @功  能:设置属性HP
  * @参  数:HP---要设置的属性
  * @返回值:无
  *********************************************************/
void People::setHP(int HP) {
	this->HP = HP;
}

/***********************************************************
  * @函数名:getHP
  * @功  能:获取属性HP
  * @参  数:无
  * @返回值:属性HP
  *********************************************************/
int People::getHP() {
	return this->HP;
}

/***********************************************************
  * @函数名:setAttackPower
  * @功  能:设置属性attackPower
  * @参  数:attackPower---要设置的属性
  * @返回值:无
  *********************************************************/
void People::setAttackPower(int attackPower) {
	this->attackPower = attackPower;
}

/***********************************************************
  * @函数名:getAttackPower
  * @功  能:获取属性attackPower
  * @参  数:无
  * @返回值:属性attackPower
  *********************************************************/
int People::getAttackPower() {
	return this->attackPower;
}

/***********************************************************
  * @函数名:hurt
  * @功  能:受伤,减少HP
  * @参  数:hurtValue---伤害值
  * @返回值:无
  *********************************************************/
void People::hurt(int hurtValue) {
	this->HP -= hurtValue;
}

【3】Monster.h如下:

#pragma once
#include <iostream>
#include "People.h"

/***********************************************************
  * @类名:	Monster
  * @摘要:	是People的子类
  * @作者:	柯同学
  * @注意:	实现纯虚函数normalAttack才能实例化
  *********************************************************/
class Monster : public People
{
public:
	Monster();

	Monster(int hp, int attack);

	virtual void normalAttack(class People& people) override; //普通攻击
};

【4】Monster.cpp如下:

#include "Monster.h"

/***********************************************************
  * @函数名:Monster
  * @功  能:无参的构造函数
  * @参  数:无
  * @返回值:无
  *********************************************************/
Monster::Monster() {
	this->HP = 0;
	this->attackPower = 0;
}

/***********************************************************
  * @函数名:Monster
  * @功  能:两个参数的构造函数
  * @参  数:hP---要设置的属性HP
  * @参  数:attack---要设置的属性attackPower
  * @返回值:无
  *********************************************************/
Monster::Monster(int hp, int attack) {
	this->HP = hp;
	this->attackPower = attack;
}

/***********************************************************
  * @函数名:normalAttack
  * @功  能:怪物类的普通攻击
  * @参  数:people---攻击的对象
  * @返回值:无
  *********************************************************/
void Monster::normalAttack(class People& people){
	std::cout << "【怪物】 普通攻击 -----> 英雄损失" << this->attackPower << "血量" << "\n\n" << std::endl;
	people.hurt(this->attackPower);
}

【5】Hero.h如下:

#pragma once
#include <iostream>
#include "People.h"

#define PEACH_MP		15	//桃花灼灼消耗的蓝量
#define PEACH_ADD		10	//桃花灼灼回复的血量
#define HAND_MP			20	//千手浮屠消耗的蓝量
#define HAND_HURT		25	//千手浮屠的伤害
#define THUNDER_MP		40	//万雷天牢引消耗的蓝量
#define THUNDER_HURT	45	//万雷天牢引的伤害
#define HP_MAX			100	//血量上限
#define MP_MAX			50	//蓝量上限

/***********************************************************
  * @类名:	Hero
  * @摘要:	是People的子类
  * @作者:	柯同学
  * @注意:	实现纯虚函数normalAttack才能实例化
  *********************************************************/
class Hero : public People
{
private:
	int MP;			//蓝量
	int MP_Recover = 1;	//回合结束回复的蓝量值 (每回合多回复1点)
public:
	Hero();

	Hero(int hp, int mp, int attack);

	void setMP(int MP);

	int getMP();

	void recoverMP();										 //每回合结束回复蓝量

	virtual void normalAttack(class People& people) override;//普通攻击

	void peachBlossom();									 //桃花灼灼:耗蓝PEACH_MP,补血PEACH_ADD

	void handHurt(class People& people);					 //千手浮屠:耗蓝HAND_MP,伤害HAND_HURT

	void thunderHurt(class People& people);					 //万雷天牢引:耗蓝THUNDER_MP,伤害THUNDER_HURT
};

【6】Hero.cpp如下:

#include "Hero.h"

/***********************************************************
  * @函数名:Hero
  * @功  能:无参的构造函数
  * @参  数:无
  * @返回值:无
  *********************************************************/
Hero::Hero() {
	this->HP = 0;
	this->MP = 0;
	this->attackPower = 0;
}

/***********************************************************
  * @函数名:Hero
  * @功  能:三个参数的构造函数
  * @参  数:hp---设置的属性HP
  * @参  数:mp---设置的属性MP
  * @参  数:attack---设置的属性attackPower
  * @返回值:无
  *********************************************************/
Hero::Hero(int hp, int mp, int attack) {
	this->HP = hp;
	this->MP = mp;
	this->attackPower = attack;
}

/***********************************************************
  * @函数名:setMP
  * @功  能:设置属性MP
  * @参  数:MP---设置的属性值
  * @返回值:无
  *********************************************************/
void Hero::setMP(int MP) {
	this->MP = MP;
}

/***********************************************************
  * @函数名:getMP
  * @功  能:获取属性MP
  * @参  数:无
  * @返回值:获取的属性
  *********************************************************/
int Hero::getMP() {
	return this->MP;
}

/***********************************************************
  * @函数名:recoverMP
  * @功  能:回合结束英雄回复蓝量MP
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Hero::recoverMP() {
	//回蓝不超过蓝量上限
	this->MP += (this->MP_Recover)++;//随着回合数增加,回蓝能力提升1点
	if (this->MP > MP_MAX) {
		this->MP = MP_MAX;
	}
}

/***********************************************************
  * @函数名:normalAttack
  * @功  能:英雄普通攻击
  * @参  数:people---攻击的对象
  * @返回值:无
  *********************************************************/
void Hero::normalAttack(class People& people) {
	std::cout << "【英雄】 普通攻击 -----> 怪物损失" << this->attackPower << "血量" << std::endl;
	people.hurt(this->attackPower);
}

/***********************************************************
  * @函数名:peachBlossom
  * @功  能:英雄技能:桃花灼灼
  *			 回复血量PEACH_ADD,消耗蓝量PEACH_MP
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Hero::peachBlossom() {
	//蓝量不足
	if (this->MP < PEACH_MP) {
		std::cout << "【英雄】 MP不足,桃花灼灼失败" << std::endl;
		return;
	}
	//蓝量减少,不低于0
	this->MP -= PEACH_MP;
	if (this->MP < 0) {
		this->MP = 0;
	}
	//回血不超过血量上限
	int HP_Pre = this->HP;
	this->HP += PEACH_ADD;
	if (this->HP > HP_MAX) {
		this->HP = HP_MAX;
	}
	std::cout << "【英雄】 桃花灼灼 -----> 英雄回复" << this->HP - HP_Pre << "血量" << std::endl;
}

/***********************************************************
  * @函数名:handHurt
  * @功  能:英雄技能:千手浮屠
  *			 伤害HAND_HURT,消耗蓝量HAND_MP
  * @参  数:people---攻击的对象
  * @返回值:无
  *********************************************************/
void Hero::handHurt(class People& people) {
	//蓝量不足
	if (this->MP < HAND_MP) {
		std::cout << "【英雄】 MP不足,千手浮屠失败" << std::endl;
		return;
	}
	//蓝量减少,不低于0
	this->MP -= HAND_MP;
	if (this->MP < 0) {
		this->MP = 0;
	}
	//怪物受伤
	people.hurt(HAND_HURT);
	std::cout << "【英雄】 千手浮屠 -----> 怪物损失" << HAND_HURT << "血量" << std::endl;
}

/***********************************************************
  * @函数名:thunderHurt
  * @功  能:英雄技能:万雷天牢引
  *			 伤害THUNDER_HURT,消耗蓝量THUNDER_MP
  * @参  数:people---攻击的对象
  * @返回值:无
  *********************************************************/
void Hero::thunderHurt(class People& people) {
	//蓝量不足
	if (this->MP < THUNDER_MP) {
		std::cout << "【英雄】 MP不足,万雷天牢引失败" << std::endl;
		return;
	}
	//蓝量减少,不低于0
	this->MP -= THUNDER_MP;
	if (this->MP < 0) {
		this->MP = 0;
	}
	//怪物受伤
	people.hurt(THUNDER_HURT);
	std::cout << "【英雄】 万雷天牢引 -----> 怪物损失" << THUNDER_HURT << "血量" << std::endl;
}

【7】Menu.h如下:

#pragma once
#include <iostream>
#include "Hero.h"
#include "Monster.h"

/***********************************************************
  * @类名:	Menu
  * @摘要:	封装了菜单等功能
  * @作者:	柯同学
  * @注意:	无
  *********************************************************/
class Menu
{
private:
	int total;						//游戏的回合数
	void returnMenu();				//返回主菜单

public:
	Menu() : total(1){}

	void showMenu();				//显示主菜单

	void introduceGame();			//游戏简介

	void viewProperty(class Hero& hero, class Monster& monster);//查看属性

	void setMonster(class Monster& monster);					//设置怪物

	void setHero(class Hero& hero);	//设置英雄

	void startGame(class Hero& hero, class Monster& monster);	//开始游戏
};

【8】Menu.cpp如下:

#include "Menu.h"

using namespace std;

/***********************************************************
  * @函数名:showMenu
  * @功  能:显示游戏主界面
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::showMenu() {
	cout << "*****************************************" << endl;
	cout << "**************游戏: 怪物英雄*************" << endl;
	cout << "******** 1.游戏简介   2.查看属性 ********" << endl;
	cout << "******** 3.设置怪物   4.设置英雄 ********" << endl;
	cout << "******** 5.开始作战   6.退出游戏 ********" << endl;
	cout << "*****************************************" << endl;
	cout << "请输入选项:";
}

/***********************************************************
  * @函数名:returnMenu
  * @功  能:返回游戏主界面的按键判断
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::returnMenu() {
	cout << "请按0键返回主菜单!";
	int tmp = -1;
	while (1) {
		cin >> tmp;
		if (tmp != 0)
			cout << "按键无效!请重新输入:";
		else
			break;
	}
}

/***********************************************************
  * @函数名:introduceGame
  * @功  能:游戏简介
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::introduceGame() {
	cout << "************************游戏简介************************" << endl;
	cout << "【概述】你将扮演一名英雄,去使用你的技能战胜怪物!" << endl;
	cout << "【英雄】有血量、蓝量和攻击力三种属性。" << endl;
	cout << "        当血量低于0时,英雄死亡。" << endl;
	cout << "        每回合结束时,蓝量会自动回复一定数值。" << endl;
	cout << "        回复的蓝量会随着回合数增加而增加。" << endl;
	cout << "【怪物】有血量和攻击力两种属性。" << endl;
	cout << "        怪物只会进行普通攻击。" << endl;
	cout << "********************************************************" << endl;
	this->returnMenu();
}

/***********************************************************
  * @函数名:viewProperty
  * @功  能:查看怪物和英雄属性
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::viewProperty(class Hero& hero, class Monster& monster){
	cout << "****************查看属性*****************" << endl;
	cout << "【英雄】血量: " << hero.getHP() << ", 蓝量: " << hero.getMP() << ", 攻击力: " << hero.getAttackPower() << endl;
	cout << "【怪物】血量: " << monster.getHP() << ", 攻击力: " << monster.getAttackPower() << endl;
	cout << "*****************************************" << endl;
	this->returnMenu();
}

/***********************************************************
  * @函数名:setHero
  * @功  能:设置英雄的属性
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::setHero(class Hero& hero) {
	cout << "****************设置英雄*******************" << endl;
	cout << "* 提示: 英雄HP最大值为 " << HP_MAX << ", MP最大值为 " << MP_MAX << " *" << endl;
	cout << "*******************************************" << endl;
	int HP_tmp, MP_tmp, attack_tmp;
	cout << "请输入英雄的血量(HP): ";
	cin >> HP_tmp;
	hero.setHP(HP_tmp);
	cout << "请输入英雄的蓝量(MP): ";
	cin >> MP_tmp;
	hero.setMP(MP_tmp);
	cout << "请输入英雄的攻击力: ";
	cin >> attack_tmp;
	hero.setAttackPower(attack_tmp);
	cout << "设置英雄成功!" << endl;
	cout << "【英雄】血量: " << hero.getHP() << ", 蓝量: " << hero.getMP() << ", 攻击力: " << hero.getAttackPower() << endl;
	cout << "*******************************************" << endl;
	this->returnMenu();
}

/***********************************************************
  * @函数名:setMonster
  * @功  能:设置怪物的属性
  * @参  数:无
  * @返回值:无
  *********************************************************/
void Menu::setMonster(class Monster& monster) {
	cout << "****************设置怪物*******************" << endl;
	int HP_tmp, attack_tmp;
	cout << "请输入怪物的血量(HP): ";
	cin >> HP_tmp;
	monster.setHP(HP_tmp);
	cout << "请输入怪物的攻击力: ";
	cin >> attack_tmp;
	monster.setAttackPower(attack_tmp);
	cout << "设置怪物成功!" << endl;
	cout << "【怪物】血量: " << monster.getHP() << ", 攻击力: " << monster.getAttackPower() << endl;
	cout << "*******************************************" << endl;
	this->returnMenu();
}

/***********************************************************
  * @函数名:startGame
  * @功  能:开始回合制游戏,英雄先攻(可选3个技能+1个普通攻击)
  * @参  数:hero---创建的英雄对象
  * @参  数:monster---创建的怪物对象
  * @返回值:无
  *********************************************************/
void Menu::startGame(class Hero& hero, class Monster& monster) {
	while (1) {
		//玩家回合信息提示
		cout << "****************玩家回合" << (this->total)++ << "*****************" << endl;
		cout << "------【n】查看属性【q】结束游戏   ------" << endl;
		cout << "------【1】普通攻击【2】桃花灼灼   ------" << endl;
		cout << "------【3】千手浮屠【4】万雷天牢引 ------" << endl;
		cout << "****************************************" << endl;
		cout << "请输入您的选择: ";
		char gameKey;
		cin >> gameKey;
		//不同选项
		switch (gameKey) {
		case 'n':
			cout << "【英雄】血量: " << hero.getHP() << ", 蓝量: " << hero.getMP() << ", 攻击力: " << hero.getAttackPower() << endl;
			cout << "【怪物】血量: " << monster.getHP() << ", 攻击力: " << monster.getAttackPower() << "\n\n" << endl;
			break;
		case 'q':
			this->returnMenu();
			return;
		case '1':
			hero.normalAttack(monster);
			monster.normalAttack(hero);
			hero.recoverMP();
			break;
		case '2':
			hero.peachBlossom();
			monster.normalAttack(hero);
			hero.recoverMP();
			break;
		case '3':
			hero.handHurt(monster);
			monster.normalAttack(hero);
			hero.recoverMP();
			break;
		case '4':
			hero.thunderHurt(monster);
			monster.normalAttack(hero);
			hero.recoverMP();
			break;
		}
		//判定死亡
		if (monster.getHP() <= 0 && hero.getHP() > 0) {
			cout << "怪物死亡,游戏胜利!" << endl;
			break;
		}
		if (monster.getHP() > 0 && hero.getHP() <= 0) {
			cout << "英雄死亡,游戏失败!" << endl;
			break;
		}
		if (monster.getHP() <= 0 && hero.getHP() <= 0) {
			cout << "游戏平局,再接再厉!" << endl;
			break;
		}
	}
	this->returnMenu();
}

【9】main.cpp如下:

#include <iostream>
#include <stdlib.h>
#include "People.h"
#include "Monster.h"
#include "Hero.h"
#include "Menu.h"

int main()
{
	//创建相关对象
	class Menu menu;
	class Hero hero(100, 50, 15);
	class Monster monster(110, 5);

	//主循环
	while (1) {
		int keyNumber = -1;

		// 显示菜单
		system("cls");
		menu.showMenu();
		std::cin >> keyNumber;

		// 不同模式
		switch (keyNumber) {
		case 1://游戏简介
			system("cls");
			menu.introduceGame();
			break;
		case 2://查看属性
			system("cls");
			menu.viewProperty(hero, monster);
			break;
		case 3://设置怪物
			system("cls");
			menu.setMonster(monster);
			break;
		case 4://设置英雄
			system("cls");
			menu.setHero(hero);
			break;
		case 5://开始作战
			system("cls");
			menu.startGame(hero, monster);
			break;
		case 6://退出游戏
			return 0;
		default:
			std::cout << "按键值输入有误,请重新输入!" << std::endl;
		}
	}
	return 0;
}

四、实现效果

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
以下是一个简单的基于控制台的五子棋C语言小游戏示例: ```c #include <stdio.h> #include <stdlib.h> #define ROWS 15 #define COLS 15 // 棋盘 char board[ROWS][COLS]; // 初始化棋盘 void init_board() { for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { board[i][j] = '+'; } } } // 显示棋盘 void print_board() { printf(" "); for (int i = 0; i < COLS; i++) { printf("%c ", 'A' + i); } printf("\n"); for (int i = 0; i < ROWS; i++) { printf("%2d", i + 1); for (int j = 0; j < COLS; j++) { printf("%c ", board[i][j]); } printf("\n"); } } // 判断是否胜利 int is_win(char c) { // 判断行 for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS - 4; j++) { if (board[i][j] == c && board[i][j+1] == c && board[i][j+2] == c && board[i][j+3] == c && board[i][j+4] == c) { return 1; } } } // 判断列 for (int i = 0; i < ROWS - 4; i++) { for (int j = 0; j < COLS; j++) { if (board[i][j] == c && board[i+1][j] == c && board[i+2][j] == c && board[i+3][j] == c && board[i+4][j] == c) { return 1; } } } // 判断主对角线 for (int i = 0; i < ROWS - 4; i++) { for (int j = 0; j < COLS - 4; j++) { if (board[i][j] == c && board[i+1][j+1] == c && board[i+2][j+2] == c && board[i+3][j+3] == c && board[i+4][j+4] == c) { return 1; } } } // 判断副对角线 for (int i = 0; i < ROWS - 4; i++) { for (int j = 4; j < COLS; j++) { if (board[i][j] == c && board[i+1][j-1] == c && board[i+2][j-2] == c && board[i+3][j-3] == c && board[i+4][j-4] == c) { return 1; } } } return 0; } int main() { int x, y; char player = 'O'; init_board(); print_board(); while (1) { printf("Player %c's turn.\n", player); printf("Enter the row and column (e.g., 1A): "); scanf("%d%c", &x, &y); x--; // 行号从0开始 y -= 'A'; // 列号从0开始 if (x < 0 || x >= ROWS || y < 0 || y >= COLS || board[x][y] != '+') { printf("Invalid input. Please try again.\n"); continue; } board[x][y] = player; print_board(); if (is_win(player)) { printf("Player %c wins!\n", player); break; } if (player == 'O') { player = 'X'; } else { player = 'O'; } } return 0; } ``` 在上面的代码中,我们首先定义了棋盘的大小(15x15),并使用`init_board`函数初始化棋盘为初始状态(所有位置都是'+')。然后,我们使用`print_board`函数打印当前的棋盘状态。 在每个玩家的回合中,我们使用`scanf`函数输入玩家的行和列。需要注意的是,行号从1开始,但是我们的数组是从0开始编号的,因此需要将输入的行号减去1。列号是一个字母,但是我们的数组是用数字表示的,因此需要将输入的列号减去'A'。如果输入的行或列不在合法的范围内,或已经有棋子了,我们会提示玩家重新输入。 在每个玩家下完棋子后,我们使用`is_win`函数检查是否有五个棋子连成一线。如果是,我们输出胜利者并退出游戏。如果没有胜者,则交换玩家,并继续下一回合。 需要注意的是,此代码示例是基于控制台的,因此无法实现图形化的界面。同时,由于没有实现人机对战和网络对战等功能,只能用于双人对战。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值