C++面向对象游戏模型


简单模拟一下“英雄联盟”的模型,先把所有英雄抽象成Hero,他们有很多共同的属性和攻击特性,所以先定义一个抽象类。

由于注释已经写得很清楚了,所以也无需赘述。

#ifndef __HERO__
#define __HERO__

#define TRUE		1
#define FALSE		0


typedef enum ability {
	ABILITY_Q = 0x0000000a, 
	ABILITY_W = 0x0000000b, 
	ABILITY_E = 0x0000000c, 
	ABILITY_R = 0x0000000d } ABILITY; //Q,W,E,R技能枚举

typedef int	HEROPARAM;
typedef int	BOOL;

//英雄抽象类
class Hero
{
protected:
	HEROPARAM _level;						//等级
	HEROPARAM _experience;					//经验值
	BOOL _died;								//是否死亡

	/*消耗系列参数*/
	HEROPARAM _max_health;					//最大生命值
	HEROPARAM _cur_health;					//当前生命值
	HEROPARAM _health_up_speed;				//生命恢复速度(点/每秒)
	HEROPARAM _max_mana;					//最大法力值
	HEROPARAM _cur_mana;					//当前法力值
	HEROPARAM _mana_up_speed;				//法力恢复速度(点/每秒)

	/*攻击系列参数*/
	const HEROPARAM _EFFECTIVE_PER_LEVEL;	//每级增长攻击力(点/每级)
	HEROPARAM _effective;					//当前攻击力
	HEROPARAM _effective_penetration;		//当前攻击穿透
	HEROPARAM _crit;						//暴击几率(0 to 100)
	HEROPARAM _magic;						//当前法术强度
	HEROPARAM _magic_penetration;			//当前法术穿透

	/*防御系列参数*/
	const HEROPARAM _ARMOR_PER_LEVEL;		//每级增长护甲(点/每级)
	HEROPARAM _armor;						//当前护甲
	HEROPARAM _resistance;					//当前魔法抗性

public:
	Hero(HEROPARAM max_health, 
		HEROPARAM health_up_speed, 
		HEROPARAM max_mana, 
		HEROPARAM mana_up_speed, 
		const HEROPARAM effective_per_level, 
		HEROPARAM effective, 
		HEROPARAM effective_penetration,
		HEROPARAM crit,
		HEROPARAM magic, 
		HEROPARAM magic_penetration, 
		const HEROPARAM armor_per_level, 
		HEROPARAM armor, 
		HEROPARAM resistance);	//构造一个英雄
	virtual ~Hero();													//析构英雄
	virtual void attack(Hero *destHero);								//普通攻击目标英雄
	virtual void excute(Hero *destHero, ABILITY what) = 0;				//对目标英雄释放技能(what是指定技能,Q,W,E,R四个技能)
	virtual HEROPARAM getEffective();									//获取攻击力
	virtual HEROPARAM getArmor();										//获取护甲值
	virtual HEROPARAM getEffectivePenetration();						//获取护甲穿透值
	virtual HEROPARAM getCurHealth();									//获取当前生命值
	virtual void putCurHealth(HEROPARAM cur_health);					//设置当前生命值
	virtual void die(Hero *srcHero);									//死亡(被某个英雄击杀)
	virtual const char* getSelfName(char *name) = 0;					//获取英雄自己的名字
	virtual HEROPARAM getMagic();										//获得法术强度
	virtual HEROPARAM getMagicPenetration();							//获得法术穿透
	virtual HEROPARAM getResistance();									//获得魔法抗性
};

#endif

接下来把这个抽象类中的非纯虚函数实现

#include "stdafx.h"
#include "Hero.h"

Hero::Hero(HEROPARAM max_health, 
	HEROPARAM health_up_speed, 
	HEROPARAM max_mana, 
	HEROPARAM mana_up_speed, 
	const HEROPARAM effective_per_level, 
	HEROPARAM effective, 
	HEROPARAM effective_penetration,
	HEROPARAM crit, 
	HEROPARAM magic, 
	HEROPARAM magic_penetration, 
	const HEROPARAM armor_per_level, 
	HEROPARAM armor, 
	HEROPARAM resistance) : 
		_EFFECTIVE_PER_LEVEL(effective_per_level), 
		_ARMOR_PER_LEVEL(armor_per_level)
{
	_level = 1;
	_experience = 0;
	_died = FALSE;
	_max_health = max_health;
	_cur_health = max_health;
	_health_up_speed = health_up_speed;
	_max_mana = max_mana;
	_cur_mana = max_mana;
	_mana_up_speed = mana_up_speed;
	_effective = effective;
	_effective_penetration = effective_penetration;
	_crit = crit;
	_magic = magic;
	_magic_penetration = magic_penetration;
	_armor = armor;
	_resistance = resistance;
}

Hero::~Hero()
{
}

void Hero::attack(Hero *destHero)
{
	HEROPARAM armor = destHero->getArmor() - this->getEffectivePenetration(); //减去护甲穿透之后的护甲
	armor = armor > 0 ? armor : 0; //护甲不能为负数
	HEROPARAM effective = this->getEffective();
	BOOL bIsCrited = FALSE;
	SYSTEMTIME st;
	GetLocalTime(&st);
	srand((unsigned)st.wMilliseconds);
	int num = rand() % (100 - 1) + 1; //产生1到100到随机数
	if (num <= _crit) //决定是否暴击,看看产生的随机数是否小于暴击几率,暴击几率越高,此条件越容易成立
	{
		effective <<= 1; //暴击
		bIsCrited = TRUE;
	}
	HEROPARAM lost_health = (int)((float)effective * (100 / (100 + (float)armor))); //目标损失的生命值,实际对你造成的物理伤害=自己攻击力*[100/(100+对方护甲值)]
	HEROPARAM cur_health = destHero->getCurHealth() - lost_health; //所剩生命值
	char name[255];
	destHero->getSelfName(name); //得到目标英雄名字
	if (bIsCrited)
	{
		printf("你普通攻击了【%s】,并且暴击了!\n", name);
	}
	else
	{
		printf("你普通攻击了【%s】。\n", name);
	}
	if (cur_health <= 0)
	{
		destHero->die(this); //生命值小于或等于0就死亡
		printf("你击杀了【%s】!\n", name);
		_experience += 50; //击杀英雄加50点经验
		//经验值到100就升级
		if (_experience >= 100)
		{
			_experience = 0;
			printf("你升级了!当前等级是%d。\n", _level);
		}
	}
	else
	{
		destHero->putCurHealth(cur_health); //没死就减血
		printf("【%s】丢失%d生命值,剩余生命值%d。\n", name, lost_health, cur_health);
	}
}

HEROPARAM Hero::getEffective()
{
	return _effective;
}

HEROPARAM Hero::getArmor()
{
	return _armor;
}

HEROPARAM Hero::getEffectivePenetration()
{
	return _effective_penetration;
}

HEROPARAM Hero::getCurHealth()
{
	return _cur_health;
}

void Hero::putCurHealth(HEROPARAM cur_health)
{
	_cur_health = cur_health;
}

void Hero::die(Hero *srcHero)
{
	char name[255];
	srcHero->getSelfName(name);
//	printf("你被【%s】击杀了!\n", name);
}

HEROPARAM Hero::getMagic()
{
	return _magic;
}

HEROPARAM Hero::getMagicPenetration()
{
	return _magic_penetration;
}

HEROPARAM Hero::getResistance()
{
	return _resistance;
}


我这样计算暴击几率也不知道合适不合适,因为这样每次暴击是否触发都是独立事件,也就是说,如果运气特别好,可能每次都暴击,当然我相信不会有人运气这么好的!

这样,就定义并实现了Hero这个抽象类,然后要做的就是从这个类中派生出具体的英雄,比如现在派生一个Ashe(艾希)类

头文件:

#ifndef __ASHE__
#define __ASHE__

#include "Hero.h"

//寒冰射手-艾希
class Ashe : public Hero
{
public:
	Ashe(HEROPARAM max_health, 
		HEROPARAM health_up_speed, 
		HEROPARAM max_mana, 
		HEROPARAM mana_up_speed, 
		const HEROPARAM effective_per_level, 
		HEROPARAM effective, 
		HEROPARAM effective_penetration,
		HEROPARAM crit, 
		HEROPARAM magic, 
		HEROPARAM magic_penetration, 
		const HEROPARAM armor_per_level, 
		HEROPARAM armor, 
		HEROPARAM resistance);	//构造一个艾希
	virtual void excute(Hero *destHero, ABILITY what);
	virtual const char* getSelfName(char *name);
};


#endif

源文件:

#include "stdafx.h"
#include "Ashe.h"

Ashe::Ashe(HEROPARAM max_health, 
	HEROPARAM health_up_speed, 
	HEROPARAM max_mana, 
	HEROPARAM mana_up_speed, 
	const HEROPARAM effective_per_level, 
	HEROPARAM effective, 
	HEROPARAM effective_penetration,
	HEROPARAM crit,
	HEROPARAM magic, 
	HEROPARAM magic_penetration, 
	const HEROPARAM armor_per_level, 
	HEROPARAM armor, 
	HEROPARAM resistance) : 
		Hero(max_health, 
			health_up_speed, 
			max_mana, 
			mana_up_speed, 
			effective_per_level, 
			effective, 
			effective_penetration, 
			crit, 
			magic, 
			magic_penetration, 
			armor_per_level, 
			armor, 
			resistance)
{
}

void Ashe::excute(Hero *destHero, ABILITY what)
{
	char name[255];
	destHero->getSelfName(name);

	if (ABILITY_Q == what)
	{
		printf("[寒冰射击]使【%s】减速了。\n", name);
	}
	else if (ABILITY_W == what) //W技能对目标造成40+1全额攻击力的物理伤害
	{
		if (_cur_mana < 60)
		{
			return;
		}
		_cur_mana -= 60; //W技能消耗60点法力值
		HEROPARAM armor = destHero->getArmor() - this->getEffectivePenetration();
		armor = armor > 0 ? armor : 0; //护甲不能为负数
		HEROPARAM lost_health = (int)((40 + (float)this->getEffective()) * (100 / (100 + (float)armor))); //目标损失的生命值,实际对你造成的物理伤害=100/(100+护甲值)
		HEROPARAM cur_health = destHero->getCurHealth() - lost_health; //所剩生命值
		printf("[万箭齐发]使【%s】减速了。\n", name);
		if (cur_health <= 0)
		{
			destHero->die(this); //生命值小于或等于0就死亡
			printf("你击杀了【%s】!\n", name);
			//经验值到100就升级
			if (_experience >= 100)
			{
				_experience = 0;
				printf("你升级了!当前等级是%d。\n", _level);
			}
		}
		else
		{
			destHero->putCurHealth(cur_health); //没死就减血
			printf("【%s】丢失%d生命值,剩余生命值%d。\n", name, lost_health, cur_health);
		}
	}
	else if (ABILITY_E == what)
	{
		printf("[鹰击长空]刚好照亮了【%s】。\n", name);
	}
	else if (ABILITY_R == what) //R技能对目标造成250+1全额法术强度的魔法伤害
	{
		if (_cur_mana < 100)
		{
			return;
		}
		_cur_mana -= 100; //R技能消耗100点法力值
		HEROPARAM resistance = destHero->getResistance() - this->getMagic(); //减去法术穿透后的魔法抗性
		resistance = resistance > 0 ? resistance : 0; //魔法抗性不能为负数
		HEROPARAM lost_health = (int)((250 + (float)this->getMagic()) * (100 / (100 + (float)resistance))); //目标损失的生命值,实际对你造成的魔法伤害=100/(100+魔法抗性)
		HEROPARAM cur_health = destHero->getCurHealth() - lost_health; //所剩生命值
		printf("[魔法水晶剑]命中了【%s】。\n", name);
		if (cur_health <= 0)
		{
			destHero->die(this); //生命值小于或等于0就死亡
			printf("你击杀了【%s】!\n", name);
			if (_experience >= 100)
			{
				_experience = 0;
				printf("你升级了!当前等级是%d。\n", _level);
			}
		}
		else
		{
			destHero->putCurHealth(cur_health); //没死就减血
			printf("【%s】丢失%d生命值,剩余生命值%d。\n", name, lost_health, cur_health);
		}
	}
}


const char* Ashe::getSelfName(char *name)
{
	return strcpy(name, "寒冰射手");
}

Ashe这个类的构造函数就直接调用父类的构造函数来构造了,因为所有的英雄基本属性和攻击特性都是类似的,只是数值不同而已。

最后,构造2个艾希,演示一号艾希攻击二号艾希

// LOLModel.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "Ashe.h"

int main(int argc, char* argv[])
{
	Hero *ashe1 = new Ashe(528, 5, 234, 7, 3, 51, 0, 55, 0, 0, 3, 22, 30); //带暴击几率符文的艾希,假设55%暴击
	Hero *ashe2 = new Ashe(528, 5, 234, 7, 3, 80, 0, 0, 0, 0, 3, 32, 40); //普通符文的艾希
	ashe1->attack(ashe2);
	Sleep(1000);
	ashe1->excute(ashe2, ABILITY_W);
	Sleep(1000);
	ashe1->excute(ashe2, ABILITY_R);
	Sleep(1000);
	ashe1->attack(ashe2);
	Sleep(1000);
	ashe1->attack(ashe2);
	Sleep(1000);
	ashe1->attack(ashe2);
	Sleep(1000);
	ashe1->attack(ashe2);
	Sleep(1000);
	ashe1->excute(ashe2, ABILITY_W);
	delete ashe1;
	delete ashe2;
	return 0;
}

用父类的指针来指向具体英雄的对象,通过多态的方式来调用子类对象的函数。

其实还有很多因素没有考虑到,比如目标已经死亡了还是可以攻击,再比如生命和法力回复就没有考虑。如果实在要考虑的话,可以新开一个1秒触发一次的定时器,每次触发遍历所有对象,给这些对象加上相应的值。没有完善的太多了,反正就这样了。。。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值