这套教程分为四章,第一部分主要讲诉Unity的基础以及简单RPG开发逻辑,都是比较基础的内容,其实教程整体来看很多地方做的比较粗糙.不过作为入门教程也不能要求太高,总体上很适合刚上手unity新人入门,我后面懒得每P都记录,所以就直接附上第一部分完结的源代码。有需要自己对着参考吧,为了方便有学习的新人理解,用AI写了注释
Mover
- using RPG.Attributes;
- using RPG.Core;
- using RPG.Saving;
- using UnityEngine;
- using UnityEngine.AI;
-
- namespace RPG.Movement
- {
- //移动
- //关于角色的移动逻辑,角色的移动主要使用Unity自带的寻路组件 NavMeshAgent
- public class Mover : MonoBehaviour, IAction, ISaveable
- {
- [SerializeField]
- Transform target;
-
- [SerializeField]
- float maxSpeed = 6f;// 最大移动速度
-
- NavMeshAgent navMeshAgent;// 导航网格代理,用于处理移动
-
- Health health;// 角色的生命值组件
-
- private void Awake()
- {
- health = GetComponent<Health>();
- navMeshAgent = GetComponent<NavMeshAgent>();
- }
-
- void Update()
- {
- navMeshAgent.enabled = !health.IsDead();// 如果角色死亡,则禁用导航代理
- UpdateAnimator();// 更新动画状态
- }
-
- //开始移动行为
- public void StartMoveAction(Vector3 destination, float speedFraction)
- {
- GetComponent<ActionScheduler>().StartAction(this);// 启动移动动作
- MoveTo (destination, speedFraction);// 开始移动到目标位置
- }
-
- //移动状态
- public void MoveTo(Vector3 destination, float speedFraction)
- {
- navMeshAgent.destination = destination;// 设置导航代理的目标位置
- navMeshAgent.speed = maxSpeed * Mathf.Clamp01(speedFraction);// 根据速度比例设置移动速度
- navMeshAgent.isStopped = false;// 开始移动
- }
-
- /// <summary>
- /// 取消移动
- /// </summary>
- public void Cancel()
- {
- navMeshAgent.isStopped = true;// 停止移动
- }
-
- //更新动画
- private void UpdateAnimator()
- {
- Vector3 velocity = navMeshAgent.velocity;// 获取导航代理的速度
-
-
- Vector3 localVelocity =
- transform.InverseTransformDirection(velocity);// 将全局速度转换为本地坐标系
-
- float speed = localVelocity.z;
- GetComponent<Animator>().SetFloat("forwardSpeed", speed);// 更新动画控制器中的前进速度
- }
-
-
- //捕获状态 返回当前坐标
- public object CaptureState()
- {
- return new SerializableVector3(transform.position);
- }
-
- //恢复状态
- public void RestoreState(object state)
- {
- SerializableVector3 position = (SerializableVector3) state;// 将状态转换为可序列化的向量
-
- // 为避免与导航代理冲突,先禁用导航代理
- GetComponent<NavMeshAgent>().enabled = false;
-
- transform.position = position.ToVector();
-
- // 在设置位置后重新启用导航代理
- GetComponent<NavMeshAgent>().enabled = true;
- }
- }
- }
复制代码
PlayerController
- using System; // 引入系统命名空间
- using RPG.Attributes; // 引入角色属性相关的命名空间
- using RPG.Combat; // 引入战斗相关的命名空间
- using RPG.Movement; // 引入移动相关的命名空间
- using UnityEngine; // 引入Unity引擎相关的命名空间
- using UnityEngine.AI; // 引入Unity的导航系统相关的命名空间
- using UnityEngine.EventSystems; // 引入UI事件系统相关的命名空间
-
- namespace RPG.Control // 定义RPG控制相关的命名空间
- {
- public class PlayerController : MonoBehaviour // 玩家控制器类
- {
- Health health; // 角色的生命值组件
-
- // 用于在Unity编辑器中显示的光标映射结构体
- [Serializable]
- struct CursorMapping
- {
- public CursorType type; // 光标类型
- public Texture2D texture; // 光标的纹理
- public Vector2 hotspot; // 光标的热点
- }
-
- [SerializeField]
- CursorMapping[] cursorMappings = null; // 光标映射数组,配置不同光标类型
-
- [SerializeField]
- float maxNavMeshProjectionDistance = 1f; // 最大导航网格投影距离
-
- [SerializeField]
- float maxNavPathLength = 40f; // 最大导航路径长度
-
- private void Awake()
- {
- health = GetComponent<Health>(); // 初始化健康组件
- }
-
- void Update()
- {
- // 检测是否与UI交互,如果是则返回
- if (InteractWithUI()) return;
-
- // 如果角色死亡,设置光标为无效状态并返回
- if (health.IsDead())
- {
- SetCursor(CursorType.None);
- return;
- }
-
- // 检测与组件交互,如果有交互则返回
- if (InteractWithComponent()) return;
-
- // 检测移动交互,如果有交互则返回
- if (InteractWithMovement()) return;
-
- // 如果没有交互,设置光标为无效状态
- SetCursor(CursorType.None);
- }
-
- private bool InteractWithComponent()
- {
- RaycastHit[] hits = RaycastAllSorted(); // 获取排序后的射线检测结果
- foreach (RaycastHit hit in hits)
- {
- // 获取当前对象的所有可射线检测组件
- IRaycastable[] raycastables =
- hit.transform.GetComponents<IRaycastable>();
-
- foreach (IRaycastable raycastable in raycastables)
- {
- // 如果组件处理了射线检测
- if (raycastable.HandleRaycast(this))
- {
- SetCursor(raycastable.GetCursorType()); // 设置光标为对应类型
- return true; // 返回交互成功
- }
- }
- }
-
- return false; // 没有交互,返回false
- }
-
- RaycastHit[] RaycastAllSorted()
- {
- // 进行射线检测,获取所有碰撞体
- RaycastHit[] hits = Physics.RaycastAll(GetMouseRay());
- float[] distances = new float[hits.Length]; // 存储每个碰撞体与射线起点的距离
-
- for (int i = 0; i < hits.Length; i++)
- {
- distances[i] = hits[i].distance; // 记录距离
- }
-
- Array.Sort(distances, hits); // 根据距离排序碰撞体
- return hits; // 返回排序后的碰撞体数组
- }
-
- private bool InteractWithUI()
- {
- // 检测鼠标是否悬停在UI元素上
- if (EventSystem.current.IsPointerOverGameObject())
- {
- SetCursor(CursorType.UI); // 设置光标为UI类型
- return true; // 返回交互成功
- }
- return false; // 没有UI交互,返回false
- }
-
- private void SetCursor(CursorType type)
- {
- // 根据类型获取光标映射并设置光标
- CursorMapping mapping = GetCursorMapping(type);
- Cursor.SetCursor(mapping.texture, mapping.hotspot, CursorMode.Auto);
- }
-
- private CursorMapping GetCursorMapping(CursorType type)
- {
- // 根据光标类型获取对应的映射
- foreach (CursorMapping mapping in cursorMappings)
- {
- if (mapping.type == type)
- {
- return mapping; // 找到对应类型,返回映射
- }
- }
-
- return cursorMappings[0]; // 如果没有找到,返回默认映射
- }
-
- private bool InteractWithMovement()
- {
- Vector3 target; // 定义目标位置
- bool hasHit = RaycastNavMesh(out target); // 射线检测导航网格
-
- if (hasHit)
- {
- if (Input.GetMouseButton(0)) // 如果鼠标左键按下
- {
- GetComponent<Mover>().StartMoveAction(target, 1f); // 开始移动到目标位置
- }
- SetCursor(CursorType.Movement); // 设置光标为移动类型
- return true; // 返回交互成功
- }
- return false; // 没有移动交互,返回false
- }
-
- // out关键字表示该方法有两个返回规则
- // 1. 返回bool值
- // 2. 更新目标位置
- private bool RaycastNavMesh(out Vector3 target)
- {
- target = new Vector3(); // 初始化目标位置
-
- // 射线检测地形
- RaycastHit hit;
- bool hasHit = Physics.Raycast(GetMouseRay(), out hit);
- if (!hasHit) return false; // 没有检测到,返回false
-
- // 找到最近的导航网格点
- NavMeshHit navMeshHit;
- bool hasCastToNavMesh =
- NavMesh
- .SamplePosition(hit.point,
- out navMeshHit,
- maxNavMeshProjectionDistance,
- NavMesh.AllAreas);
-
- if (!hasCastToNavMesh) return false; // 如果没有有效的导航点,返回false
-
- target = navMeshHit.position; // 更新目标位置
-
- NavMeshPath path = new NavMeshPath();
- // 计算从当前位置到目标位置的导航路径
- bool hasPath =
- NavMesh
- .CalculatePath(transform.position,
- target,
- NavMesh.AllAreas,
- path);
- if (!hasPath) return false; // 如果没有路径,返回false
-
- // 如果路径不完整,返回false
- if (path.status != NavMeshPathStatus.PathComplete) return false;
-
- // 如果路径长度超过最大限制,返回false
- if (GetPathLength(path) > maxNavPathLength) return false;
-
- // 返回true,表示成功找到有效路径
- return true;
- }
-
- private float GetPathLength(NavMeshPath path)
- {
- float total = 0; // 初始化路径长度
-
- if (path.corners.Length < 2) return 0; // 如果路径角点少于2,返回0
-
- // 计算路径长度
- for (int i = 0; i < path.corners.Length - 1; i++)
- {
- total += Vector3.Distance(path.corners[i], path.corners[i + 1]); // 累加各段距离
- }
-
- return total; // 返回总路径长度
- }
-
- private static Ray GetMouseRay()
- {
- return Camera.main.ScreenPointToRay(Input.mousePosition); // 从鼠标位置获取射线
- }
- }
- }
复制代码
AIController
复制代码
PatrolPath
- using System.Collections; // 引入集合相关命名空间
- using System.Collections.Generic; // 引入泛型集合相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.Control // 定义RPG控制相关的命名空间
- {
- public class PatrolPath : MonoBehaviour // 巡逻路径类
- {
- const float wayPointGizmoRadius = 0.3f; // 路点在Gizmos中显示的半径
-
- private void OnDrawGizmos() // 在编辑器中绘制Gizmos
- {
- for (int i = 0; i < transform.childCount; i++) // 遍历所有子对象
- {
- int j = GetNextIndex(i); // 获取下一个路点的索引
- Gizmos.DrawSphere(GetWaypoint(i), wayPointGizmoRadius); // 绘制当前路点的球体
- Gizmos.DrawLine(GetWaypoint(i), GetWaypoint(j)); // 绘制当前路点与下一个路点之间的连线
- }
- }
-
- public int GetNextIndex(int i) // 获取下一个路点的索引
- {
- // 如果当前路点是最后一个路点,则返回第一个路点的索引
- if (i + 1 == transform.childCount)
- {
- return 0;
- }
-
- return i + 1; // 否则返回下一个路点的索引
- }
-
- public Vector3 GetWaypoint(int i) // 获取指定索引的路点位置
- {
- return transform.GetChild(i).position; // 返回子对象的
- }
- }
- }
复制代码
IRaycastable
- namespace RPG.Control
- {
- public interface IRaycastable
- {
- CursorType GetCursorType();
-
- bool HandleRaycast(PlayerController callingController);
- }
- }
复制代码
CursorType
- namespace RPG.Control
- {
- public enum CursorType
- {
- None,
- Movement,
- Combat,
- UI,
- Pickup
- }
- }
复制代码
ActionScheduler
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace RPG.Core
- {
- public class ActionScheduler : MonoBehaviour
- {
- IAction currentAction;
-
- public void StartAction(IAction action)
- {
- if (currentAction == action)
- {
- return;
- }
-
- if (currentAction != null)
- {
- currentAction.Cancel();
- print($"Canceling {currentAction}");
- }
-
- currentAction = action;
- }
-
- public void CancelCurrentAction()
- {
- StartAction(null);
- }
- }
- }
复制代码
CameraFacing
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace RPG.Core
- {
- public class CameraFacing : MonoBehaviour
- {
- void LateUpdate()
- {
- transform.forward = Camera.main.transform.forward;
- }
- }
- }
复制代码
DestroyAfterEffect
- using UnityEngine;
-
- namespace RPG.Core
- {
- public class DestroyAfterEffect : MonoBehaviour
- {
- [SerializeField]
- GameObject targetToDestroy = null;
-
- void Update()
- {
- if (!GetComponent<ParticleSystem>().IsAlive())
- {
- if (targetToDestroy != null)
- {
- Destroy (targetToDestroy);
- }
- else
- {
- Destroy(this.gameObject);
- }
- }
- }
- }
- }
复制代码
FollowCamera
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace RPG.Core
- {
- public class FollowCamera : MonoBehaviour
- {
- [SerializeField]
- Transform target;
-
- void LateUpdate()
- {
- transform.position = target.position;
- }
- }
- }
复制代码
IAction
- namespace RPG.Core
- {
- public interface IAction
- {
- void Cancel();
- }
- }
复制代码
PersistentObjectSpawner
- using UnityEngine;
-
- namespace RPG.Core
- {
- public class PersistentObjectSpawner : MonoBehaviour
- {
- [SerializeField]
- GameObject persistentObjectPrefab;
-
-
- static bool hasSpawned = false;
-
- private void Awake()
- {
- if (hasSpawned)
- {
- return;
- }
-
- SpawnPersistentObjects();
-
- hasSpawned = true;
- }
-
- private void SpawnPersistentObjects()
- {
- GameObject persistentObject = Instantiate(persistentObjectPrefab);
- DontDestroyOnLoad (persistentObject);
- }
- }
- }
复制代码
CombatTarget
- using RPG.Attributes;
- using RPG.Control;
- using UnityEngine;
-
- namespace RPG.Combat
- {
- [RequireComponent(typeof (Health))]
- public class CombatTarget : MonoBehaviour, IRaycastable
- {
- public CursorType GetCursorType()
- {
- return CursorType.Combat;
- }
-
- public bool HandleRaycast(PlayerController callingController)
- {
- if (!callingController.GetComponent<Fighter>().CanAttack(gameObject)
- )
- {
- return false;
- }
-
- if (Input.GetMouseButton(0))
- {
- callingController.GetComponent<Fighter>().Attack(gameObject);
- }
-
- return true;
- }
- }
- }
复制代码
EnemyHealthDisplay
- using System;
- using RPG.Attributes;
- using UnityEngine;
- using UnityEngine.UI;
-
- namespace RPG.Combat
- {
- public class EnemyHealthDisplay : MonoBehaviour
- {
- Fighter fighter;
-
- private void Awake()
- {
- fighter = GameObject.FindWithTag("Player").GetComponent<Fighter>();
- }
-
- private void Update()
- {
- if (fighter.GetTarget() == null)
- {
- GetComponent<Text>().text = "N/A";
- return;
- }
-
- Health health = fighter.GetTarget();
- GetComponent<Text>().text =
- String
- .Format("{0:0.0}/{1:0}",
- health.GetHealthPoints(),
- health.GetMaxHealthPoints());
- }
- }
- }
复制代码
Fighter
- using System; // 引入系统命名空间
- using System.Collections.Generic; // 引入泛型集合相关命名空间
- using GameDevTV.Utils; // 引入GameDevTV工具相关命名空间
- using RPG.Attributes; // 引入角色属性相关的命名空间
- using RPG.Core; // 引入核心功能相关的命名空间
- using RPG.Movement; // 引入移动相关的命名空间
- using RPG.Saving; // 引入存档相关的命名空间
- using RPG.Stats; // 引入角色状态相关的命名空间
- using UnityEngine; // 引入Unity引擎相关的命名空间
-
- namespace RPG.Combat // 定义RPG战斗相关的命名空间
- {
- public class Fighter : MonoBehaviour, IAction, ISaveable, IModifierProvider // 战斗者类
- {
- [SerializeField]
- float timeBetweenAttacks = 1f; // 攻击之间的时间间隔
-
- [SerializeField]
- Transform rightHandTransform = null; // 右手的变换组件
-
- [SerializeField]
- Transform leftHandTransform = null; // 左手的变换组件
-
- [SerializeField]
- WeaponConfig defaultWeapon = null; // 默认武器配置
-
- Health target; // 当前目标的生命值组件
-
- float timeSinceLastAttack = Mathf.Infinity; // 自上次攻击以来的时间
-
- WeaponConfig currentWeaponConfig; // 当前武器配置
-
- LazyValue<Weapon> currentWeapon; // 当前武器
-
- private void Awake()
- {
- currentWeaponConfig = defaultWeapon; // 初始化当前武器配置为默认武器
- currentWeapon = new LazyValue<Weapon>(SetupDefaultWeapon); // 懒加载当前武器
- }
-
- private Weapon SetupDefaultWeapon()
- {
- return AttachWeapon(defaultWeapon); // 附加默认武器
- }
-
- private void Start()
- {
- currentWeapon.ForceInit(); // 强制初始化当前武器
- }
-
- private void Update()
- {
- timeSinceLastAttack += Time.deltaTime; // 更新自上次攻击以来的时间
-
- // 如果没有攻击目标,什么也不做
- if (target == null || target.IsDead())
- {
- return;
- }
-
- // 如果目标存在
- if (!GetIsInRange()) // 如果不在攻击范围内
- {
- // 移动到目标位置
- GetComponent<Mover>().MoveTo(target.transform.position, 1f);
- }
- else
- {
- // 停止移动
- GetComponent<Mover>().Cancel();
- AttackBehaviour(); // 执行攻击行为
- }
- }
-
- public void EquipWeapon(WeaponConfig weapon) // 装备武器
- {
- currentWeaponConfig = weapon; // 更新当前武器配置
- currentWeapon.value = AttachWeapon(weapon); // 附加新武器
- }
-
- private Weapon AttachWeapon(WeaponConfig weapon) // 附加武器
- {
- Animator animator = GetComponent<Animator>(); // 获取动画组件
- return weapon
- .Spawn(rightHandTransform, leftHandTransform, animator); // 在手上生成武器
- }
-
- public Health GetTarget() // 获取当前目标的生命值组件
- {
- return target;
- }
-
- public bool CanAttack(GameObject combatTarget) // 判断是否可以攻击目标
- {
- if (combatTarget == null)
- {
- return false; // 目标为空时返回false
- }
-
- Health targetToTest = combatTarget.GetComponent<Health>(); // 获取目标的生命值组件
- return !targetToTest.IsDead(); // 如果目标未死亡,则返回true
- }
-
- public void Attack(GameObject combatTarget) // 开始攻击目标
- {
- GetComponent<ActionScheduler>().StartAction(this); // 启动当前行动
- target = combatTarget.GetComponent<Health>(); // 设置目标的生命值组件
- }
-
- private void AttackBehaviour() // 攻击行为
- {
- transform.LookAt(target.transform); // 朝向目标
- if (timeSinceLastAttack > timeBetweenAttacks) // 如果已经超过攻击间隔
- {
- TriggerAttack(); // 触发攻击
- timeSinceLastAttack = 0f; // 重置上次攻击时间
- }
- }
-
- private void TriggerAttack() // 触发攻击动画
- {
- GetComponent<Animator>().ResetTrigger("stopAttack"); // 重置停止攻击触发器
- GetComponent<Animator>().SetTrigger("attack"); // 设置攻击触发器
- }
-
- // 动画事件
- void Hit()
- {
- if (!target) return; // 如果没有目标则返回
-
- float damage = GetComponent<BaseStats>().GetStat(Stat.Damage); // 获取伤害值
-
- if (currentWeapon.value != null) // 如果当前武器不为空
- {
- currentWeapon.value.OnHit(); // 执行武器的命中逻辑
- }
-
- // 检查当前武器是否有投射物
- if (currentWeaponConfig.HasProjectile())
- {
- currentWeaponConfig.LaunchProjectile(
- rightHandTransform, // 右手变换
- leftHandTransform, // 左手变换
- target, // 目标
- gameObject, // 攻击者
- damage // 伤害值
- );
- }
- else // 否则直接造成伤害
- {
- target.TakeDamage(gameObject, damage); // 目标受到伤害
- }
- }
-
- // 动画中的射击事件
- void Shoot()
- {
- Hit(); // 调用命中方法
- }
-
- private bool GetIsInRange() // 检查是否在攻击范围内
- {
- return Vector3
- .Distance(transform.position, target.transform.position) <
- currentWeaponConfig.GetRange(); // 比较距离和武器范围
- }
-
- public void Cancel() // 取消当前攻击
- {
- StopAttack(); // 停止攻击
- target = null; // 清空目标
- GetComponent<Mover>().Cancel(); // 取消移动
- }
-
- private void StopAttack() // 停止攻击动画
- {
- GetComponent<Animator>().ResetTrigger("attack"); // 重置攻击触发器
- GetComponent<Animator>().SetTrigger("stopAttack"); // 设置停止攻击触发器
- }
-
- public object CaptureState() // 捕获当前状态
- {
- return currentWeaponConfig.name; // 返回当前武器的名称
- }
-
- public void RestoreState(object state) // 恢复状态
- {
- string weaponName = (string)state; // 将状态转换为武器名称
- WeaponConfig weapon = Resources.Load<WeaponConfig>(weaponName); // 从资源中加载武器配置
- EquipWeapon(weapon); // 装备武器
- }
-
- public IEnumerable<float> GetAdditiveModifiers(Stat stat) // 获取加成修正
- {
- if (stat == Stat.Damage) // 如果是伤害修正
- {
- yield return currentWeaponConfig.GetDamage(); // 返回当前武器的伤害
- }
- }
-
- public IEnumerable<float> GetPercentageModifiers(Stat stat) // 获取百分比修正
- {
- if (stat == Stat.Damage) // 如果是伤害修正
- {
- yield return currentWeaponConfig.GetPercentageBonus(); // 返回当前武器的百分比加成
- }
- }
- }
- }
复制代码
Projectile
复制代码 Weapon
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- namespace RPG.Combat
- {
- public class Weapon : MonoBehaviour
- {
- public void OnHit()
- {
- print($"Weapon Hit {gameObject.name}");
- }
- }
- }
复制代码
WeaponConfig
- using RPG.Attributes; // 引入角色属性相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.Combat // 定义RPG战斗相关的命名空间
- {
- [
- CreateAssetMenu(
- fileName = "Weapon", // 创建的资产文件名
- menuName = "Weapons/Make New Weapon", // 菜单中显示的名称
- order = 0) // 菜单中的顺序
- ]
- public class WeaponConfig : ScriptableObject // 武器配置类,继承自ScriptableObject
- {
- [SerializeField]
- AnimatorOverrideController animatorOverride = null; // 动画覆盖控制器
-
- [SerializeField]
- Weapon equippedPrefab = null; // 装备的武器预制件
-
- [SerializeField]
- float weaponDamage = 5f; // 武器伤害
-
- [SerializeField]
- float percentageBonus = 0; // 伤害百分比加成
-
- [SerializeField]
- float weaponRange = 2f; // 武器攻击范围
-
- [SerializeField]
- bool isRightHanded = true; // 是否为右手武器
-
- [SerializeField]
- Projectile projectile = null; // 武器的投射物
-
- const string weaponName = "Weapon"; // 武器名称常量
-
- // 实例化并装备武器
- public Weapon Spawn(Transform rightHand, Transform leftHand, Animator animator)
- {
- DestroyOldWeapon(rightHand, leftHand); // 销毁旧的武器
-
- Weapon weapon = null; // 初始化武器变量
-
- if (equippedPrefab != null) // 如果有装备的预制件
- {
- Transform handTransform = GetTransform(rightHand, leftHand); // 获取手部变换
-
- weapon = Instantiate(equippedPrefab, handTransform); // 实例化武器
- weapon.gameObject.name = weaponName; // 设置武器名称
- }
-
- var overrideController =
- animator.runtimeAnimatorController as
- AnimatorOverrideController; // 获取动画覆盖控制器
-
- if (animatorOverride != null) // 如果有动画覆盖
- {
- animator.runtimeAnimatorController = animatorOverride; // 设置动画控制器为覆盖控制器
- }
- else if (overrideController) // 如果已经有覆盖控制器
- {
-
- animator.runtimeAnimatorController =
- overrideController.runtimeAnimatorController; // 更新为默认动画控制器
- }
-
- return weapon; // 返回装备的武器
- }
-
- // 销毁旧武器
- private void DestroyOldWeapon(Transform rightHand, Transform leftHand)
- {
- // 查找旧武器
- Transform oldWeapon = rightHand.Find(weaponName);
- if (oldWeapon == null)
- {
- oldWeapon = leftHand.Find(weaponName); // 如果右手没有找到,查找左手
- }
-
- // 如果没有找到旧武器
- if (oldWeapon == null)
- {
- return; // 直接返回
- }
-
- // 销毁旧武器
- oldWeapon.name = "DESTROYING"; // 设置名称为销毁中
- Destroy(oldWeapon.gameObject); // 销毁游戏对象
- }
-
- // 获取手部变换
- private Transform GetTransform(Transform rightHand, Transform leftHand)
- {
- Transform handTransform;
- if (isRightHanded) // 如果是右手
- {
- handTransform = rightHand; // 使用右手变换
- }
- else // 如果是左手
- {
- handTransform = leftHand; // 使用左手变换
- }
-
- return handTransform; // 返回手部变换
- }
-
- // 检查武器是否有投射物
- public bool HasProjectile()
- {
- return projectile != null; // 返回投射物是否为null
- }
-
- // 发射投射物
- public void LaunchProjectile(
- Transform rightHand,
- Transform leftHand,
- Health target,
- GameObject instigator,
- float calculatedDamage
- )
- {
- // 实例化投射物
- Projectile projectileInstance =
- Instantiate(projectile,
- GetTransform(rightHand, leftHand).position,
- Quaternion.identity);
-
- // 设置投射物的目标、发射者和伤害值
- projectileInstance.SetTarget(target, instigator, calculatedDamage);
- }
-
- // 获取武器攻击范围
- public float GetRange()
- {
- return weaponRange; // 返回武器范围
- }
-
- // 获取武器的百分比加成
- public float GetPercentageBonus()
- {
- return percentageBonus; // 返回百分比加成
- }
-
- // 获取武器的基础伤害
- public float GetDamage()
- {
- return weaponDamage; // 返回武器伤害
- }
- }
- }
复制代码
WeaponPickup
- using System; // 引入系统命名空间
- using System.Collections; // 引入集合命名空间
- using RPG.Control; // 引入角色控制相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.Combat // 定义RPG战斗相关的命名空间
- {
- public class WeaponPickup : MonoBehaviour, IRaycastable // 武器拾取类,继承自MonoBehaviour,并实现IRaycastable接口
- {
- [SerializeField]
- WeaponConfig weapon = null; // 武器配置,序列化以便在Inspector中设置
-
- [SerializeField]
- float respawnTime = 5f; // 武器重生时间
-
- // 当玩家进入触发器时调用
- private void OnTriggerEnter(Collider other)
- {
- // 检查进入的对象是否为玩家
- if (other.gameObject.tag == "Player")
- {
- Pickup(other.GetComponent<Fighter>()); // 拾取武器
- }
- }
-
- // 拾取武器的方法
- private void Pickup(Fighter fighter)
- {
- fighter.EquipWeapon(weapon); // 为战斗者装备武器
- StartCoroutine(HideForSeconds(respawnTime)); // 启动协程隐藏武器
- }
-
- // 协程:在指定时间后隐藏武器
- private IEnumerator HideForSeconds(float seconds)
- {
- ShowPickup(false); // 隐藏武器
- yield return new WaitForSeconds(seconds); // 等待指定的时间
- ShowPickup(true); // 重新显示武器
- }
-
- // 控制武器的显示与隐藏
- private void ShowPickup(bool shouldShow)
- {
- GetComponent<Collider>().enabled = shouldShow; // 启用或禁用触发器
-
- // 方法1:设置子物体的激活状态
- // transform.GetChild(0).gameObject.SetActive(shouldShow);
- //
- // 方法2:遍历所有子物体,设置它们的激活状态
- foreach (Transform child in transform)
- {
- child.gameObject.SetActive(shouldShow); // 设置子物体的显示状态
- }
- }
-
- // 实现IRaycastable接口的方法,处理射线检测
- public bool HandleRaycast(PlayerController callingController)
- {
- // 如果鼠标左键被按下,拾取武器
- if (Input.GetMouseButtonDown(0))
- {
- Pickup(callingController.GetComponent<Fighter>());
- }
-
- return true; // 返回true表示处理成功
- }
-
- // 获取光标类型,用于拾取武器时的光标显示
- public CursorType GetCursorType()
- {
- return CursorType.Pickup; // 返回拾取光标类型
- }
- }
- }
复制代码
Fader
- using System.Collections; // 引入集合命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.SceneManagement // 定义RPG场景管理相关的命名空间
- {
- public class Fader : MonoBehaviour // Fader类,负责场景的淡入淡出效果
- {
- CanvasGroup canvasGroup; // 用于控制UI元素的透明度
-
- Coroutine currentActiveFade; // 当前正在执行的淡入淡出协程
-
- private void Start() // Unity生命周期方法,在对象初始化时调用
- {
- canvasGroup = GetComponent<CanvasGroup>(); // 获取CanvasGroup组件
- }
-
- public void FadeOutImmediate() // 立即淡出方法
- {
- canvasGroup.alpha = 1; // 将透明度设置为1(完全可见)
- }
-
- public Coroutine FadeOut(float time) // 淡出方法,返回一个协程
- {
- return Fade(1, time); // 调用Fade方法,目标透明度为1
- }
-
- public Coroutine FadeIn(float time) // 淡入方法,返回一个协程
- {
- return Fade(0, time); // 调用Fade方法,目标透明度为0
- }
-
- // target = 目标透明度
- public Coroutine Fade(float target, float time) // 淡入淡出通用方法
- {
- if (currentActiveFade != null) // 检查是否有正在执行的淡入淡出
- {
- StopCoroutine(currentActiveFade); // 停止当前的协程
- }
-
- currentActiveFade = StartCoroutine(FadeRoutine(target, time)); // 启动新的淡入淡出协程
- return currentActiveFade; // 返回当前协程
- }
-
- private IEnumerator FadeRoutine(float target, float time) // 实际的淡入淡出过程
- {
- while (!Mathf.Approximately(canvasGroup.alpha, target)) // 当当前透明度与目标透明度不相等时
- {
- // 根据时间逐步调整透明度
- canvasGroup.alpha =
- Mathf
- .MoveTowards(canvasGroup.alpha,
- target,
- Time.deltaTime / time); // 逐步接近目标透明度
-
- yield return null; // 等待下一帧
- }
- }
- }
- }
复制代码
Portal
复制代码 SavingWrapper
- using System.Collections; // 引入集合命名空间
- using RPG.Saving; // 引入保存相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.SceneManagement // 定义RPG场景管理相关的命名空间
- {
- public class SavingWrapper : MonoBehaviour // SavingWrapper类,用于处理保存和加载场景
- {
- const string defaultSaveFile = "save"; // 默认保存文件名
-
- [SerializeField]
- float fadeInTime = 0.2f; // 淡入时间
-
- private void Awake() // 在对象激活时调用
- {
- StartCoroutine(LoadLastScene()); // 开始加载上一个场景的协程
- }
-
- IEnumerator LoadLastScene() // 协程:加载上一个场景
- {
- // 异步加载最后一个保存的场景
- yield return GetComponent<SavingSystem>()
- .LoadLastScene(defaultSaveFile);
-
- Fader fader = FindObjectOfType<Fader>(); // 查找Fader对象
- fader.FadeOutImmediate(); // 立即执行淡出效果
-
- yield return fader.FadeIn(fadeInTime); // 执行淡入效果
- }
-
- void Update() // 每帧更新
- {
- if (Input.GetKeyDown(KeyCode.L)) // 如果按下L键
- {
- Load(); // 加载保存
- }
-
- if (Input.GetKeyDown(KeyCode.S)) // 如果按下S键
- {
- Save(); // 保存游戏
- }
-
- if (Input.GetKeyDown(KeyCode.D)) // 如果按下D键
- {
- Delete(); // 删除保存
- }
- }
-
- public void Save() // 保存方法
- {
- GetComponent<SavingSystem>().Save(defaultSaveFile); // 调用保存系统保存数据
- }
-
- public void Load() // 加载方法
- {
- GetComponent<SavingSystem>().Load(defaultSaveFile); // 调用保存系统加载数据
- }
-
- public void Delete() // 删除保存方法
- {
- GetComponent<SavingSystem>().Delete(defaultSaveFile); // 调用保存系统删除数据
- }
- }
- }
复制代码
ISaveable
- namespace RPG.Saving
- {
- public interface ISaveable
- {
- object CaptureState();
- void RestoreState(object state);
- }
- }
复制代码
SaveableEntity
- using System; // 引入基本命名空间
- using System.Collections.Generic; // 引入集合命名空间
- using RPG.Core; // 引入RPG核心命名空间
- using UnityEditor; // 引入Unity编辑器相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
- using UnityEngine.AI; // 引入Unity导航系统相关命名空间
-
- namespace RPG.Saving // 定义RPG保存相关的命名空间
- {
- [ExecuteAlways] // 使该类在编辑模式和播放模式下都能执行
- public class SaveableEntity : MonoBehaviour // SaveableEntity类,表示可保存的实体
- {
- [SerializeField] string uniqueIdentifier = ""; // 唯一标识符
- static Dictionary<string, SaveableEntity> globalLookup = new Dictionary<string, SaveableEntity>(); // 全局查找字典
-
- public string GetUniqueIdentifier() // 获取唯一标识符
- {
- return uniqueIdentifier;
- }
-
- public object CaptureState() // 捕获状态
- {
- Dictionary<string, object> state = new Dictionary<string, object>(); // 创建状态字典
- foreach (ISaveable saveable in GetComponents<ISaveable>()) // 获取所有可保存组件
- {
- // 将每个可保存组件的状态添加到状态字典
- state[saveable.GetType().ToString()] = saveable.CaptureState();
- }
- return state; // 返回状态字典
- }
-
- public void RestoreState(object state) // 恢复状态
- {
- Dictionary<string, object> stateDict = (Dictionary<string, object>)state; // 将状态转换为字典
- foreach (ISaveable saveable in GetComponents<ISaveable>()) // 获取所有可保存组件
- {
- string typeString = saveable.GetType().ToString(); // 获取组件类型字符串
- if (stateDict.ContainsKey(typeString)) // 如果状态字典包含该类型
- {
- saveable.RestoreState(stateDict[typeString]); // 恢复状态
- }
- }
- }
-
- #if UNITY_EDITOR
- private void Update() // 编辑器更新方法
- {
- if (Application.IsPlaying(gameObject)) return; // 如果正在播放,则返回
- if (string.IsNullOrEmpty(gameObject.scene.path)) return; // 如果场景路径为空,则返回
-
- SerializedObject serializedObject = new SerializedObject(this); // 创建序列化对象
- SerializedProperty property = serializedObject.FindProperty("uniqueIdentifier"); // 查找唯一标识符属性
-
- // 如果唯一标识符为空或不唯一
- if (string.IsNullOrEmpty(property.stringValue) || !IsUnique(property.stringValue))
- {
- property.stringValue = System.Guid.NewGuid().ToString(); // 生成新的唯一标识符
- serializedObject.ApplyModifiedProperties(); // 应用修改
- }
-
- globalLookup[property.stringValue] = this; // 将当前对象添加到全局查找字典
- }
- #endif
-
- private bool IsUnique(string candidate) // 检查唯一性
- {
- if (!globalLookup.ContainsKey(candidate)) return true; // 如果字典中不存在该候选标识符,则返回true
-
- if (globalLookup[candidate] == this) return true; // 如果字典中的对象是当前对象,则返回true
-
- if (globalLookup[candidate] == null) // 如果字典中的对象为空
- {
- globalLookup.Remove(candidate); // 从字典中移除该标识符
- return true; // 返回true
- }
-
- if (globalLookup[candidate].GetUniqueIdentifier() != candidate) // 如果字典中的对象的唯一标识符与候选标识符不一致
- {
- globalLookup.Remove(candidate); // 从字典中移除该标识符
- return true; // 返回true
- }
-
- return false; // 否则返回false
- }
- }
- }
复制代码
SavingSystem
- using System; // 引入基本命名空间
- using System.Collections; // 引入集合命名空间
- using System.Collections.Generic; // 引入泛型集合命名空间
- using System.IO; // 引入输入输出相关命名空间
- using System.Runtime.Serialization.Formatters.Binary; // 引入二进制格式化器
- using System.Text; // 引入字符串处理相关命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
- using UnityEngine.SceneManagement; // 引入场景管理相关命名空间
-
- namespace RPG.Saving // 定义RPG保存相关的命名空间
- {
- public class SavingSystem : MonoBehaviour // 保存系统类
- {
- // 加载上一个场景
- public IEnumerator LoadLastScene(string saveFile)
- {
- Dictionary<string, object> state = LoadFile(saveFile); // 加载保存文件
- int buildIndex = SceneManager.GetActiveScene().buildIndex; // 获取当前场景的构建索引
- if (state.ContainsKey("lastSceneBuildIndex")) // 如果状态包含最后场景的构建索引
- {
- buildIndex = (int)state["lastSceneBuildIndex"]; // 更新构建索引
- }
- yield return SceneManager.LoadSceneAsync(buildIndex); // 异步加载场景
- RestoreState(state); // 恢复状态
- }
-
- // 保存游戏状态
- public void Save(string saveFile)
- {
- Dictionary<string, object> state = LoadFile(saveFile); // 加载保存文件
- CaptureState(state); // 捕获当前状态
- SaveFile(saveFile, state); // 保存状态到文件
- }
-
- // 加载游戏状态
- public void Load(string saveFile)
- {
- RestoreState(LoadFile(saveFile)); // 恢复从保存文件加载的状态
- }
-
- // 删除保存文件
- public void Delete(string saveFile)
- {
- File.Delete(GetPathFromSaveFile(saveFile)); // 删除指定的保存文件
- }
-
- // 加载保存文件
- private Dictionary<string, object> LoadFile(string saveFile)
- {
- string path = GetPathFromSaveFile(saveFile); // 获取保存文件路径
- if (!File.Exists(path)) // 如果文件不存在
- {
- return new Dictionary<string, object>(); // 返回空字典
- }
- using (FileStream stream = File.Open(path, FileMode.Open)) // 打开文件流
- {
- BinaryFormatter formatter = new BinaryFormatter(); // 创建二进制格式化器
- return (Dictionary<string, object>)
- formatter.Deserialize(stream); // 反序列化并返回状态字典
- }
- }
-
- // 保存状态到文件
- private void SaveFile(string saveFile, object state)
- {
- string path = GetPathFromSaveFile(saveFile); // 获取保存文件路径
- print("Saving to " + path); // 输出保存路径
- using (FileStream stream = File.Open(path, FileMode.Create)) // 创建文件流
- {
- BinaryFormatter formatter = new BinaryFormatter(); // 创建二进制格式化器
- formatter.Serialize(stream, state); // 序列化状态并保存
- }
- }
-
- // 捕获当前游戏状态
- private void CaptureState(Dictionary<string, object> state)
- {
- foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>()) // 遍历所有可保存实体
- {
- state[saveable.GetUniqueIdentifier()] = saveable.CaptureState(); // 捕获状态并添加到字典
- }
-
- state["lastSceneBuildIndex"] = SceneManager.GetActiveScene().buildIndex; // 保存当前场景的构建索引
- }
-
- // 恢复游戏状态
- private void RestoreState(Dictionary<string, object> state)
- {
- foreach (SaveableEntity saveable in FindObjectsOfType<SaveableEntity>()) // 遍历所有可保存实体
- {
- string id = saveable.GetUniqueIdentifier(); // 获取唯一标识符
- if (state.ContainsKey(id)) // 如果状态字典包含该标识符
- {
- saveable.RestoreState(state[id]); // 恢复状态
- }
- }
- }
-
- // 获取保存文件路径
- private string GetPathFromSaveFile(string saveFile)
- {
- return Path.Combine(Application.persistentDataPath, saveFile + ".sav"); // 生成完整的保存文件路径
- }
- }
- }
复制代码
SerializableVector3
- using UnityEngine;
-
- namespace RPG.Saving
- {
- [System.Serializable]
- public class SerializableVector3
- {
- float x, y, z;
-
- public SerializableVector3(Vector3 vector)
- {
- x = vector.x;
- y = vector.y;
- z = vector.z;
- }
-
- public Vector3 ToVector()
- {
- return new Vector3(x, y, z);
- }
- }
- }
复制代码
CinematicTrigger
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.Playables;
-
- namespace RPG.Cinematics
- {
- public class CinematicTrigger : MonoBehaviour
- {
- bool alreadyTriggered = false;
-
- private void OnTriggerEnter(Collider other)
- {
- if (!alreadyTriggered && other.gameObject.tag == "Player")
- {
- alreadyTriggered = true;
- GetComponent<PlayableDirector>().Play();
- }
- }
- }
- }
复制代码
CinematicControlRemover
- using RPG.Control;
- using RPG.Core;
- using UnityEngine;
- using UnityEngine.Playables;
-
- public class CinematicControlRemover : MonoBehaviour
- {
- GameObject player;
-
- private void Awake()
- {
- player = GameObject.FindWithTag("Player");
- }
-
- private void OnEnable()
- {
- // event + observer pattern in C#
- GetComponent<PlayableDirector>().played += DisableControl;
- GetComponent<PlayableDirector>().stopped += EnableControl;
- }
-
- private void OnDisable()
- {
- GetComponent<PlayableDirector>().played -= DisableControl;
- GetComponent<PlayableDirector>().stopped -= EnableControl;
- }
-
- void DisableControl(PlayableDirector pd)
- {
- player.GetComponent<ActionScheduler>().CancelCurrentAction();
- player.GetComponent<PlayerController>().enabled = false;
- }
-
- void EnableControl(PlayableDirector pd)
- {
- player.GetComponent<PlayerController>().enabled = true;
- }
- }
复制代码
BaseStats
复制代码 CharacterClass
- namespace RPG.Stats
- {
- public enum CharacterClass
- {
- Player,
- Grunt,
- Mage,
- Archer
- }
- }
复制代码
Experience
- using System;
- using RPG.Saving;
- using UnityEngine;
-
- namespace RPG.Stats
- { }
-
- public class Experience : MonoBehaviour, ISaveable
- {
- [SerializeField]
- float experiencePoints = 0;
-
- public event Action onExperienceGained;
-
- public void GainExperience(float experience)
- {
- experiencePoints += experience;
- onExperienceGained();
- }
-
- public object CaptureState()
- {
- return experiencePoints;
- }
-
- public void RestoreState(object state)
- {
- this.experiencePoints = (float) state;
- }
-
- public float GetPoint()
- {
- return experiencePoints;
- }
- }
复制代码
ExperienceDisplay
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- namespace RPG.Stats
- {
- public class ExperienceDisplay : MonoBehaviour
- {
- Experience experience;
-
- private void Awake()
- {
- experience =
- GameObject.FindWithTag("Player").GetComponent<Experience>();
- }
-
- private void Update()
- {
- GetComponent<Text>().text =
- String.Format("{0:0.0}", experience.GetPoint());
- }
- }
- }
复制代码
IModifierProvider
- using System.Collections.Generic;
-
- namespace RPG.Stats
- {
- public interface IModifierProvider
- {
- IEnumerable<float> GetAdditiveModifiers(Stat stat);
-
- IEnumerable<float> GetPercentageModifiers(Stat stat);
- }
- }
复制代码
LevelDisplay
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- namespace RPG.Stats
- {
- public class LevelDisplay : MonoBehaviour
- {
- BaseStats baseStats;
-
- private void Awake()
- {
- baseStats =
- GameObject.FindWithTag("Player").GetComponent<BaseStats>();
- }
-
- private void Update()
- {
- GetComponent<Text>().text =
- String.Format("{0:0.0}", baseStats.GetLevel());
- }
- }
- }
复制代码
Progression
- using System; // 引入基本命名空间
- using System.Collections.Generic; // 引入泛型集合命名空间
- using UnityEngine; // 引入Unity引擎相关命名空间
-
- namespace RPG.Stats // 定义RPG统计相关的命名空间
- {
- [
- CreateAssetMenu(
- fileName = "Progression", // 资源文件名
- menuName = "Stats/New Progression", // 菜单名称
- order = 0) // 菜单排序
- ]
- public class Progression : ScriptableObject // 角色进展类
- {
- [SerializeField]
- ProgressionCharacterClass[] characterClasses = null; // 角色职业数组
-
- Dictionary<CharacterClass, Dictionary<Stat, float[]>> lookupTable = null; // 查找表
-
- // 获取指定角色职业在特定等级的属性值
- public float GetStat(Stat stat, CharacterClass characterClass, int level)
- {
- BuildLookup(); // 构建查找表
-
- float[] levels = lookupTable[characterClass][stat]; // 获取该职业的属性等级数组
-
- if (levels.Length < level) // 如果等级超出范围
- {
- return 0; // 返回0
- }
-
- return levels[level - 1]; // 返回对应等级的属性值
- }
-
- // 获取指定角色职业的属性等级总数
- public int GetLevels(Stat stat, CharacterClass characterClass)
- {
- BuildLookup(); // 构建查找表
-
- float[] levels = lookupTable[characterClass][stat]; // 获取该职业的属性等级数组
- return levels.Length; // 返回属性等级总数
- }
-
- private void BuildLookup() // 构建查找表的方法
- {
- if (lookupTable != null) // 如果查找表已经构建
- {
- return; // 直接返回
- }
-
- lookupTable = new Dictionary<CharacterClass, Dictionary<Stat, float[]>>(); // 初始化查找表
-
- foreach (ProgressionCharacterClass progressionClass in characterClasses) // 遍历每个职业
- {
- var statLookupTable = new Dictionary<Stat, float[]>(); // 创建属性查找表
-
- foreach (ProgressionStat progressionStat in progressionClass.stats) // 遍历每个职业的属性
- {
- statLookupTable[progressionStat.stat] = progressionStat.levels; // 将属性及其等级值添加到查找表
- }
-
- lookupTable[progressionClass.characterClass] = statLookupTable; // 将职业及其属性查找表添加到主查找表
- }
- }
-
- [Serializable] // 可序列化类
- class ProgressionCharacterClass // 职业进展类
- {
- public CharacterClass characterClass; // 角色职业
-
- public ProgressionStat[] stats; // 职业对应的属性数组
- }
-
- [Serializable] // 可序列化类
- class ProgressionStat // 属性进展类
- {
- public Stat stat; // 属性类型
-
- public float[] levels; // 属性在各等级的值
- }
- }
- }
复制代码
Stats
- using UnityEngine;
-
- namespace RPG.Stats
- {
- public enum Stat
- {
- Health,
- ExperienceReward,
- ExperienceToLevelUp,
- Damage
- }
- }
复制代码
Health
复制代码 HealthBar
- using UnityEngine;
-
- namespace RPG.Attributes
- {
- public class HealthBar : MonoBehaviour
- {
- [SerializeField]
- Health healthComponent = null;
-
- [SerializeField]
- RectTransform foreground = null;
-
- [SerializeField]
- Canvas rootCanvas = null;
-
- void Update()
- {
- if (
- Mathf.Approximately(healthComponent.GetFraction(), 0) ||
- Mathf.Approximately(healthComponent.GetFraction(), 1)
- )
- {
- rootCanvas.enabled = false;
- return;
- }
-
- foreground.localScale =
- new Vector3(healthComponent.GetFraction(), 1, 1);
- }
- }
- }
复制代码
HealthDisplay
- using System;
- using UnityEngine;
- using UnityEngine.UI;
-
- namespace RPG.Attributes
- {
- public class HealthDisplay : MonoBehaviour
- {
- Health health;
-
- private void Awake()
- {
- health = GameObject.FindWithTag("Player").GetComponent<Health>();
- }
-
- private void Update()
- {
- GetComponent<Text>().text =
- String
- .Format("{0:0.0}/{1:0}",
- health.GetHealthPoints(),
- health.GetMaxHealthPoints());
- }
- }
- }
复制代码
DamageText
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.UI;
-
- namespace RPG.UI.DamageText
- {
- public class DamageText : MonoBehaviour
- {
- [SerializeField]
- Text damageText = null;
-
- public void SetValue(float amount)
- {
- damageText.text = String.Format("{0:0}", amount);
- }
- }
- }
复制代码
DamageTextSpawner
- using UnityEngine;
-
- namespace RPG.UI.DamageText
- {
- public class DamageTextSpawner : MonoBehaviour
- {
- [SerializeField]
- DamageText damageTextPrefab = null;
-
- private void Start()
- {
- Spawn(11f);
- }
-
- public void Spawn(float damageAmount)
- {
- DamageText instance =
- Instantiate<DamageText>(damageTextPrefab, transform);
- instance.SetValue (damageAmount);
- }
- }
- }
复制代码
Destroyer
- using UnityEngine;
-
- namespace RPG.UI.DamageText
- {
- public class Destroyer : MonoBehaviour
- {
- [SerializeField]
- GameObject targetToDestroy = null;
-
- public void DestroyTarget()
- {
- // Destroy (targetToDestroy);
- }
- }
- }
复制代码
|