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