简单模拟一下“英雄联盟”的模型,先把所有英雄抽象成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秒触发一次的定时器,每次触发遍历所有对象,给这些对象加上相应的值。没有完善的太多了,反正就这样了。。。