Unity3D RPG Core | 28 玩家升级系统
本篇介绍玩家角色的升级,都是和代码相关的内容。
相较于视频中的代码,这边重新组织了一下数据信息相关的代码。这块的流程和 《Unity3D RPG Core | 15 人物基本属性》 一样。
1. 角色数据信息
如代码清单 1 所示,我们新增角色人物的 ScriptableObject 类,继承之前实现的 CharacterDataScriptableObject 类。其中增加了当前等级、最高等级、基础经验值、当前经验值以及升级加成这些属性。
- [CreateAssetMenu(fileName = "Character Data", menuName = "ScriptableObject/Player Character Data")]
- public class PlayerDataScriptableObject : CharacterDataScriptableObject
- {
- [Header("Level")]
- public int m_currentLevel;
- public int m_maxLevel;
- public int m_baseExp;
- public int m_currentExp;
- public float m_levelBuff;
- }
代码清单 2 中的 PlayerData 类是对上述 ScriptableObject 的控制封装,继承之前实现的 CharacterData。关注 UpdateExp()、LevelUp() 和 GetLevelMultiplier() 这几个函数。
UpdateExp() 为角色加上获取的经验值。如果当前经验值大于基础经验值,则进行升级操作,对应 LevelUp() 函数。
LevelUp() 修改当前的等级、基础经验值和最大生命值。基础经验值和最大生命值的加成数值见 GetLevelMultiplier() 函数,它逐级递增。
- public class PlayerData : CharacterData
- {
- PlayerDataScriptableObject m_playerData;
- private void Awake()
- {
- if (m_templateCharacterData != null)
- {
- m_characterData = m_templateCharacterData;
- m_playerData = (PlayerDataScriptableObject)m_characterData;
- }
- }
- public void UpdateExp(int point)
- {
- CurrentExp += point;
- while (CurrentExp >= BaseExp)
- LevelUp();
- }
- private void LevelUp()
- {
- CurrentLevel = Math.Min(CurrentLevel + 1, MaxLevel);
- BaseExp += (int)(BaseExp * GetLevelMultiplier());
- MaxHealth = (int)(MaxHealth * GetLevelMultiplier());
- CurrentHealth = MaxHealth;
- Debug.Log("LevelUp! CurrentLevel:" + CurrentLevel + ";MaxHealth:" + MaxHealth);
- }
- private float GetLevelMultiplier()
- {
- return 1 + (CurrentLevel - 1) * LevelBuff;
- }
- public int CurrentLevel
- {
- get { return m_playerData != null ? m_playerData.m_currentLevel : 0; }
- set { if (m_playerData != null) m_playerData.m_currentLevel = value; }
- }
- public int MaxLevel
- {
- get { return m_playerData != null ? m_playerData.m_maxLevel : 0; }
- set { if (m_playerData != null) m_playerData.m_maxLevel = value; }
- }
- public int BaseExp
- {
- get { return m_playerData != null ? m_playerData.m_baseExp : 0; }
- set { if (m_playerData != null) m_playerData.m_baseExp = value; }
- }
- public int CurrentExp
- {
- get { return m_playerData != null ? m_playerData.m_currentExp : 0; }
- set { if (m_playerData != null) m_playerData.m_currentExp = value; }
- }
- public float LevelBuff
- {
- get { return m_playerData != null ? m_playerData.m_levelBuff : 0; }
- set { if (m_playerData != null) m_playerData.m_levelBuff = value; }
- }
- }
2. 敌人数据信息
如代码清单 3 所示,敌人的信息我们新增了一个被击杀获取的经验点数字段。访问相关的逻辑和角色人物的一致,这边不再赘述。
- [CreateAssetMenu(fileName = "Character Data", menuName = "ScriptableObject/Enemy Character Data")]
- public class EnemyDataScriptableObject : CharacterDataScriptableObject
- {
- [Header("Kill")]
- public int m_killPoint;
- }
3. 升级逻辑
我们将升级的逻辑放在敌人数据这边,即之前的 CharacterData,第 2 节中重新组织到敌人数据这边了。见代码清单 4 所示的第 29 至 33 行,如果当前敌人的生命值小于等于 0,我们就把敌人所属的经验值加到攻击它的角色身上。为了防止重复经验值添加的意外发生,特别添加了 hasGivenPoint 变量用来区分。
- public class EnemyData : CharacterData
- {
- EnemyDataScriptableObject m_enemyData;
- bool hasGivenPoint = false;
- void Awake()
- {
- base.Awake();
- m_enemyData = (EnemyDataScriptableObject)m_characterData;
- }
- public int KillPoint
- {
- get { return m_characterData != null ? m_enemyData.m_killPoint : 0; }
- set { if (m_characterData != null) m_enemyData.m_killPoint = value; }
- }
- public void ReceiveAttackDamage(AttackData attackerAttackData, PlayerData attackerData)
- {
- if (attackerAttackData.m_isCriticalHit)
- {
- GetComponent<Animator>().SetTrigger("Hurt");
- }
- int damage = Mathf.Max(CalculateDamage(attackerAttackData) - CurrentDefence, 1);
- CurrentHealth = Mathf.Max(CurrentHealth - damage, 0);
- // 更新UI
- RaiseHealthChanged();
- //TODO:更新经验
- if (CurrentHealth <= 0 && hasGivenPoint == false)
- {
- hasGivenPoint = true;
- attackerData.UpdateExp(KillPoint);
- }
- }
- int CalculateDamage(AttackData attacker)
- {
- float damage = UnityEngine.Random.Range(attacker.MinDamage, attacker.MaxDamage);
- if (attacker.m_isCriticalHit)
- damage *= attacker.CriticalMultiplier;
- return (int)damage;
- }
- }
4. 测试
在测试之前,我们需要重新创建人物角色和敌人的 ScriptableObject。然后移除之前的角色数据脚本,替换成角色或敌人的数据控制脚本。最后在控制脚本上添加新的 ScriptableObject。
我们打三只史莱姆就可以升级了,显示如图 1 所示的日志就代表逻辑跑通了,角色升了一级,最大血量加了 10%。
