您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
118 行
4.4 KiB
118 行
4.4 KiB
using Unity.Netcode;
|
|
using UnityEngine;
|
|
|
|
namespace Unity.Multiplayer.Samples.BossRoom.Visual
|
|
{
|
|
/// <summary>
|
|
/// The TargetActionFX runs persistently on the local player, and will attach target reticules to the player's active target.
|
|
/// </summary>
|
|
public class TargetActionFX : ActionFX
|
|
{
|
|
private GameObject m_TargetReticule;
|
|
private ulong m_CurrentTarget;
|
|
private ulong m_NewTarget;
|
|
private NetworkCharacterState m_ParentState;
|
|
|
|
private const float k_ReticuleGroundHeight = 0.2f;
|
|
|
|
public TargetActionFX(ref ActionRequestData data, ClientCharacterVisualization parent) : base(ref data, parent)
|
|
{
|
|
}
|
|
|
|
public override bool Start()
|
|
{
|
|
base.Start();
|
|
m_ParentState = m_Parent.NetState;
|
|
|
|
m_ParentState.TargetId.OnValueChanged += OnTargetChanged;
|
|
m_ParentState.GetComponent<Client.ClientInputSender>().ActionInputEvent += OnActionInput;
|
|
|
|
return true;
|
|
}
|
|
|
|
private void OnTargetChanged(ulong oldTarget, ulong newTarget)
|
|
{
|
|
m_NewTarget = newTarget;
|
|
}
|
|
|
|
private void OnActionInput(ActionRequestData data)
|
|
{
|
|
//this method runs on the owning client, and allows us to anticipate our new target for purposes of FX visualization.
|
|
if (data.ActionTypeEnum == ActionType.GeneralTarget)
|
|
{
|
|
m_NewTarget = data.TargetIds[0];
|
|
}
|
|
}
|
|
|
|
public override bool Update()
|
|
{
|
|
if (m_CurrentTarget != m_NewTarget)
|
|
{
|
|
m_CurrentTarget = m_NewTarget;
|
|
|
|
if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(m_CurrentTarget, out NetworkObject targetObject))
|
|
{
|
|
var targetEntity = targetObject != null ? targetObject.GetComponent<ITargetable>() : null;
|
|
if (targetEntity != null)
|
|
{
|
|
ValidateReticule(targetObject);
|
|
m_TargetReticule.SetActive(true);
|
|
|
|
var parentTransform = targetObject.transform;
|
|
if (targetObject.TryGetComponent(out Client.ClientCharacter clientCharacter) && clientCharacter.ChildVizObject)
|
|
{
|
|
//for characters, attach the reticule to the child graphics object.
|
|
parentTransform = clientCharacter.ChildVizObject.transform;
|
|
}
|
|
|
|
m_TargetReticule.transform.parent = parentTransform;
|
|
m_TargetReticule.transform.localPosition = new Vector3(0, k_ReticuleGroundHeight, 0);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// null check here in case the target was destroyed along with the target reticule
|
|
if (m_TargetReticule != null)
|
|
{
|
|
m_TargetReticule.transform.parent = null;
|
|
m_TargetReticule.SetActive(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures that the TargetReticule GameObject exists. This must be done prior to enabling it because it can be destroyed
|
|
/// "accidentally" if its parent is destroyed while it is detached.
|
|
/// </summary>
|
|
private void ValidateReticule(NetworkObject targetObject)
|
|
{
|
|
if (m_TargetReticule == null)
|
|
{
|
|
m_TargetReticule = Object.Instantiate(m_Parent.TargetReticulePrefab);
|
|
}
|
|
|
|
bool target_isnpc = targetObject.GetComponent<ITargetable>().IsNpc;
|
|
bool myself_isnpc = m_ParentState.CharacterClass.IsNpc;
|
|
bool hostile = target_isnpc != myself_isnpc;
|
|
|
|
m_TargetReticule.GetComponent<MeshRenderer>().material = hostile ? m_Parent.ReticuleHostileMat : m_Parent.ReticuleFriendlyMat;
|
|
}
|
|
|
|
|
|
public override void Cancel()
|
|
{
|
|
GameObject.Destroy(m_TargetReticule);
|
|
|
|
m_ParentState.TargetId.OnValueChanged -= OnTargetChanged;
|
|
if (m_ParentState.TryGetComponent(out Client.ClientInputSender inputSender))
|
|
{
|
|
inputSender.ActionInputEvent -= OnActionInput;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|