游戏技能系统开发探索2

本文探讨了如何将主角的技能容器转化为可复用的通用技能容器,以减少代码重复。作者通过创建技能列表基类SkillListBase并采用单例模式,实现了代码复用。接着,讨论了技能使用时与游戏对象交互的问题,提出了通过参数传递来确定作用对象,同时处理了不同游戏对象使用技能时的耦合问题。文章最后提到了技能寻找目标对象的策略,包括范围伤害、轨迹型和追踪型技能,并给出了处理不同类型的初步方案。
摘要由CSDN通过智能技术生成

昨天简单的设计了一个可供主角方便使用的技能容器,今天进一步研究这个容器如何设计才可以变成公用型容器。
先把昨天的容器代码拿来看一下

class HeroSkillList
{
public:
    //获取单例实例方法
    static HeroSkillList& Instance(){}
    std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
    std::map<std::string,std::shared_ptr<SkillBase>> skillList;
    HeroSkillList(){}
    //省略拷贝构造函数,重载赋值运算符等
}

现在我把它变成一个供敌人使用的容器,看看能否顺利使用

class EnemySkillList
{
public:
    //获取单例实例方法
    static EnemySkillList& Instance(){}
    std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
    std::map<std::string,std::shared_ptr<SkillBase>> skillList;
    EnemySkillList()
    {
        //将敌人能使用的技能加入列表
    }
    //省略拷贝构造函数,重载赋值运算符等
}

直接这样敌人能不能直接使用?大概是可以的,敌人的代码可以向这样

class Enemy:public GameObject
{
public:
    void UseSkill()
    {
        EnemySkillList::Instance().FindSkill(/*技能名*/)->Use();
    }
}

完全照搬主角类的模式来做就可以很方便的使用技能。但是这种做法我认为并不是非常好的做法。因为一个游戏中并不止有一种敌人,可能很多的敌人都会使用技能,假设有10种敌人,Enemy1,Enemy2….Enemy10;那么对应的EnemySkillList列表可能就有10种。那么EnemySkillList的很多代码都会被重复编写10遍,这不是我们所希望的。这个List里,至少

    static EnemySkillList& Instance(){}
    std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
    std::map<std::string,std::shared_ptr<SkillBase>> skillList;

这些代码都是被重复编写的,可能还有其他方法也是要被重复写好多遍的,我希望能够有效的重用这些代码,我采取的方法是把这些代码放进一个类中,即SkillListBase,代码如下

template <typename T>
class SkillListBase
{
public:
    static T& Instance()
    {
        static T instance;
        return instance;
    }
    std::shared_ptr<SkillBase> FindSkill(std::string){}
protected:
    SkillListBase(){}
    ~SkillListBase(){}
    std::map<std::string,std::shared_ptr<SkillBase>> skillList;
}

这里我直接把技能列表基类做成了单例基类,至于具体为什么单例基类这么设计,网上一搜一大把,这里不多解释。这样可以使代码复用效率大大提升。在一个特定的技能列表中应该这么做,以主角类举例

class HeroSkillList : public SkillListBase<HeroSkillList>
{
private:
    friend SkillListBase<HeroSkillList>;
    HeroSkillList()
    {
        //添加技能的代码,可能有100行
    }
}

这时这个主角技能列表编写时需要注意三点,第一是继承基类时的写法

class HeroSkillList : public SkillListBase<HeroSkillList>

因为基类时使用泛型的,所以这里需要给出确定的类型,否则编译器会罢工。
第二点是在子类中指定友元

    friend SkillListBase<HeroSkillList>;

如果这里不再子类中将基类指定为友元,在基类的Instance方法中,编译器会认为HeroSkillList这个类的构造函数是不可访问的,会拒绝执行代码。
第三点是子类的构造函数,拷贝构造函数,赋值运算符等应声明为私有成员。这样做可以确保外界无法声明一个子类实例,也无法通过继承来创建一个实例。
做出这样的修改后,主角想要使用一个技能应该怎么做?代码大概像这样

class Hero:public GameObject
{
public:
    void UseSkill()
    {
        HeroSkillList::Instance().FindSkill(/*技能名*/)->Use();
    }
}

和之前没有变化。那么敌人类呢?

class Enemy:public GameObject
{
public:
    void UseSkill()
    {
        EnemySkillList::Instance().FindSkill(/*技能名*/)->Use();
    }
}

敌人类也没有变化。变化的部分在于下面代码

class HeroSkillList : public SkillListBase<HeroSkillList>
{
private:
    friend SkillListBase<HeroSkillList>;
    HeroSkillList()
    {
        //添加技能的代码,可能有100行
    }
}
class EnemySkillList : public SkillListBase<EnemySkillList>
{
private:
    friend SkillListBase<EnemySkillList>;
    EnemySkillList()
    {
        //添加技能的代码,可能有100行
    }
}

修改之前的代码长这样

class HeroSkillList
{
public:
    //获取单例实例方法
    static HeroSkillList& Instance(){}
    std::shared_ptr<SkillBase> FindSkill(std::string){}
private:
    std::
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值