浏览代码

first pass at getting ActionVisualizer in and hooked up

/main
David Woodruff 4 年前
当前提交
22eeb1a7
共有 22 个文件被更改,包括 452 次插入99 次删除
  1. 25
      Assets/BossRoom/Models/BossSetController.controller
  2. 27
      Assets/BossRoom/Models/CharacterSet.fbx.meta
  3. 29
      Assets/BossRoom/Models/CharacterSetController.controller
  4. 65
      Assets/BossRoom/Scripts/Client/ClientCharacterVisualization.cs
  5. 17
      Assets/BossRoom/Scripts/Server/Game/Action/Action.cs
  6. 3
      Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs
  7. 2
      Assets/BossRoom/Scripts/Server/Game/Action/ChaseAction.cs
  8. 25
      Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs
  9. 11
      Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs
  10. 12
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionRequestData.cs
  11. 8
      Assets/BossRoom/Scripts/Client/Game/Action.meta
  12. 44
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionBase.cs
  13. 11
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionBase.cs.meta
  14. 42
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionUtils.cs
  15. 11
      Assets/BossRoom/Scripts/Shared/Game/Action/ActionUtils.cs.meta
  16. 55
      Assets/BossRoom/Scripts/Client/Game/Action/ActionFX.cs
  17. 11
      Assets/BossRoom/Scripts/Client/Game/Action/ActionFX.cs.meta
  18. 60
      Assets/BossRoom/Scripts/Client/Game/Action/ActionVisualization.cs
  19. 11
      Assets/BossRoom/Scripts/Client/Game/Action/ActionVisualization.cs.meta
  20. 71
      Assets/BossRoom/Scripts/Client/Game/Action/MeleeActionFX.cs
  21. 11
      Assets/BossRoom/Scripts/Client/Game/Action/MeleeActionFX.cs.meta

25
Assets/BossRoom/Models/BossSetController.controller


m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 6
m_ConditionEvent: AttackID
m_EventTreshold: 1
m_ConditionEvent: BeginAttack
m_ConditionEvent: Attack1
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 6299315480180736668}

serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionDuration: 0
m_ExitTime: 0.75
m_ExitTime: 0.0000000010521221
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0

m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_Controller: {fileID: 9100000}
- m_Name: AttackID
m_Type: 3
m_Controller: {fileID: 0}
- m_Name: Attack1
m_Type: 9
m_Controller: {fileID: 9100000}
- m_Name: BeginAttack
m_Controller: {fileID: 0}
- m_Name: HitReact1
m_Controller: {fileID: 9100000}
m_Controller: {fileID: 0}
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base Layer

m_Position: {x: 240, y: 90, z: 0}
- serializedVersion: 1
m_State: {fileID: 6299315480180736668}
m_Position: {x: 40, y: 220, z: 0}
m_Position: {x: 240, y: 260, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []

27
Assets/BossRoom/Models/CharacterSet.fbx.meta


mirror: 0
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events: []
events:
- time: 0.40376437
functionName: OnAnimEvent
data: impact
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
transformMask: []
maskType: 3
maskSource: {instanceID: 0}

mirror: 0
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events: []
events:
- time: 0.53248686
functionName: OnAnimEvent
data: impact
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
transformMask: []
maskType: 3
maskSource: {instanceID: 0}

mirror: 0
bodyMask: 01000000010000000100000001000000010000000100000001000000010000000100000001000000010000000100000001000000
curves: []
events: []
events:
- time: 0.40753868
functionName: OnAnimEvent
data: impact
objectReferenceParameter: {instanceID: 0}
floatParameter: 0
intParameter: 0
messageOptions: 0
transformMask: []
maskType: 3
maskSource: {instanceID: 0}

29
Assets/BossRoom/Models/CharacterSetController.controller


m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: HitReact
m_Name: HitReact1
m_Speed: 1
m_CycleOffset: 0
m_Transitions:

m_Name:
m_Conditions:
- m_ConditionMode: 1
m_ConditionEvent: BeginHitReact
m_ConditionEvent: HitReact1
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: -7345246596832709857}

m_TransitionDuration: 0
m_TransitionOffset: 0
m_ExitTime: 2.5632382e-10
m_HasExitTime: 1
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0
m_OrderedInterruption: 1

m_PrefabAsset: {fileID: 0}
m_Name:
m_Conditions:
- m_ConditionMode: 6
m_ConditionEvent: AttackID
m_EventTreshold: 1
m_ConditionEvent: BeginAttack
m_ConditionEvent: Attack1
m_EventTreshold: 0
m_DstStateMachine: {fileID: 0}
m_DstState: {fileID: 6299315480180736668}

serializedVersion: 3
m_TransitionDuration: 0.25
m_TransitionDuration: 0.0000000037252903
m_ExitTime: 0.75
m_ExitTime: 0.016478343
m_HasExitTime: 0
m_HasFixedDuration: 1
m_InterruptionSource: 0

m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
- m_Name: AttackID
m_Type: 3
m_DefaultFloat: 0
m_DefaultInt: 0
m_DefaultBool: 0
m_Controller: {fileID: 0}
- m_Name: BeginAttack
- m_Name: Attack1
- m_Name: BeginHitReact
- m_Name: HitReact1
m_Type: 9
m_DefaultFloat: 0
m_DefaultInt: 0

m_Position: {x: 280, y: 70, z: 0}
- serializedVersion: 1
m_State: {fileID: -7345246596832709857}
m_Position: {x: 290, y: -30, z: 0}
m_Position: {x: 280, y: -30, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []

m_Position: {x: 240, y: 90, z: 0}
- serializedVersion: 1
m_State: {fileID: 6299315480180736668}
m_Position: {x: 250, y: 240, z: 0}
m_Position: {x: 240, y: 240, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []

65
Assets/BossRoom/Scripts/Client/ClientCharacterVisualization.cs


public Animator OurAnimator { get { return m_ClientVisualsAnimator; } }
private ActionVisualization m_ActionViz;
private Transform m_Parent;
public Transform Parent { get; private set; }
public float MinZoomDistance = 3;
public float MaxZoomDistance = 30;

private const float x_MaxRotSpeed = 280; //max angular speed at which we will rotate, in degrees/second.
private const float x_MaxRotSpeed = 280; //max angular speed at which we will rotate, in degrees/second.
public void Start()
{
m_ActionViz = new ActionVisualization(this);
}
/// <inheritdoc />
public override void NetworkStart()

m_NetState.DoActionEventClient += this.PerformActionFX;
//we want to follow our parent on a spring, which means it can't be directly in the transform hierarchy.
m_Parent = transform.parent;
m_Parent.GetComponent<BossRoom.Client.ClientCharacter>().ChildVizObject = this;
Parent = transform.parent;
Parent.GetComponent<BossRoom.Client.ClientCharacter>().ChildVizObject = this;
transform.parent = null;
if (IsLocalPlayer)

{
//TODO: [GOMPS-13] break this method out into its own class, so we can drive multi-frame graphical effects.
//FIXME: [GOMPS-13] hook this up to information in the ActionDescription.
m_ClientVisualsAnimator.SetInteger("AttackID", 1);
m_ClientVisualsAnimator.SetTrigger("BeginAttack");
//m_ClientVisualsAnimator.SetInteger("AttackID", 1);
//m_ClientVisualsAnimator.SetTrigger("BeginAttack");
//if (data.TargetIds != null && data.TargetIds.Length > 0)
//{
// NetworkedObject targetObject = MLAPI.Spawning.SpawnManager.SpawnedObjects[data.TargetIds[0]];
// if (targetObject != null)
// {
// var targetAnimator = targetObject.GetComponent<BossRoom.Client.ClientCharacter>().ChildVizObject.OurAnimator;
// if (targetAnimator != null)
// {
// targetAnimator.SetTrigger("BeginHitReact");
// }
// }
//}
if (data.TargetIds != null && data.TargetIds.Length > 0)
{
NetworkedObject targetObject = MLAPI.Spawning.SpawnManager.SpawnedObjects[data.TargetIds[0]];
if (targetObject != null)
{
var targetAnimator = targetObject.GetComponent<BossRoom.Client.ClientCharacter>().ChildVizObject.OurAnimator;
if (targetAnimator != null)
{
targetAnimator.SetTrigger("BeginHitReact");
}
}
}
m_ActionViz.PlayAction(ref data);
if (m_Parent == null)
if (Parent == null)
{
//since we aren't in the transform hierarchy, we have to explicitly die when our parent dies.
GameObject.Destroy(this.gameObject);

m_ClientVisualsAnimator.SetFloat("Speed", m_NetState.NetworkMovementSpeed.Value);
}
m_ActionViz.Update();
float scroll = Input.GetAxis("Mouse ScrollWheel");
if (scroll != 0 && m_MainCamera)
{

}
public void OnAnimEvent(string id)
{
//if you are trying to figure out who calls this method, it's "magic". The Unity Animation Event system takes method names as strings,
//and calls a method of the same name on a component on the same GameObject as the Animator. See the "attack1" Animation Clip as one
//example of where this is configured.
m_ActionViz.OnAnimEvent(id);
}
var posDiff = m_Parent.transform.position - transform.position;
var angleDiff = Quaternion.Angle(m_Parent.transform.rotation, transform.rotation);
var posDiff = Parent.transform.position - transform.position;
var angleDiff = Quaternion.Angle(Parent.transform.rotation, transform.rotation);
float timeDelta = Time.deltaTime;

float maxAngleMove = timeDelta * x_MaxRotSpeed;
float angleMove = Mathf.Min(maxAngleMove, angleDiff);
float t = angleMove / angleDiff;
transform.rotation = Quaternion.Slerp(transform.rotation, m_Parent.transform.rotation, t);
transform.rotation = Quaternion.Slerp(transform.rotation, Parent.transform.rotation, t);
}
}

17
Assets/BossRoom/Scripts/Server/Game/Action/Action.cs


{
protected ServerCharacter m_Parent;
/// <summary>
/// The level this action plays back at. e.g. a weak "level 0" melee attack, vs a strong "level 3" melee attack.
/// </summary>
protected int m_Level;
protected ActionRequestData m_Data;
/// <summary>

get
{
var list = ActionData.ActionDescriptions[Data.ActionTypeEnum];
int level = Mathf.Min(m_Level, list.Count - 1); //if we don't go up to the requested level, just cap at the max level.
int level = Mathf.Min(Data.Level, list.Count - 1); //if we don't go up to the requested level, just cap at the max level.
return list[level];
}
}

/// </summary>
public Action(ServerCharacter parent, ref ActionRequestData data, int level)
public Action(ServerCharacter parent, ref ActionRequestData data )
m_Level = level;
m_Data.Level = level;
}
/// <summary>

/// <param name="data">the data to instantiate this skill from. </param>
/// <param name="level">the level to play the skill at. </param>
/// <returns>the newly created action. </returns>
public static Action MakeAction(ServerCharacter parent, ref ActionRequestData data, int level )
public static Action MakeAction(ServerCharacter parent, ref ActionRequestData data )
case ActionLogic.MELEE: return new MeleeAction(parent, ref data, level);
case ActionLogic.CHASE: return new ChaseAction(parent, ref data, level);
case ActionLogic.MELEE: return new MeleeAction(parent, ref data );
case ActionLogic.CHASE: return new ChaseAction(parent, ref data );
default: throw new System.NotImplementedException();
}
}

3
Assets/BossRoom/Scripts/Server/Game/Action/ActionPlayer.cs


ClearActions();
}
int level = 0; //todo, get this from parent's networked vars, maybe.
var new_action = Action.MakeAction(m_parent, ref data, level);
var new_action = Action.MakeAction(m_parent, ref data);
bool was_empty = m_queue.Count == 0;
m_queue.Add(new_action);

2
Assets/BossRoom/Scripts/Server/Game/Action/ChaseAction.cs


private Vector3 m_CurrentTargetPos;
public ChaseAction(ServerCharacter parent, ref ActionRequestData data, int level) : base(parent, ref data, level)
public ChaseAction(ServerCharacter parent, ref ActionRequestData data) : base(parent, ref data)
{
}

25
Assets/BossRoom/Scripts/Server/Game/Action/MeleeAction.cs


public class MeleeAction : Action
{
private bool m_ExecFired;
//cache Physics Cast hits, to minimize allocs.
private static RaycastHit[] s_Hits;
private const int k_MaxDetects = 4;
public MeleeAction(ServerCharacter parent, ref ActionRequestData data, int level) : base(parent, ref data, level)
public MeleeAction(ServerCharacter parent, ref ActionRequestData data) : base(parent, ref data)
if (s_Hits == null)
{
s_Hits = new RaycastHit[k_MaxDetects];
}
}
public override bool Start()

/// <returns></returns>
private ServerCharacter DetectFoe(ulong foeHint = 0)
{
//this simple detect just does a boxcast out from our position in the direction we're facing, out to the range of the attack.
var myBounds = this.m_Parent.GetComponent<Collider>().bounds;
//this simple detect just does a boxcast out from our position in the direction we're facing, out to the range of the attack.
//NPCs (monsters) can hit PCs, and vice versa. No friendly fire allowed on either side.
int mask = LayerMask.GetMask(m_Parent.IsNPC ? "PCs" : "NPCs");
int numResults = Physics.BoxCastNonAlloc(m_Parent.transform.position, myBounds.extents,
m_Parent.transform.forward, s_Hits, Quaternion.identity, Description.Range, mask);
RaycastHit[] results;
int numResults = ActionUtils.DetectMeleeFoe(m_Parent.IsNPC, m_Parent.GetComponent<Collider>(), Description, out results);
ServerCharacter foundFoe = s_Hits[0].collider.GetComponent<ServerCharacter>();
ServerCharacter foundFoe = results[0].collider.GetComponent<ServerCharacter>();
var serverChar = s_Hits[i].collider.GetComponent<ServerCharacter>();
var serverChar = results[i].collider.GetComponent<ServerCharacter>();
if (serverChar.NetworkId == foeHint)
{
foundFoe = serverChar;

11
Assets/BossRoom/Scripts/Server/Game/Character/ServerCharacter.cs


[Tooltip("If IsNPC, this is how far the npc can detect others (in meters)")]
public float DetectRange = 10;
[SerializeField]
[Tooltip("If set to false, an NPC character will be denied its brain (won't attack or chase players)")]
private bool BrainEnabled = true;
private ActionPlayer m_actionPlayer;
private AIBrain m_aiBrain;

/// <param name="data">Contains all data necessary to create the action</param>
public void PlayAction(ref ActionRequestData data )
{
if( !IsNPC )
{
//Can't trust the client! If this was a human request, make sure the Level of the skill being played is correct.
data.Level = 0;
}
this.m_actionPlayer.PlayAction(ref data);
}

void Update()
{
m_actionPlayer.Update();
if (m_aiBrain != null)
if (m_aiBrain != null && BrainEnabled )
{
m_aiBrain.Update();
}

12
Assets/BossRoom/Scripts/Shared/Game/Action/ActionRequestData.cs


{
{ ActionType.TANK_BASEATTACK , new List<ActionDescription>
{
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=10, ManaCost=2, ExecTime_s=0.3f, Duration_s=0.5f, Range=2f, Anim="Todo" } }, //level 1
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=15, ManaCost=2, ExecTime_s=0.3f, Duration_s=0.5f, Range=2f, Anim="Todo" } }, //level 2
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=20, ManaCost=2, ExecTime_s=0.3f, Duration_s=0.5f, Range=2f, Anim="Todo" } }, //level 3
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=10, ManaCost=2, ExecTime_s=0.3f, Duration_s=1.2f, Range=2f, Anim="Attack1" } }, //level 1
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=15, ManaCost=2, ExecTime_s=0.3f, Duration_s=1.2f, Range=2f, Anim="Attack1" } }, //level 2
{new ActionDescription{Logic=ActionLogic.MELEE, Amount=20, ManaCost=2, ExecTime_s=0.3f, Duration_s=1.2f, Range=2f, Anim="Attack1" } }, //level 3
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=7, ManaCost=2, Duration_s=0.5f, Range=12f, Anim="Todo" } }, //Level 1
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=12, ManaCost=2, Duration_s=0.5f, Range=15f, Anim="Todo" } }, //Level 2
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=15, ManaCost=2, Duration_s=0.5f, Range=18f, Anim="Todo" } }, //Level 3
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=7, ManaCost=2, Duration_s=0.5f, Range=12f, Anim="Attack1" } }, //Level 1
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=12, ManaCost=2, Duration_s=0.5f, Range=15f, Anim="Attack1" } }, //Level 2
{new ActionDescription{Logic=ActionLogic.RANGED, Amount=15, ManaCost=2, Duration_s=0.5f, Range=18f, Anim="Attack1" } }, //Level 3
}
},

8
Assets/BossRoom/Scripts/Client/Game/Action.meta


fileFormatVersion: 2
guid: 469848a43d22a88499451600cee68f03
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

44
Assets/BossRoom/Scripts/Shared/Game/Action/ActionBase.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom
{
/// <summary>
/// Abstract base class containing some common members shared by Action (server) and ActionFX (client visual)
/// </summary>
public abstract class ActionBase
{
protected ActionRequestData m_Data;
/// <summary>
/// Time when this Action was started (from Time.time) in seconds. Set by the ActionPlayer or ActionVisualization.
/// </summary>
public float TimeStarted { get; set; }
/// <summary>
/// RequestData we were instantiated with. Value should be treated as readonly.
/// </summary>
public ref ActionRequestData Data { get { return ref m_Data; } }
/// <summary>
/// Data Description for this action.
/// </summary>
public ActionDescription Description
{
get
{
var list = ActionData.ActionDescriptions[Data.ActionTypeEnum];
int level = Mathf.Min(Data.Level, list.Count - 1); //if we don't go up to the requested level, just cap at the max level.
return list[level];
}
}
public ActionBase(ref ActionRequestData data )
{
m_Data = data;
}
}
}

11
Assets/BossRoom/Scripts/Shared/Game/Action/ActionBase.cs.meta


fileFormatVersion: 2
guid: 5b435f2cb67bfbd4da38c5a06e04a432
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

42
Assets/BossRoom/Scripts/Shared/Game/Action/ActionUtils.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom
{
public static class ActionUtils
{
//cache Physics Cast hits, to minimize allocs.
private static RaycastHit[] s_Hits = new RaycastHit[4];
/// <summary>
/// Does a melee foe hit detect.
/// </summary>
/// <param name="isNPC">true if the attacker is an NPC (and therefore should hit PCs). False for the reverse.</param>
/// <param name="attacker">The collider of the attacking GameObject.</param>
/// <param name="description">The Description of the Action being played (containing things like Range that control the physics query.</param>
/// <param name="results">Place an uninitialized RayCastHit[] ref in here. It will be set to the results array. </param>
/// <remarks>
/// This method does not alloc. It returns a maximum of 4 results. Consume the results immediately, as the array will be overwritten with
/// the next similar query.
/// </remarks>
/// <returns>Total number of foes encountered. </returns>
public static int DetectMeleeFoe(bool isNPC, Collider attacker, ActionDescription description, out RaycastHit[] results )
{
//this simple detect just does a boxcast out from our position in the direction we're facing, out to the range of the attack.
var myBounds = attacker.bounds;
//NPCs (monsters) can hit PCs, and vice versa. No friendly fire allowed on either side.
int mask = LayerMask.GetMask(isNPC ? "PCs" : "NPCs");
int numResults = Physics.BoxCastNonAlloc( attacker.transform.position, myBounds.extents,
attacker.transform.forward, s_Hits, Quaternion.identity, description.Range, mask);
results = s_Hits;
return numResults;
}
}
}

11
Assets/BossRoom/Scripts/Shared/Game/Action/ActionUtils.cs.meta


fileFormatVersion: 2
guid: da8e533df9f2e3d4f9498ba76434ff4b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

55
Assets/BossRoom/Scripts/Client/Game/Action/ActionFX.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom.Visual
{
/// <summary>
/// Abstract base class for playing back the visual feedback of an Action.
/// </summary>
public abstract class ActionFX : ActionBase
{
protected ClientCharacterVisualization m_Parent;
public ActionFX(ref ActionRequestData data, ClientCharacterVisualization parent) : base(ref data)
{
m_Parent = parent;
}
public ActionLogic Logic
{
get
{
return ActionData.ActionDescriptions[Data.ActionTypeEnum][0].Logic;
}
}
public abstract void Start();
public abstract bool Update();
public virtual void End()
{
Cancel();
}
protected virtual void Cancel() { }
public static ActionFX MakeActionFX(ref ActionRequestData data, ClientCharacterVisualization parent)
{
ActionLogic logic = ActionData.ActionDescriptions[data.ActionTypeEnum][0].Logic;
switch (logic)
{
case ActionLogic.MELEE: return new MeleeActionFX(ref data, parent);
default: throw new System.NotImplementedException();
}
}
public virtual void OnAnimEvent(string id) { }
}
}

11
Assets/BossRoom/Scripts/Client/Game/Action/ActionFX.cs.meta


fileFormatVersion: 2
guid: bd5022fe94e2de7418ca7b00cb3431b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

60
Assets/BossRoom/Scripts/Client/Game/Action/ActionVisualization.cs


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace BossRoom.Visual
{
/// <summary>
/// This is a companion class to ClientCharacterVisualization that is specifically responsible for visualizing Actions. Action visualizations have lifetimes
/// and ongoing state, making this class closely analogous in spirit to the BossRoom.Server.ActionPlayer class.
/// </summary>
[RequireComponent(typeof(ClientCharacterVisualization))]
public class ActionVisualization
{
private List<ActionFX> m_PlayingActions;
public ClientCharacterVisualization Parent { get; private set; }
public ActionVisualization(ClientCharacterVisualization parent)
{
Parent = parent;
m_PlayingActions = new List<ActionFX>();
}
public void Update()
{
//do a reverse-walk so we can safely remove inside the loop.
for (int i = m_PlayingActions.Count - 1; i >= 0; --i)
{
var action = m_PlayingActions[i];
bool keepGoing = action.Update();
bool expirable = action.Description.Duration_s > 0f; //non-positive value is a sentinel indicating the duration is indefinite.
bool timeExpired = expirable && (Time.time - action.TimeStarted) >= action.Description.Duration_s;
if (!keepGoing || timeExpired)
{
action.End();
m_PlayingActions.RemoveAt(i);
}
}
}
public void OnAnimEvent(string id)
{
Debug.Log("Animation event received: " + id);
foreach (var action in m_PlayingActions)
{
action.OnAnimEvent(id);
}
}
public void PlayAction(ref ActionRequestData data)
{
ActionFX action = ActionFX.MakeActionFX(ref data, Parent);
action.TimeStarted = Time.time;
m_PlayingActions.Add(action);
action.Start();
}
}
}

11
Assets/BossRoom/Scripts/Client/Game/Action/ActionVisualization.cs.meta


fileFormatVersion: 2
guid: ac73f3a9b424550468f04fc5362275b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

71
Assets/BossRoom/Scripts/Client/Game/Action/MeleeActionFX.cs


using MLAPI;
using MLAPI.Spawning;
namespace BossRoom.Visual
{
/// <summary>
/// The visual part of a MeleeAction. See MeleeAction.cs for more about this action type.
/// </summary>
public class MeleeActionFX : ActionFX
{
public MeleeActionFX(ref ActionRequestData data, ClientCharacterVisualization parent) : base(ref data, parent) { }
//have we actually played an impact? This won't necessarily happen for all swings. Sometimes you're just swinging at space.
private bool m_ImpactPlayed;
/// <summary>
/// When we detect if our original target is still around, we use a bit of padding on the range check.
/// </summary>
private float k_RangePadding = 3f;
// Start is called before the first frame update
public override void Start()
{
m_Parent.OurAnimator.SetTrigger(Description.Anim);
}
// Update is called once per frame
public override bool Update()
{
return true;
}
public override void OnAnimEvent(string id)
{
if (id == "impact" && !m_ImpactPlayed)
{
PlayHitReact();
}
}
public override void End()
{
//if this didn't already happen, make sure it gets a chance to run. This could have failed to run because
//our animationclip didn't have the "impact" event properly configured (as one possibility).
PlayHitReact();
}
private void PlayHitReact()
{
if (m_ImpactPlayed) { return; }
m_ImpactPlayed = true;
//Is my original target still in range? Then definitely get him!
if (Data.TargetIds != null && Data.TargetIds.Length > 0 && SpawnManager.SpawnedObjects.ContainsKey(Data.TargetIds[0]))
{
NetworkedObject originalTarget = SpawnManager.SpawnedObjects[Data.TargetIds[0]];
float padRange = Description.Range + k_RangePadding;
if ((m_Parent.transform.position - originalTarget.transform.position).sqrMagnitude < (padRange * padRange))
{
ClientCharacterVisualization targetViz = originalTarget.GetComponent<BossRoom.Client.ClientCharacter>().ChildVizObject;
targetViz.OurAnimator.SetTrigger("HitReact1");
}
}
//in the future we may do another physics check to handle the case where a target "ran under our weapon".
//But for now, if the original target is no longer present, then we just don't play our hit react on anything.
}
}
}

11
Assets/BossRoom/Scripts/Client/Game/Action/MeleeActionFX.cs.meta


fileFormatVersion: 2
guid: 87ac9a12dfd0b47478c2ce8ede685033
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存