unity 战斗系统设计——角色管理

#设计思路

采用角色管理类和角色类组成,每个角色自己维护自己,角色管理器负责存放所以角色方便后面的战斗系统在战斗中添加角色

#示意图

#设计分析

角色接口

作为一个角色首先就要包含属性,属性由属性控制器提供(AttributeController),同时也可以修改属性,这些功能也由属性控制器提供,还要有装备,buff等,这些功能先预留的后面在补充,然后就是战斗相关的方法,如减血(被攻击),加血,扣蓝,加蓝等,至于攻击,和冷却的放到技能里了,我这里将普通攻击也是为一个技能。

除了上面这些战斗主要内容外还有一些补充:角色名,角色id,站位,队伍

using UnityEngine;

/// <summary>
/// 角色接口,定义角色的基本属性和行为
/// </summary>
public interface ICharacter
{
    /// <summary>
    /// 角色唯一标识
    /// </summary>
    int ID { get; }

    /// <summary>
    /// 角色名称
    /// </summary>
    string Name { get; }

    /// <summary>
    /// 角色等级
    /// </summary>
    int Level { get; }

    /// <summary>
    /// 当前生命值
    /// </summary>
    float CurrentHP { get; }

    /// <summary>
    /// 最大生命值
    /// </summary>
    float MaxHP { get; }

    /// <summary>
    /// 当前魔法值
    /// </summary>
    float CurrentMP { get; }

    /// <summary>
    /// 最大魔法值
    /// </summary>
    float MaxMP { get; }

    /// <summary>
    /// 攻击力
    /// </summary>
    float Attack { get; }

    /// <summary>
    /// 防御力
    /// </summary>
    float Defense { get; }

    /// <summary>
    /// 速度
    /// </summary>
    float Speed { get; }

    /// <summary>
    /// 队伍ID,用于区分敌我
    /// </summary>
    int Team { get; }

    /// <summary>
    /// 是否存活
    /// </summary>
    bool IsAlive { get; }

    /// <summary>
    /// 受到伤害
    /// </summary>
    void TakeDamage(float damage);

    /// <summary>
    /// 治疗生命值
    /// </summary>
    void Heal(float amount);

    /// <summary>
    /// 消耗魔法值
    /// </summary>
    /// <returns>是否消耗成功</returns>
    bool ConsumeMana(float amount);

    /// <summary>
    /// 恢复魔法值
    /// </summary>
    void RestoreMana(float amount);

    /// <summary>
    /// 添加固定值加成
    /// </summary>
    void AddEquipmentBonus(AttributeType type, float value);
    /// <summary>
    /// 移除固定值属性加成
    /// </summary>
    void RemoveEquipmentBonus(AttributeType type, float value);
    /// <summary>
    /// 添加百分比加成(Buff或百分比)
    /// </summary>
    /// <param name="type">属性类型</param>
    /// <param name="value">增加值</param>
    /// <param name="isPercentage">百分比/buff增加,默认百分比加成</param>
    void AddAttributeBonus(AttributeType type, float value, bool isPercentage = true);

    /// <summary>
    /// 移除百分比加成(Buff或百分比)
    /// </summary>
    /// <param name="type">属性类型</param>
    /// <param name="value">减少值</param>
    /// <param name="isPercentage">百分比/buff减少,默认百分比加成</param>
    void RemoveAttributeBonus(AttributeType type, float value, bool isPercentage = true);

    ///// <summary>
    ///// 获取装备控制器
    ///// </summary>
    //EquipmentController GetEquipmentController();

    ///// <summary>
    ///// 获取技能控制器
    ///// </summary>
    //SkillController GetSkillController();

    ///// <summary>
    ///// 获取Buff控制器
    ///// </summary>
    //BuffController GetBuffController();

    /// <summary>
    /// 暴击率
    /// </summary>
    float CritRate { get; }

    /// <summary>
    /// 暴击伤害
    /// </summary>
    float CritDamage { get; }

    /// <summary>
    /// 获取属性控制器
    /// </summary>
    AttributeController GetAttributeController();

    /// <summary>
    /// 战斗位置
    /// </summary>
    BattlePosition Position { get; }
} 
using UnityEngine;

/// <summary>
/// 角色基类,实现角色的基本属性和行为
/// </summary>
public class Character : MonoBehaviour, ICharacter
{
    [SerializeField]
    private int id;
    [SerializeField]
    private string characterName;
    [SerializeField]
    private int level = 1;
    [SerializeField]
    private int team;
    [SerializeField]
    private BattlePosition battlePosition;
    [SerializeField]
    private float currentHP;
    [SerializeField]
    private float currentMP;

    public int ID => id;
    public string Name => characterName;
    public int Level => level;
    public float CurrentHP => currentHP;
    public float MaxHP => attributeController.GetAttributeValue(AttributeType.MaxHP);
    public float CurrentMP => currentMP;
    public float MaxMP => attributeController.GetAttributeValue(AttributeType.MaxMP);
    public float Attack => attributeController.GetAttributeValue(AttributeType.Attack);
    public float Defense => attributeController.GetAttributeValue(AttributeType.Defense);
    public float Speed => attributeController.GetAttributeValue(AttributeType.Speed);
    public int Team => team;
    public bool IsAlive => currentHP > 0;
    public float CritRate => attributeController.GetAttributeValue(AttributeType.CritRate);
    public float CritDamage => attributeController.GetAttributeValue(AttributeType.CritDamage);
    public BattlePosition Position => battlePosition;

    #region 控制器
    ///// <summary>
    ///// 技能控制器
    ///// </summary>
    //private SkillController skillController;
    ///// <summary>
    ///// buff控制器
    ///// </summary>
    //private BuffController buffController;
    ///// <summary>
    ///// 装备控制器
    ///// </summary>
    //private EquipmentController equipmentController;
    /// <summary>
    /// 属性控制器,管理所有角色属性的计算和更新
    /// </summary>
    private AttributeController attributeController;
    #endregion

    #region 获取控制器
    //public SkillController GetSkillController()
    //{
    //    return skillController;
    //}
    //public BuffController GetBuffController()
    //{
    //    return buffController;
    //}
    //public EquipmentController GetEquipmentController()
    //{
    //    return equipmentController;
    //}
    public AttributeController GetAttributeController()
    {
        return attributeController;
    }
    #endregion

    /// <summary>
    /// 当角色被创建时初始化
    /// 设置初始属性、等级和各种控制器
    /// </summary>
    public void Awake()
    {
        // 初始化属性控制器(这里后期改成读表数据)
        attributeController = new AttributeController(AttributeInitialData.CreateDefault(1000, 0, 100, 20, 50, 0, 0, 0, 0, 0), 1);

        // 初始化当前生命值和魔法值
        currentHP = attributeController.GetAttributeValue(AttributeType.MaxHP);
        currentMP = attributeController.GetAttributeValue(AttributeType.MaxMP);



        //// 初始化其他控制器
        //skillController = new SkillController(this);
        //buffController = new BuffController(this);
        //equipmentController = new EquipmentController(this)
        // 注册到角色管理器
        CharacterManager.Instance.RegisterCharacter(this);
    }
    
    #region 属性变化
    /// <summary>
    /// 添加固定值加成
    /// </summary>
    public void AddEquipmentBonus(AttributeType type, float value)
    {
        attributeController.AddFixedValueBonus(type, value);
    }

    /// <summary>
    /// 移除固定值属性加成
    /// </summary>
    public void RemoveEquipmentBonus(AttributeType type, float value)
    {
        attributeController.RemoveFixedValueBonus(type, value);
    }

    /// <summary>
    /// 添加百分比加成(Buff或百分比)
    /// </summary>
    /// <param name="type">属性类型</param>
    /// <param name="value">增加值</param>
    /// <param name="isPercentage">百分比/buff增加,默认百分比加成</param>
    public void AddAttributeBonus(AttributeType type, float value, bool isPercentage = true)
    {
        if (isPercentage)
        {
            attributeController.AddPercentageBonus(type, value);
        }
        else
        {
            attributeController.AddBuffBonus(type, value);
        }
    }

    /// <summary>
    /// 移除百分比加成(Buff或百分比)
    /// </summary>
    /// <param name="type">属性类型</param>
    /// <param name="value">减少值</param>
    /// <param name="isPercentage">百分比/buff减少,默认百分比加成</param>
    public void RemoveAttributeBonus(AttributeType type, float value, bool isPercentage = true)
    {
        if (isPercentage)
        {
            attributeController.RemovePercentageBonus(type, value);
        }
        else
        {
            attributeController.RemoveBuffBonus(type, value);
        }
    }
    #endregion

    #region 战斗数据变化
    public virtual void TakeDamage(float damage)
    {
        if (!IsAlive) return;

        float actualDamage = Mathf.Max(0, damage - Defense);
        currentHP = Mathf.Max(0, currentHP - actualDamage);

        if (currentHP <= 0)
        {
            OnDeath();
        }
    }

    public virtual void Heal(float amount)
    {
        if (!IsAlive) return;

        currentHP = Mathf.Min(MaxHP, currentHP + amount);
    }

    public virtual bool ConsumeMana(float amount)
    {
        if (currentMP < amount) return false;

        currentMP -= amount;
        return true;
    }

    public virtual void RestoreMana(float amount)
    {
        currentMP = Mathf.Min(MaxMP, currentMP + amount);
    }
    #endregion



    protected virtual void OnDeath()
    {
        //// 处理死亡逻辑
        //buffController.ClearBuffs();
        //skillController.ClearSkills();
    }

    private void OnDestroy()
    {
        // 从角色管理器注销
        CharacterManager.Instance.UnregisterCharacter(this);

        //// 清理控制器
        //SkillManager.Instance.RemoveController(this);
        //BuffManager.Instance.RemoveController(this);
        //EquipmentManager.Instance.RemoveController(this);
    }
    // 添加一个用于测试的初始化方法
    public void InitializeForTest()
    {
        // 初始化属性控制器
        attributeController = new AttributeController(AttributeInitialData.CreateDefault(1000, 100, 100, 20, 50, 0, 0, 0, 0, 0), 1);

        // 初始化当前生命值和魔法值
        currentHP = attributeController.GetAttributeValue(AttributeType.MaxHP);
        currentMP = attributeController.GetAttributeValue(AttributeType.MaxMP) / 2;
    }
} 

角色管理器

角色管理器要包含所以角色,并且支持添加减少角色以及获得一个角色

using UnityEngine;
using System.Collections.Generic;

/// <summary>
/// 角色管理器,负责管理所有角色
/// 实现为单例模式,统一管理游戏中所有角色的创建
/// </summary>
public class CharacterManager : MonoSingleton<CharacterManager>
{
    /// <summary>
    /// 所有角色字典,键为角色ID,值为角色实例
    /// 用于快速查找和访问特定角色
    /// </summary>
    private Dictionary<int, ICharacter> characters = new Dictionary<int, ICharacter>();

    /// <summary>
    /// 注册角色到管理器
    /// </summary>
    public void RegisterCharacter(ICharacter character)
    {
        if (characters.ContainsKey(character.ID)) return;
        characters[character.ID] = character;
    }

    /// <summary>
    /// 从管理器中注销角色
    /// </summary>
    public void UnregisterCharacter(ICharacter character)
    {
        characters.Remove(character.ID);
    }

    /// <summary>
    /// 根据ID获取角色
    /// </summary>
    public ICharacter GetCharacter(int characterId)
    {
        characters.TryGetValue(characterId, out var character);
        return character;
    }

    /// <summary>
    /// 获取所有角色的只读列表
    /// </summary>
    public IReadOnlyList<ICharacter> GetAllCharacters()
    {
        return new List<ICharacter>(characters.Values).AsReadOnly();
    }

    /// <summary>
    /// 清除所有角色数据
    /// </summary>
    public void ClearAllCharacters()
    {
        characters.Clear();
    }
}

以上功能就是battle1.0了,源文件里附加了单元测试可以验证和测试功能

通过网盘分享的文件:battle1.0.unitypackage
链接: https://pan.baidu.com/s/1hwYAz0XfYvIMduA2zJZUPA?pwd=pn7t 提取码: pn7t 
--来自百度网盘超级会员v3的分享

单元测试

单元测试具体使用百度就有

### Unity3D 战斗系统概述 战斗系统是ARPG游戏中至关重要的组成部分之一,在Unity3D环境中构建这样的系统涉及多个方面,包括但不限于攻击逻辑、伤害计算以及技能释放机制。为了确保游戏内的战斗过程既流畅又充满乐趣,开发者通常会围绕以下几个核心要素展开工作[^2]。 #### 攻击判定与伤害计算 在设计攻击判定时,需考虑如何精确判断一次攻击是否命中目标。这可以通过射线投射(raycasting)技术来完成,即从攻击者的位置向特定方向发射一条虚拟光线,并检测该光线是否与其他对象发生碰撞。一旦确认存在有效的碰撞,则进一步执行伤害评估流程。对于伤害数值的确定,一般基于双方单位的基础属性(例如攻击力和防御力),并通过预设公式得出最终结果: ```csharp public float CalculateDamage(float attackerPower, float defenderDefense) { return Mathf.Max(0f, attackerPower * (1 - defenderDefense / 100)); } ``` 此方法接收两个参数——`attackerPower`(攻击方的力量值) 和 `defenderDefense`(防守方的护甲等级),返回实际造成的伤害量。值得注意的是,这里采用了简单的乘法运算模拟减益效果;而在更复杂的情况下,还可以引入更多变量以增加变化性和真实性。 #### 技能释放机制 除了基本的近战打击外,许多游戏角色还具备特殊能力或魔法咒语等形式各异的主动技能。这些技能往往伴随着独特的视觉特效、音效反馈乃至额外的游戏规则约束。因此,在实现这部分功能之前,建议先规划好每项技能的具体表现形式及其作用范围等细节信息。接着利用协程(coroutine)配合Animator组件共同驱动整个施放过程,如下所示: ```csharp IEnumerator CastSkill(SkillData skillInfo) { // 开始播放准备动作 animator.SetTrigger(skillInfo.PrepareAnim); yield return new WaitForSeconds(skillInfo.CastTime); // 施展具体效果... ApplyEffect(skillInfo.EffectType); // 结束后恢复默认姿态 animator.ResetTrigger(skillInfo.PrepareAnim); } ``` 上述代码片段展示了怎样借助C#中的迭代器模式(`yield`)暂停当前帧更新直至满足指定条件为止,期间允许其他任务继续运行而不受影响。与此同时,通过调用`animator.SetTrigger()`函数触发相应的动画序列,使得角色模型能够按照预期方式做出反应。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值