Update
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ab59ed1e4731cd4fb487f3cc20a3b40
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.Abilities
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.UltimateCharacterController.Character.Abilities;
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Follows a path specified by the 2.5D movement type. Ensures the character stays at a consistant horizontal offset.
|
||||
/// </summary>
|
||||
[DefaultStartType(AbilityStartType.Manual)]
|
||||
public class FollowPseudo3DPath : Ability
|
||||
{
|
||||
public override bool IsConcurrent { get { return true; } }
|
||||
|
||||
private MovementTypes.Pseudo3D m_Pseudo3DMovementType;
|
||||
private int m_PathIndex;
|
||||
private float m_Offset;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
EventHandler.RegisterEvent<MovementType, bool>(m_GameObject, "OnCharacterChangeMovementType", OnCharacterChangeMovementType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The specified movement type has been activated or deactivated.
|
||||
/// </summary>
|
||||
/// <param name="movementType">The movement type that has been activated or deactivated.</param>
|
||||
/// <param name="active">Is the movement type active?</param>
|
||||
private void OnCharacterChangeMovementType(MovementType movementType, bool active)
|
||||
{
|
||||
if (!(movementType is MovementTypes.Pseudo3D)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsActive && active) {
|
||||
// If the movement type is active then the ability should start if a path exists.
|
||||
var pseudo3DMovementType = movementType as MovementTypes.Pseudo3D;
|
||||
if (pseudo3DMovementType.Path != null) {
|
||||
StartAbility();
|
||||
return;
|
||||
}
|
||||
} else if (IsActive && !active) {
|
||||
// If the movement type is no longer active then the ability should stop.
|
||||
StopAbility();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the ablity is tried to be started. If false is returned then the ability will not be started.
|
||||
/// </summary>
|
||||
/// <returns>True if the ability can be started.</returns>
|
||||
public override bool CanStartAbility()
|
||||
{
|
||||
if (!base.CanStartAbility()) {
|
||||
return false;
|
||||
}
|
||||
return (m_CharacterLocomotion.ActiveMovementType is MovementTypes.Pseudo3D) && (m_CharacterLocomotion.ActiveMovementType as MovementTypes.Pseudo3D).Path != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The ability has started.
|
||||
/// </summary>
|
||||
protected override void AbilityStarted()
|
||||
{
|
||||
base.AbilityStarted();
|
||||
|
||||
m_Pseudo3DMovementType = m_CharacterLocomotion.ActiveMovementType as MovementTypes.Pseudo3D;
|
||||
|
||||
// Store the horizontal offset between the character and the path. This offset will ensure the character stays at a constant horizontal position.
|
||||
var pathRotation = Quaternion.LookRotation(m_Pseudo3DMovementType.Path.GetTangent(m_Transform.position, ref m_PathIndex));
|
||||
var closestPoint = m_Pseudo3DMovementType.Path.GetClosestPoint(m_Transform.position, ref m_PathIndex);
|
||||
m_Offset = MathUtility.InverseTransformPoint(m_Transform.position, pathRotation, closestPoint).x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stop the ability if the path no longer exists.
|
||||
/// </summary>
|
||||
public override void Update()
|
||||
{
|
||||
if (m_Pseudo3DMovementType.Path == null) {
|
||||
StopAbility();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the controller's position values.
|
||||
/// </summary>
|
||||
public override void UpdatePosition()
|
||||
{
|
||||
// Retireve the closest point and tangent of the path at the target position. This position will be used when determining if the character needs to change
|
||||
// horizontal offsets.
|
||||
var targetPosition = m_Transform.position + m_CharacterLocomotion.MoveDirection;
|
||||
var closestPoint = m_Pseudo3DMovementType.Path.GetClosestPoint(targetPosition, ref m_PathIndex);
|
||||
var pathRotation = Quaternion.LookRotation(m_Pseudo3DMovementType.Path.GetTangent(targetPosition, ref m_PathIndex));
|
||||
|
||||
// Update the offset if the character can move along the relative x axis. The depth term is used in relation to the camera's depth axis.
|
||||
if (m_Pseudo3DMovementType.AllowDepthMovement && m_CharacterLocomotion.RawInputVector.y != 0) {
|
||||
m_Offset -= MathUtility.InverseTransformDirection(m_CharacterLocomotion.MotorThrottle, pathRotation).x;
|
||||
}
|
||||
|
||||
// Update the target position based on the difference between the current offset and the stored offset.
|
||||
var offset = MathUtility.InverseTransformPoint(targetPosition, pathRotation, closestPoint).x;
|
||||
targetPosition = MathUtility.TransformPoint(targetPosition, pathRotation, Vector3.right * (offset - m_Offset));
|
||||
m_CharacterLocomotion.MoveDirection = targetPosition - m_Transform.position;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character has been destroyed.
|
||||
/// </summary>
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
EventHandler.UnregisterEvent<MovementType, bool>(m_GameObject, "OnCharacterChangeMovementType", OnCharacterChangeMovementType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f2b3cd302b28cf54ebb3823309cb9bbf
|
||||
timeCreated: 1528491971
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a98f71974871654fab0879a6e52b779
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.Abilities.Items
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Character.Abilities;
|
||||
using Opsive.UltimateCharacterController.Character.Abilities.Items;
|
||||
using Opsive.UltimateCharacterController.Game;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Pulls back the item if the character gets too close to a wall. This will prevent the item from clipping with the wall.
|
||||
/// </summary>
|
||||
[DefaultStopType(AbilityStopType.Automatic)]
|
||||
public class ItemPullback : ItemAbility
|
||||
{
|
||||
[Tooltip("The collider used to detect when the character is near an object and should pull back the items.")]
|
||||
[SerializeField] protected Collider m_Collider;
|
||||
[Tooltip("The layers that the collider can collide with.")]
|
||||
[SerializeField] protected LayerMask m_CollisionLayers = ~(1 << LayerManager.IgnoreRaycast | 1 << LayerManager.TransparentFX | 1 << LayerManager.SubCharacter |
|
||||
1 << LayerManager.Overlay | 1 << LayerManager.VisualEffect | 1 << LayerManager.Water);
|
||||
[Tooltip("The maximum number of collisions that should be detected by the collider.")]
|
||||
[SerializeField] protected int m_MaxCollisionCount = 5;
|
||||
|
||||
public Collider Collider { get { return m_Collider; } set { m_Collider = value; } }
|
||||
public LayerMask CollisionLayers { get { return m_CollisionLayers; } set { m_CollisionLayers = value; } }
|
||||
|
||||
private Transform m_ColliderTransform;
|
||||
private Collider[] m_HitColliders;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
if (m_Collider == null || (!(m_Collider is CapsuleCollider) && !(m_Collider is SphereCollider))) {
|
||||
Debug.LogError("Error: Only Capsule and Sphere Colliders are supported by the Item Pullback ability.");
|
||||
m_Collider = null;
|
||||
Enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_HitColliders = new Collider[m_MaxCollisionCount];
|
||||
m_ColliderTransform = m_Collider.transform;
|
||||
m_Collider.gameObject.SetActive(false);
|
||||
|
||||
EventHandler.RegisterEvent<bool>(m_GameObject, "OnCameraWillChangePerspectives", OnChangePerspectives);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the ablity is tried to be started. If false is returned then the ability will not be started.
|
||||
/// </summary>
|
||||
/// <returns>True if the ability can be started.</returns>
|
||||
public override bool CanStartAbility()
|
||||
{
|
||||
return HasCollision();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is there a collision between the item pullback collider and another object?
|
||||
/// </summary>
|
||||
/// <returns>True if there is a collision with the item pullback collider.</returns>
|
||||
private bool HasCollision()
|
||||
{
|
||||
int hitCount;
|
||||
if (m_Collider is CapsuleCollider) {
|
||||
var capsuleCollider = m_Collider as CapsuleCollider;
|
||||
if (capsuleCollider.radius == 0) {
|
||||
return false;
|
||||
}
|
||||
Vector3 startEndCap, endEndCap;
|
||||
MathUtility.CapsuleColliderEndCaps(capsuleCollider, m_ColliderTransform.position, m_ColliderTransform.rotation, out startEndCap, out endEndCap);
|
||||
hitCount = Physics.OverlapCapsuleNonAlloc(startEndCap, endEndCap, capsuleCollider.radius * MathUtility.ColliderRadiusMultiplier(capsuleCollider), m_HitColliders, m_CollisionLayers, QueryTriggerInteraction.Ignore);
|
||||
} else { // SphereCollider.
|
||||
var sphereCollider = m_Collider as SphereCollider;
|
||||
if (sphereCollider.radius == 0) {
|
||||
return false;
|
||||
}
|
||||
hitCount = Physics.OverlapSphereNonAlloc(m_ColliderTransform.position, sphereCollider.radius * MathUtility.ColliderRadiusMultiplier(sphereCollider), m_HitColliders, m_CollisionLayers, QueryTriggerInteraction.Ignore);
|
||||
}
|
||||
|
||||
for (int i = 0; i < hitCount; ++i) {
|
||||
// Objects which are children of the character aren't considered a collision.
|
||||
if (m_HitColliders[i].transform.IsChildOf(m_Transform)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Projectiles shouldn't prevent the pullback ability.
|
||||
if (m_HitColliders[i].gameObject.GetCachedComponent<Objects.Projectile>() != null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// It only takes one object for the ability to be in a collision state.
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when another ability is attempting to start and the current ability is active.
|
||||
/// Returns true or false depending on if the new ability should be blocked from starting.
|
||||
/// </summary>
|
||||
/// <param name="startingAbility">The ability that is starting.</param>
|
||||
/// <returns>True if the ability should be blocked.</returns>
|
||||
public override bool ShouldBlockAbilityStart(Ability startingAbility)
|
||||
{
|
||||
return CanStopAbility(startingAbility);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when the current ability is attempting to start and another ability is active.
|
||||
/// Returns true or false depending on if the active ability should be stopped.
|
||||
/// </summary>
|
||||
/// <param name="activeAbility">The ability that is currently active.</param>
|
||||
/// <returns>True if the ability should be stopped.</returns>
|
||||
public override bool ShouldStopActiveAbility(Ability activeAbility)
|
||||
{
|
||||
return CanStopAbility(activeAbility);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the Item Pullback ability stop the specified ability?
|
||||
/// </summary>
|
||||
/// <param name="ability">The ability that may be able to be stopped.</param>
|
||||
/// <returns>True if the ability can be stopped.</returns>
|
||||
private bool CanStopAbility(Ability ability)
|
||||
{
|
||||
#if ULTIMATE_CHARACTER_CONTROLLER_SHOOTER
|
||||
if (ability is Use) {
|
||||
var useAbility = ability as Use;
|
||||
return useAbility.UsesItemActionType(typeof(UltimateCharacterController.Items.Actions.ShootableWeapon));
|
||||
}
|
||||
if (ability is Reload) {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the ability be stopped?
|
||||
/// </summary>
|
||||
/// <returns>True if the ability can be stopped.</returns>
|
||||
public override bool CanStopAbility()
|
||||
{
|
||||
return !HasCollision();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character perspective between first and third person has changed.
|
||||
/// </summary>
|
||||
/// <param name="firstPersonPerspective">Is the character in a first person perspective?</param>
|
||||
private void OnChangePerspectives(bool firstPersonPerspective)
|
||||
{
|
||||
// Item Pullback does not work in first person mode.
|
||||
Enabled = !firstPersonPerspective;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character has been destroyed.
|
||||
/// </summary>
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
EventHandler.UnregisterEvent<bool>(m_GameObject, "OnCameraWillChangePerspectives", OnChangePerspectives);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 453263f004c12c74e871dd76b4dfa8c4
|
||||
timeCreated: 1522777146
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,68 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.Abilities.Items
|
||||
{
|
||||
using Opsive.UltimateCharacterController.StateSystem;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Allows the ItemPullback collider to be resized/positioned based upon the state.
|
||||
/// </summary>
|
||||
public class ItemPullbackCollider : StateBehavior
|
||||
{
|
||||
[Tooltip("The offset to apply to the transform relative to the starting local position.")]
|
||||
[SerializeField] protected Vector3 m_LocalPositionOffset;
|
||||
[Tooltip("The offset to apply to the radius to the starting radius.")]
|
||||
[SerializeField] protected float m_RadiusOffset;
|
||||
|
||||
public Vector3 LocalPositionOffset { get { return m_LocalPositionOffset; } set { m_LocalPositionOffset = value; } }
|
||||
public float RadiusOffset { get { return m_RadiusOffset; } set { m_RadiusOffset = value; } }
|
||||
|
||||
private Transform m_Transform;
|
||||
private Collider m_Collider;
|
||||
|
||||
private Vector3 m_LocalPosition;
|
||||
private float m_Radius;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
m_Collider = GetComponent<Collider>();
|
||||
if (!(m_Collider is CapsuleCollider) && !(m_Collider is SphereCollider)) {
|
||||
Debug.LogWarning("Warning: The ItemPullbackCollider only supports capsule and sphere colliders.");
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
m_Transform = transform;
|
||||
m_LocalPosition = m_Transform.localPosition;
|
||||
if (m_Collider is CapsuleCollider) {
|
||||
m_Radius = (m_Collider as CapsuleCollider).radius;
|
||||
} else { // SphereCollider
|
||||
m_Radius = (m_Collider as SphereCollider).radius;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback when the StateManager has changed the active state on the current object.
|
||||
/// </summary>
|
||||
public override void StateChange()
|
||||
{
|
||||
m_Transform.localPosition = m_LocalPosition + m_LocalPositionOffset;
|
||||
|
||||
if (m_Collider is CapsuleCollider) {
|
||||
(m_Collider as CapsuleCollider).radius = m_Radius + m_RadiusOffset;
|
||||
} else { // SphereCollider
|
||||
(m_Collider as SphereCollider).radius = m_Radius + m_RadiusOffset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 156bcc35929b82b49bb622963c6def6a
|
||||
timeCreated: 1522787067
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43f20180f83eae546a73c2ef4bcf7a84
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,118 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Character.Abilities.Items;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// With the Adventure movement type the character will always move forward in the movement direction. This is relative to the camera direction and prevents the
|
||||
/// character from playing a strafe or backwards animation.
|
||||
/// </summary>
|
||||
public class Adventure : MovementType
|
||||
{
|
||||
private bool m_AimActive;
|
||||
private int m_FaceUseTargetCount;
|
||||
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
EventHandler.RegisterEvent<bool, bool>(m_GameObject, "OnAimAbilityStart", OnAimStart);
|
||||
EventHandler.RegisterEvent<bool, Use>(m_GameObject, "OnUseAbilityStart", OnUseStart);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Aim ability has started or stopped.
|
||||
/// </summary>
|
||||
/// <param name="start">Has the Aim ability started?</param>
|
||||
/// <param name="inputStart">Was the ability started from input?</param>
|
||||
private void OnAimStart(bool start, bool inputStart)
|
||||
{
|
||||
if (!inputStart) {
|
||||
return;
|
||||
}
|
||||
m_AimActive = start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Use ability has started or stopped using an item.
|
||||
/// </summary>
|
||||
/// <param name="start">Has the Use ability started?</param>
|
||||
/// <param name="useAbility">The Use ability that has started or stopped.</param>
|
||||
private void OnUseStart(bool start, Use useAbility)
|
||||
{
|
||||
if (useAbility.FaceTargetItem != null) {
|
||||
m_FaceUseTargetCount += start ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (characterHorizontalMovement != 0 || characterForwardMovement != 0) {
|
||||
var lookRotation = Quaternion.LookRotation(m_LookSource.Transform.rotation *
|
||||
new Vector3(characterHorizontalMovement, 0, characterForwardMovement).normalized, m_CharacterLocomotion.Up);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, lookRotation).eulerAngles.y);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
// The character will be facing the target while the aim ability is active or the use ability is facing the target. During this time the character should be
|
||||
// able to strafe or move backwards.
|
||||
if (m_AimActive || m_FaceUseTargetCount > 0) {
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
// The Adventure Movement Type only uses the forward input value.
|
||||
// Clamp to a value higher then one if the x or y value is greater then one. This can happen if the character is sprinting.
|
||||
var clampValue = Mathf.Max(Mathf.Abs(inputVector.x), Mathf.Max(Mathf.Abs(inputVector.y), 1));
|
||||
inputVector.y = Mathf.Clamp(inputVector.magnitude, -clampValue, clampValue);
|
||||
inputVector.x = 0;
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject has been destroyed.
|
||||
/// </summary>
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
EventHandler.UnregisterEvent<bool, bool>(m_GameObject, "OnAimAbilityStart", OnAimStart);
|
||||
EventHandler.UnregisterEvent<bool, Use>(m_GameObject, "OnUseAbilityStart", OnUseStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b69f0bb5b55e47d48b4f800ecd868c42
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,52 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// With the Combat movement type the character can strafe and move backwards, and is always facing in the direction of the camera.
|
||||
/// </summary>
|
||||
public class Combat : MovementType
|
||||
{
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
var lookRotation = Quaternion.LookRotation(m_LookSource.LookDirection(true), m_CharacterLocomotion.Up);
|
||||
// Convert to a local character rotation and then only return the relative y rotation.
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, lookRotation).eulerAngles.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
// No changes are necessary.
|
||||
return inputVector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3eed0ebe602b43044a30ae7371109403
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The FourLegged MovementType allows the character to move as if they are on four legs. The character cannot strafe and will rotate when trying to turn.
|
||||
/// </summary>
|
||||
public class FourLegged : MovementType
|
||||
{
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
var localEuler = MathUtility.InverseTransformQuaternion(m_Transform.rotation, Quaternion.LookRotation(m_Transform.forward, m_Transform.up)).eulerAngles;
|
||||
localEuler.y += characterHorizontalMovement * (characterForwardMovement < 0 ? -1 : 1);
|
||||
// If there is no horizontal movement and some forward movement then the character should turn in the direction of the camera.
|
||||
if (characterHorizontalMovement == 0 && characterForwardMovement != 0) {
|
||||
var cameraAngle = MathUtility.InverseTransformQuaternion(m_Transform.rotation, m_LookSource.Transform.rotation).eulerAngles;
|
||||
// The horizontal/forward movement input values will always be in a range between -1 and 1 so keep the camera angle within the same range
|
||||
// so the rotation doesn't move too quickly.
|
||||
localEuler.y += Mathf.Clamp(MathUtility.ClampInnerAngle(cameraAngle.y), -1, 1);
|
||||
}
|
||||
return localEuler.y;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
return inputVector;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: faea5c3719ad489438350ba14709cb6e
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,184 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Input;
|
||||
using Opsive.UltimateCharacterController.Motion;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The Pseudo3D MovementType can move the character relative to a 2.5D camera.
|
||||
/// </summary>
|
||||
public class Pseudo3D : MovementType
|
||||
{
|
||||
[Tooltip("Can the character move along the depth axis (the z axis relative to the camera)?")]
|
||||
[SerializeField] protected bool m_AllowDepthMovement;
|
||||
[Tooltip("Should the character look in the direction of the movement?")]
|
||||
[SerializeField] protected bool m_LookInMoveDirection;
|
||||
[Tooltip("A small buffer used to prevent the character from quickly switching directions when the mouse is near the character's origin.")]
|
||||
[SerializeField] protected float m_LookRotateBuffer = 0.2f;
|
||||
[Tooltip("The path that the character should orient towards. If null then the character will be oriented towards the look source direction.")]
|
||||
[SerializeField] protected Path m_Path;
|
||||
|
||||
public bool AllowDepthMovement { get { return m_AllowDepthMovement; } set { m_AllowDepthMovement = value; } }
|
||||
public bool LookInMoveDirection { get { return m_LookInMoveDirection; } set { m_LookInMoveDirection = value; } }
|
||||
public float LookRotateBuffer { get { return m_LookRotateBuffer; } set { m_LookRotateBuffer = value; } }
|
||||
public Path Path { get { return m_Path; } set { m_Path = value; } }
|
||||
|
||||
private PlayerInput m_PlayerInput;
|
||||
private UnityEngine.Camera m_Camera;
|
||||
private Plane m_HitPlane = new Plane();
|
||||
private int m_PathIndex;
|
||||
private bool m_InitialOrientation = true;
|
||||
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the MovementType.
|
||||
/// </summary>
|
||||
/// <param name="characterLocomotion">The reference to the character locomotion component.</param>
|
||||
public override void Initialize(UltimateCharacterLocomotion characterLocomotion)
|
||||
{
|
||||
base.Initialize(characterLocomotion);
|
||||
|
||||
m_PlayerInput = characterLocomotion.gameObject.GetCachedComponent<PlayerInput>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A new ILookSource object has been attached to the character.
|
||||
/// </summary>
|
||||
/// <param name="lookSource">The ILookSource object attached to the character.</param>
|
||||
protected override void OnAttachLookSource(ILookSource lookSource)
|
||||
{
|
||||
base.OnAttachLookSource(lookSource);
|
||||
|
||||
if (lookSource != null) {
|
||||
m_Camera = lookSource.GameObject.GetCachedComponent<UnityEngine.Camera>();
|
||||
m_InitialOrientation = false;
|
||||
} else {
|
||||
m_Camera = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (m_LookInMoveDirection) {
|
||||
if (characterHorizontalMovement != 0 || (m_AllowDepthMovement ? characterForwardMovement : 0) != 0) {
|
||||
var inputVector = Vector3.zero;
|
||||
inputVector.Set(characterHorizontalMovement, 0, (m_AllowDepthMovement ? characterForwardMovement : 0));
|
||||
Quaternion lookRotation;
|
||||
if (m_Path != null) {
|
||||
lookRotation = Quaternion.LookRotation(Quaternion.LookRotation(Vector3.Cross(m_Path.GetTangent(m_Transform.position, ref m_PathIndex), m_CharacterLocomotion.Up)) * inputVector.normalized);
|
||||
} else {
|
||||
lookRotation = Quaternion.LookRotation(m_LookSource.Transform.rotation * inputVector.normalized);
|
||||
}
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, lookRotation).eulerAngles.y);
|
||||
}
|
||||
} else {
|
||||
// The character should look towards the cursor or Mouse X/Y direction.
|
||||
if (m_PlayerInput.IsCursorVisible()) {
|
||||
var characterCenter = m_Transform.position + (m_CharacterLocomotion.Up * m_CharacterLocomotion.Height / 2);
|
||||
Vector3 forward;
|
||||
if (m_Path != null) {
|
||||
forward = Vector3.Cross(m_Path.GetTangent(m_Transform.position, ref m_PathIndex), m_CharacterLocomotion.Up);
|
||||
} else {
|
||||
forward = m_LookSource.Transform.forward;
|
||||
}
|
||||
var localLookDirection = m_Transform.InverseTransformDirection(forward);
|
||||
// The vertical look direction can be ignored.
|
||||
localLookDirection.y = 0;
|
||||
m_HitPlane.SetNormalAndPosition(m_Transform.TransformDirection(localLookDirection), characterCenter);
|
||||
|
||||
// Cast a ray from the mouse position to an invisible plane to determine the direction that the character should look.
|
||||
float distance;
|
||||
var ray = m_Camera.ScreenPointToRay(m_PlayerInput.GetMousePosition());
|
||||
if (m_HitPlane.Raycast(ray, out distance)) {
|
||||
// Only rotate the character if the mouse is far enough away from the character's origin.
|
||||
var localHitPoint = m_Transform.InverseTransformPoint(ray.GetPoint(distance));
|
||||
localHitPoint.y = 0;
|
||||
if (localHitPoint.magnitude > (m_LookRotateBuffer * Mathf.Max(1, m_CharacterLocomotion.LocomotionVelocity.magnitude)) || m_InitialOrientation) {
|
||||
// The character should only rotate along the local y axis. This can be done by zeroing out the y direction after the character center is subtracted.
|
||||
localHitPoint.y = m_CharacterLocomotion.Height / 2;
|
||||
var rotation = Quaternion.LookRotation((m_Transform.TransformPoint(localHitPoint) - characterCenter).normalized, m_CharacterLocomotion.Up);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, rotation).eulerAngles.y);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the mouse hasn't moved then get the axis to determine a look rotation. This will be used for controllers and virtual input.
|
||||
var direction = Vector3.zero;
|
||||
direction.x = m_PlayerInput.GetAxis(m_PlayerInput.HorizontalLookInputName);
|
||||
direction.z = m_PlayerInput.GetAxis(m_PlayerInput.VerticalLookInputName);
|
||||
if (direction.sqrMagnitude > 0.1f) {
|
||||
var rotation = Quaternion.LookRotation(direction.normalized, m_CharacterLocomotion.Up);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, rotation).eulerAngles.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
var rotation = m_Transform.rotation;
|
||||
// The camera may not exist (in the case of an AI agent) but if it does move relative to the camera position.
|
||||
if (m_LookSource != null) {
|
||||
var localEuler = MathUtility.InverseTransformQuaternion(m_LookSource.Transform.rotation, Quaternion.LookRotation(Vector3.forward, m_CharacterLocomotion.Up)).eulerAngles;
|
||||
localEuler.x = localEuler.z = 0;
|
||||
rotation *= MathUtility.TransformQuaternion(Quaternion.Euler(localEuler), Quaternion.LookRotation(Vector3.forward, m_CharacterLocomotion.Up));
|
||||
}
|
||||
// Convert to a local input vector. Vector3s are required for the correct calculation.
|
||||
var localInputVector = Vector3.zero;
|
||||
localInputVector.Set(inputVector.x, 0, (m_AllowDepthMovement ? inputVector.y : 0));
|
||||
localInputVector = Quaternion.Inverse(rotation) * localInputVector;
|
||||
|
||||
// Store the max input vector value so it can be normalized before being returned.
|
||||
var maxInputVectorValue = Mathf.Max(Mathf.Abs(inputVector.x), Mathf.Abs(inputVector.y));
|
||||
inputVector.x = localInputVector.x;
|
||||
inputVector.y = localInputVector.z;
|
||||
// Normalize the input vector to prevent the diagonals from moving faster.
|
||||
inputVector = inputVector.normalized * maxInputVectorValue;
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the character look independently of the transform rotation?
|
||||
/// </summary>
|
||||
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
|
||||
/// <returns>True if the character should look independently of the transform rotation.</returns>
|
||||
public override bool UseIndependentLook(bool characterLookDirection)
|
||||
{
|
||||
if (base.UseIndependentLook(characterLookDirection)) {
|
||||
return true;
|
||||
}
|
||||
return !characterLookDirection || m_PlayerInput.IsControllerConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 73c649042e866c54bb54d666c7a5dba8
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,222 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.Shared.Utility;
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Input;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The RPG MovementType uses a control scheme similar to the standard in the RPG genre. The MovementType works with the RPG ViewType to move and rotate the character.
|
||||
/// </summary>
|
||||
public class RPG : MovementType
|
||||
{
|
||||
[Tooltip("The name of the rotate input mapping.")]
|
||||
[SerializeField] protected string m_RotateInputName = "Fire3";
|
||||
[Tooltip("The name of the turn input mapping.")]
|
||||
[SerializeField] protected string m_TurnInputName = "Horizontal";
|
||||
[Tooltip("The amount to multiply the turn value by.")]
|
||||
[SerializeField] protected float m_TurnMultiplier = 1.5f;
|
||||
[Tooltip("The name of the auto move input mapping.")]
|
||||
[SerializeField] protected string m_AutoMoveInputName = "Action";
|
||||
|
||||
public string RotateInputName { get { return m_RotateInputName; } set { m_RotateInputName = value; } }
|
||||
public string TurnInputName { get { return m_TurnInputName; } set { m_TurnInputName = value; } }
|
||||
public float TurnMultiplier { get { return m_TurnValue; } set { m_TurnValue = value; } }
|
||||
public string AutoMoveInputName { get { return m_AutoMoveInputName; } set { m_AutoMoveInputName = value; } }
|
||||
|
||||
private UltimateCharacterLocomotionHandler m_Handler;
|
||||
private ActiveInputEvent m_StartRotateInputEvent;
|
||||
private ActiveInputEvent m_StopRotateInputEvent;
|
||||
private ActiveInputEvent m_TurnInputEvent;
|
||||
private ActiveInputEvent m_AutoMoveInputEvent;
|
||||
|
||||
private bool m_Rotate;
|
||||
private float m_TurnValue;
|
||||
private bool m_AutoMove;
|
||||
private bool m_MovementTypeActive;
|
||||
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
public override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
m_Handler = m_GameObject.GetCachedComponent<UltimateCharacterLocomotionHandler>();
|
||||
|
||||
// Work with the handler to listen for any input events.
|
||||
if (m_Handler != null) {
|
||||
m_StartRotateInputEvent = GenericObjectPool.Get<ActiveInputEvent>();
|
||||
m_StartRotateInputEvent.Initialize(ActiveInputEvent.Type.ButtonDown, m_RotateInputName, "OnRPGMovementTypeStartRotate");
|
||||
|
||||
m_StopRotateInputEvent = GenericObjectPool.Get<ActiveInputEvent>();
|
||||
m_StopRotateInputEvent.Initialize(ActiveInputEvent.Type.ButtonUp, m_RotateInputName, "OnRPGMovementTypeStopRotate");
|
||||
|
||||
m_TurnInputEvent = GenericObjectPool.Get<ActiveInputEvent>();
|
||||
m_TurnInputEvent.Initialize(ActiveInputEvent.Type.Axis, m_TurnInputName, "OnRPGMovementTypeTurn");
|
||||
|
||||
m_AutoMoveInputEvent = GenericObjectPool.Get<ActiveInputEvent>();
|
||||
m_AutoMoveInputEvent.Initialize(ActiveInputEvent.Type.ButtonDown, m_AutoMoveInputName, "OnRPGMovementTypeAutoMove");
|
||||
|
||||
m_Handler.RegisterInputEvent(m_StartRotateInputEvent);
|
||||
m_Handler.RegisterInputEvent(m_TurnInputEvent);
|
||||
m_Handler.RegisterInputEvent(m_AutoMoveInputEvent);
|
||||
}
|
||||
EventHandler.RegisterEvent(m_GameObject, "OnRPGMovementTypeStartRotate", OnStartRotate);
|
||||
EventHandler.RegisterEvent(m_GameObject, "OnRPGMovementTypeStopRotate", OnStopRotate);
|
||||
EventHandler.RegisterEvent<float>(m_GameObject, "OnRPGMovementTypeTurn", OnTurn);
|
||||
EventHandler.RegisterEvent(m_GameObject, "OnRPGMovementTypeAutoMove", OnToggleAutoMove);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The movement type has changed.
|
||||
/// </summary>
|
||||
/// <param name="activate">Should the current movement type be activated?</param>
|
||||
public override void ChangeMovementType(bool activate)
|
||||
{
|
||||
m_MovementTypeActive = activate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts rotating the character along the relative y axis.
|
||||
/// </summary>
|
||||
private void OnStartRotate()
|
||||
{
|
||||
m_Rotate = true;
|
||||
|
||||
// The handler only needs to listen to the start input event once.
|
||||
if (m_Handler != null) {
|
||||
m_Handler.UnregisterInputEvent(m_StartRotateInputEvent);
|
||||
m_Handler.RegisterInputEvent(m_StopRotateInputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stops rotating the character along the relative y axis.
|
||||
/// </summary>
|
||||
private void OnStopRotate()
|
||||
{
|
||||
m_Rotate = false;
|
||||
|
||||
// The handler only needs to listen to the stop input event once.
|
||||
if (m_Handler != null) {
|
||||
m_Handler.UnregisterInputEvent(m_StopRotateInputEvent);
|
||||
m_Handler.RegisterInputEvent(m_StartRotateInputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character axis has turned.
|
||||
/// </summary>
|
||||
/// <param name="turnValue">The value of the turn axis.</param>
|
||||
private void OnTurn(float turnValue)
|
||||
{
|
||||
m_TurnValue = turnValue * m_TurnMultiplier;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Toggles the character from automatically moving in the forward direction.
|
||||
/// </summary>
|
||||
private void OnToggleAutoMove()
|
||||
{
|
||||
if (!m_MovementTypeActive) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_AutoMove = !m_AutoMove;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
var turnAmount = m_TurnValue;
|
||||
if (m_Rotate) {
|
||||
turnAmount += MathUtility.InverseTransformQuaternion(m_Transform.rotation, m_LookSource.Transform.rotation).eulerAngles.y;
|
||||
}
|
||||
var rotation = Quaternion.AngleAxis(turnAmount, m_CharacterLocomotion.Up) * m_Transform.rotation;
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, rotation).eulerAngles.y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
// AutoMove will automatically move the character in the forward direction.
|
||||
if (m_AutoMove) {
|
||||
inputVector.y = 1;
|
||||
|
||||
// The raw input should also be updated so the movement abilities can correctly track the auto move.
|
||||
var rawInputVector = m_CharacterLocomotion.RawInputVector;
|
||||
rawInputVector.y = 1;
|
||||
m_CharacterLocomotion.RawInputVector = rawInputVector;
|
||||
}
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the character look independently of the transform rotation?
|
||||
/// </summary>
|
||||
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
|
||||
/// <returns>True if the character should look independently of the transform rotation.</returns>
|
||||
public override bool UseIndependentLook(bool characterLookDirection)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject has been destroyed.
|
||||
/// </summary>
|
||||
public override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
|
||||
if (m_Handler != null) {
|
||||
if (m_Rotate) {
|
||||
m_Handler.UnregisterInputEvent(m_StopRotateInputEvent);
|
||||
} else {
|
||||
m_Handler.UnregisterInputEvent(m_StartRotateInputEvent);
|
||||
}
|
||||
|
||||
m_Handler.UnregisterInputEvent(m_TurnInputEvent);
|
||||
m_Handler.UnregisterInputEvent(m_AutoMoveInputEvent);
|
||||
|
||||
GenericObjectPool.Return(m_StartRotateInputEvent);
|
||||
GenericObjectPool.Return(m_StopRotateInputEvent);
|
||||
GenericObjectPool.Return(m_TurnInputEvent);
|
||||
GenericObjectPool.Return(m_AutoMoveInputEvent);
|
||||
}
|
||||
EventHandler.UnregisterEvent(m_GameObject, "OnRPGMovementTypeStartRotate", OnStartRotate);
|
||||
EventHandler.UnregisterEvent(m_GameObject, "OnRPGMovementTypeStopRotate", OnStopRotate);
|
||||
EventHandler.UnregisterEvent<float>(m_GameObject, "OnRPGMovementTypeTurn", OnTurn);
|
||||
EventHandler.UnregisterEvent(m_GameObject, "OnRPGMovementTypeAutoMove", OnToggleAutoMove);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3dc906d2f18da4649803c9590337dbf8
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,157 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character.MovementTypes
|
||||
{
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Character.MovementTypes;
|
||||
using Opsive.UltimateCharacterController.Input;
|
||||
using Opsive.UltimateCharacterController.Utility;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// The TopDown MovementType can move the character relative to a top down camera.
|
||||
/// </summary>
|
||||
public class TopDown : MovementType
|
||||
{
|
||||
[Tooltip("Should the character move relative to the camera's direction?")]
|
||||
[SerializeField] protected bool m_RelativeCameraMovement = true;
|
||||
[Tooltip("Should the character look in the direction of the movement?")]
|
||||
[SerializeField] protected bool m_LookInMoveDirection;
|
||||
|
||||
public bool RelativeCameraMovement { get { return m_RelativeCameraMovement; } set { m_RelativeCameraMovement = value; } }
|
||||
public bool LookInMoveDirection { get { return m_LookInMoveDirection; } set { m_LookInMoveDirection = value; } }
|
||||
|
||||
private PlayerInput m_PlayerInput;
|
||||
private UnityEngine.Camera m_Camera;
|
||||
private Plane m_HitPlane = new Plane();
|
||||
|
||||
public override bool FirstPersonPerspective { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the MovementType.
|
||||
/// </summary>
|
||||
/// <param name="characterLocomotion">The reference to the character locomotion component.</param>
|
||||
public override void Initialize(UltimateCharacterLocomotion characterLocomotion)
|
||||
{
|
||||
base.Initialize(characterLocomotion);
|
||||
|
||||
m_PlayerInput = characterLocomotion.gameObject.GetCachedComponent<PlayerInput>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A new ILookSource object has been attached to the character.
|
||||
/// </summary>
|
||||
/// <param name="lookSource">The ILookSource object attached to the character.</param>
|
||||
protected override void OnAttachLookSource(ILookSource lookSource)
|
||||
{
|
||||
base.OnAttachLookSource(lookSource);
|
||||
|
||||
if (lookSource != null) {
|
||||
m_Camera = lookSource.GameObject.GetCachedComponent<UnityEngine.Camera>();
|
||||
} else {
|
||||
m_Camera = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the delta yaw rotation of the character.
|
||||
/// </summary>
|
||||
/// <param name="characterHorizontalMovement">The character's horizontal movement.</param>
|
||||
/// <param name="characterForwardMovement">The character's forward movement.</param>
|
||||
/// <param name="cameraHorizontalMovement">The camera's horizontal movement.</param>
|
||||
/// <param name="cameraVerticalMovement">The camera's vertical movement.</param>
|
||||
/// <returns>The delta yaw rotation of the character.</returns>
|
||||
public override float GetDeltaYawRotation(float characterHorizontalMovement, float characterForwardMovement, float cameraHorizontalMovement, float cameraVerticalMovement)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (m_LookSource == null) {
|
||||
Debug.LogError("Error: There is no look source attached to the character. Ensure the character has a look source attached. For player characters the look source is the Camera Controller, and AI agents use the Local Look Source.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (m_LookInMoveDirection) {
|
||||
if (characterHorizontalMovement != 0 || characterForwardMovement != 0) {
|
||||
var inputVector = Vector3.zero;
|
||||
inputVector.Set(characterHorizontalMovement, 0, characterForwardMovement);
|
||||
|
||||
var lookRotation = Quaternion.LookRotation(m_LookSource.Transform.rotation * inputVector.normalized);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, lookRotation).eulerAngles.y);
|
||||
}
|
||||
} else {
|
||||
// The character should look towards the cursor or Mouse X/Y direction.
|
||||
if (m_PlayerInput.IsCursorVisible()) {
|
||||
// Cast a ray from the mouse position to an invisible plane to determine the direction that the character should look.
|
||||
float distance;
|
||||
var ray = m_Camera.ScreenPointToRay(m_PlayerInput.GetMousePosition());
|
||||
var characterCenter = m_Transform.position + (m_CharacterLocomotion.Up * m_CharacterLocomotion.Height / 2);
|
||||
m_HitPlane.SetNormalAndPosition(m_CharacterLocomotion.Up, characterCenter);
|
||||
if (m_HitPlane.Raycast(ray, out distance)) {
|
||||
var rotation = Quaternion.LookRotation((ray.GetPoint(distance) - characterCenter).normalized, m_CharacterLocomotion.Up);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, rotation).eulerAngles.y);
|
||||
}
|
||||
} else {
|
||||
// If the mouse hasn't moved then get the axis to determine a look rotation. This will be used for controllers and virtual input.
|
||||
var direction = Vector3.zero;
|
||||
direction.x = m_PlayerInput.GetAxis(m_PlayerInput.HorizontalLookInputName);
|
||||
direction.z = m_PlayerInput.GetAxis(m_PlayerInput.VerticalLookInputName);
|
||||
if (direction.sqrMagnitude > 0.1f) {
|
||||
var rotation = Quaternion.LookRotation(direction.normalized, m_CharacterLocomotion.Up);
|
||||
return MathUtility.ClampInnerAngle(MathUtility.InverseTransformQuaternion(m_Transform.rotation, rotation).eulerAngles.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the controller's input vector relative to the movement type.
|
||||
/// </summary>
|
||||
/// <param name="inputVector">The current input vector.</param>
|
||||
/// <returns>The updated input vector.</returns>
|
||||
public override Vector2 GetInputVector(Vector2 inputVector)
|
||||
{
|
||||
if (!m_RelativeCameraMovement) {
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
var rotation = m_Transform.rotation;
|
||||
// The camera may not exist (in the case of an AI agent) but if it does move relative to the camera position.
|
||||
if (m_LookSource != null) {
|
||||
var localEuler = MathUtility.InverseTransformQuaternion(m_LookSource.Transform.rotation, Quaternion.LookRotation(Vector3.forward, m_CharacterLocomotion.Up)).eulerAngles;
|
||||
localEuler.x = localEuler.z = 0;
|
||||
rotation *= MathUtility.TransformQuaternion(Quaternion.Euler(localEuler), Quaternion.LookRotation(Vector3.forward, m_CharacterLocomotion.Up));
|
||||
}
|
||||
// Convert to a local input vector. Vector3s are required for the correct calculation.
|
||||
var localInputVector = Vector3.zero;
|
||||
localInputVector.Set(inputVector.x, 0, inputVector.y);
|
||||
localInputVector = Quaternion.Inverse(rotation) * localInputVector;
|
||||
|
||||
// Store the max input vector value so it can be normalized before being returned.
|
||||
var maxInputVectorValue = Mathf.Max(Mathf.Abs(inputVector.x), Mathf.Abs(inputVector.y));
|
||||
inputVector.x = localInputVector.x;
|
||||
inputVector.y = localInputVector.z;
|
||||
// Normalize the input vector to prevent the diagonals from moving faster.
|
||||
inputVector = inputVector.normalized * maxInputVectorValue;
|
||||
|
||||
return inputVector;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Can the character look independently of the transform rotation?
|
||||
/// </summary>
|
||||
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
|
||||
/// <returns>True if the character should look independently of the transform rotation.</returns>
|
||||
public override bool UseIndependentLook(bool characterLookDirection)
|
||||
{
|
||||
if (m_LookInMoveDirection || base.UseIndependentLook(characterLookDirection)) {
|
||||
}
|
||||
return !characterLookDirection || m_PlayerInput.IsControllerConnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dffcf3d2e895ac4aaf74325240d28f2
|
||||
timeCreated: 1480847939
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,270 @@
|
||||
/// ---------------------------------------------
|
||||
/// Ultimate Character Controller
|
||||
/// Copyright (c) Opsive. All Rights Reserved.
|
||||
/// https://www.opsive.com
|
||||
/// ---------------------------------------------
|
||||
|
||||
namespace Opsive.UltimateCharacterController.ThirdPersonController.Character
|
||||
{
|
||||
using Opsive.Shared.Events;
|
||||
using Opsive.Shared.Game;
|
||||
using Opsive.UltimateCharacterController.Character;
|
||||
using Opsive.UltimateCharacterController.Character.Identifiers;
|
||||
using Opsive.UltimateCharacterController.Items;
|
||||
using Opsive.UltimateCharacterController.StateSystem;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Manages the objects that are changed between a first and third person perspective.
|
||||
/// </summary>
|
||||
public class PerspectiveMonitor : StateBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// Specifies which objects should be visible when the character dies in a first person view.
|
||||
/// </summary>
|
||||
public enum ObjectDeathVisiblity
|
||||
{
|
||||
AllInvisible, // The entire rig will be invisible upon death.
|
||||
ThirdPersonObjectDetermined, // Only the objects marked with the ThirdPersonObject and ThirdPersonObject.InvisibleOnDeath set to true will be invisible upon death.
|
||||
AllVisible // No objects will be invisible upon death.
|
||||
}
|
||||
|
||||
[Tooltip("The material used to make the object invisible but still cast shadows.")]
|
||||
[SerializeField] protected Material m_InvisibleMaterial;
|
||||
[Tooltip("Specifies which objects should be visible when the character dies in a first person view.")]
|
||||
[SerializeField] protected ObjectDeathVisiblity m_DeathVisibility = ObjectDeathVisiblity.AllVisible;
|
||||
|
||||
public Material InvisibleMaterial { get { return m_InvisibleMaterial; } set { m_InvisibleMaterial = value; } }
|
||||
public ObjectDeathVisiblity DeathVisiblity { get { return m_DeathVisibility; } set { m_DeathVisibility = value; } }
|
||||
|
||||
private GameObject m_GameObject;
|
||||
private UltimateCharacterLocomotion m_CharacterLocomotion;
|
||||
private Inventory.InventoryBase m_Inventory;
|
||||
|
||||
private bool m_FirstPersonPerspective;
|
||||
private List<Renderer> m_Renderers = new List<Renderer>();
|
||||
private List<ThirdPersonObject> m_RendererThirdPersonObjects = new List<ThirdPersonObject>();
|
||||
private List<Material[]> m_OriginalMaterials = new List<Material[]>();
|
||||
private List<Material[]> m_InvisibleMaterials = new List<Material[]>();
|
||||
private HashSet<Renderer> m_RegisteredRenderers = new HashSet<Renderer>();
|
||||
private List<int> m_ThirdPersonRenderers = new List<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Registeres for any interested events.
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
m_GameObject = gameObject;
|
||||
m_CharacterLocomotion = m_GameObject.GetCachedComponent<UltimateCharacterLocomotion>();
|
||||
|
||||
// The third person objects will be hidden with the invisible shadow caster while in first person view.
|
||||
var characterRenderers = m_GameObject.GetComponentsInChildren<Renderer>(true);
|
||||
if (characterRenderers != null) {
|
||||
for (int i = 0; i < characterRenderers.Length; ++i) {
|
||||
var renderer = characterRenderers[i];
|
||||
if (m_RegisteredRenderers.Contains(renderer)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CacheRendererMaterials(renderer);
|
||||
}
|
||||
}
|
||||
|
||||
EventHandler.RegisterEvent<bool>(m_GameObject, "OnCameraChangePerspectives", OnChangePerspectives);
|
||||
EventHandler.RegisterEvent<Item>(m_GameObject, "OnInventoryAddItem", OnAddItem);
|
||||
EventHandler.RegisterEvent<Vector3, Vector3, GameObject>(m_GameObject, "OnDeath", OnDeath);
|
||||
EventHandler.RegisterEvent(m_GameObject, "OnWillRespawn", OnWillRespawn);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the default values.
|
||||
/// </summary>
|
||||
private void Start()
|
||||
{
|
||||
m_Inventory = m_GameObject.GetCachedComponent<Inventory.InventoryBase>();
|
||||
m_FirstPersonPerspective = m_CharacterLocomotion.FirstPersonPerspective;
|
||||
|
||||
#if ULTIMATE_CHARACTER_CONTROLLER_MULTIPLAYER
|
||||
var networkInfo = m_GameObject.GetCachedComponent<Networking.INetworkInfo>();
|
||||
if (networkInfo != null && !networkInfo.IsLocalPlayer()) {
|
||||
// Remote players should always be in the third person view.
|
||||
OnChangePerspectives(false);
|
||||
EventHandler.UnregisterEvent<bool>(m_GameObject, "OnCameraChangePerspectives", OnChangePerspectives);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Caches the materials attached to the renderer so they can be switched with the invisible material.
|
||||
/// </summary>
|
||||
/// <param name="renderer">The renderer to cache.</param>
|
||||
private void CacheRendererMaterials(Renderer renderer)
|
||||
{
|
||||
var thirdPersonobject = renderer.gameObject.GetCachedInactiveComponentInParent<ThirdPersonObject>();
|
||||
if (thirdPersonobject != null) {
|
||||
m_ThirdPersonRenderers.Add(m_Renderers.Count);
|
||||
}
|
||||
|
||||
m_Renderers.Add(renderer);
|
||||
m_RendererThirdPersonObjects.Add(thirdPersonobject);
|
||||
m_RegisteredRenderers.Add(renderer);
|
||||
m_OriginalMaterials.Add(renderer.materials);
|
||||
var invisibleMaterials = new Material[renderer.materials.Length];
|
||||
for (int i = 0; i < renderer.materials.Length; ++i) {
|
||||
invisibleMaterials[i] = m_InvisibleMaterial;
|
||||
}
|
||||
m_InvisibleMaterials.Add(invisibleMaterials);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The camera perspective between first and third person has changed.
|
||||
/// </summary>
|
||||
/// <param name="firstPersonPerspective">Is the camera in a first person perspective?</param>
|
||||
private void OnChangePerspectives(bool firstPersonPerspective)
|
||||
{
|
||||
m_FirstPersonPerspective = firstPersonPerspective;
|
||||
|
||||
if (!m_GameObject.activeSelf) {
|
||||
return;
|
||||
}
|
||||
|
||||
UpdateThirdPersonMaterials(false);
|
||||
|
||||
// The FirstPersonObjects GameObject must be changed first to prevent activation errors/warnings. After the GameObject has been changed the
|
||||
// character components can safely receive the event.
|
||||
EventHandler.ExecuteEvent<bool>(m_GameObject, "OnCharacterChangePerspectives", firstPersonPerspective);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the materials of the third person objects.
|
||||
/// </summary>
|
||||
public void UpdateThirdPersonMaterials(bool forceThirdPerson)
|
||||
{
|
||||
for (int i = 0; i < m_ThirdPersonRenderers.Count; ++i) {
|
||||
var thirdPersonIndex = m_ThirdPersonRenderers[i];
|
||||
m_Renderers[thirdPersonIndex].materials = ((m_FirstPersonPerspective && !m_RendererThirdPersonObjects[thirdPersonIndex].ForceVisible && !forceThirdPerson) ?
|
||||
m_InvisibleMaterials[thirdPersonIndex] : m_OriginalMaterials[thirdPersonIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The inventory has added the specified item.
|
||||
/// </summary>
|
||||
/// <param name="item">The item that was added.</param>
|
||||
private void OnAddItem(Item item)
|
||||
{
|
||||
// The Third Person's PerspectiveItem object will contain a reference to the ThirdPersonObject component.
|
||||
var perspectiveItems = item.GetComponents<PerspectiveItem>();
|
||||
PerspectiveItem thirdPersonPerspectiveItem = null;
|
||||
for (int i = 0; i < perspectiveItems.Length; ++i) {
|
||||
if (!perspectiveItems[i].FirstPersonItem) {
|
||||
thirdPersonPerspectiveItem = perspectiveItems[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (thirdPersonPerspectiveItem != null && thirdPersonPerspectiveItem.Object != null) {
|
||||
var thirdPersonObject = thirdPersonPerspectiveItem.Object.GetComponent<ThirdPersonObject>();
|
||||
// If the third person object exists then it should be added to the materials list.
|
||||
if (thirdPersonObject != null) {
|
||||
var renderers = thirdPersonObject.GetComponentsInChildren<Renderer>(true);
|
||||
for (int i = 0; i < renderers.Length; ++i) {
|
||||
if (!m_RegisteredRenderers.Contains(renderers[i])) {
|
||||
CacheRendererMaterials(renderers[i]);
|
||||
|
||||
// If the first person perspective is active then any third person item materials should use the invisible material.
|
||||
if (m_CharacterLocomotion.FirstPersonPerspective) {
|
||||
renderers[i].materials = m_InvisibleMaterials[m_InvisibleMaterials.Count - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character has died.
|
||||
/// </summary>
|
||||
/// <param name="position">The position of the force.</param>
|
||||
/// <param name="force">The amount of force which killed the character.</param>
|
||||
/// <param name="attacker">The GameObject that killed the character.</param>
|
||||
private void OnDeath(Vector3 position, Vector3 force, GameObject attacker)
|
||||
{
|
||||
TryUpdateDeathMaterials(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to switch to the materials used when the character died.
|
||||
/// </summary>
|
||||
/// <param name="fromDeathEvent">Is the method being called from the OnDeath event?</param>
|
||||
/// <returns>True if the materials were updated.</returns>
|
||||
private bool TryUpdateDeathMaterials(bool fromDeathEvent)
|
||||
{
|
||||
// Ensure no first person weapons are equipped before enabling the third person objects.
|
||||
if (m_CharacterLocomotion.FirstPersonPerspective) {
|
||||
for (int i = 0; i < m_Inventory.SlotCount; ++i) {
|
||||
if (m_Inventory.GetActiveItem(i) != null) {
|
||||
// If an item is still equipped then the material shouldn't be switched until after it is no longer equipped.
|
||||
if (fromDeathEvent) {
|
||||
EventHandler.RegisterEvent<Item, int>(m_GameObject, "OnInventoryUnequipItem", OnUnequipItem);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All items are unequipped. Update the renderers.
|
||||
for (int i = 0; i < m_Renderers.Count; ++i) {
|
||||
var invisibleObject = false;
|
||||
if (m_DeathVisibility == ObjectDeathVisiblity.AllInvisible) {
|
||||
invisibleObject = m_CharacterLocomotion.FirstPersonPerspective;
|
||||
} else if (m_DeathVisibility == ObjectDeathVisiblity.ThirdPersonObjectDetermined) {
|
||||
var thirdPersonObject = m_RendererThirdPersonObjects[i];
|
||||
invisibleObject = m_CharacterLocomotion.FirstPersonPerspective &&
|
||||
(thirdPersonObject != null && !thirdPersonObject.FirstPersonVisibleOnDeath && !thirdPersonObject.ForceVisible);
|
||||
}
|
||||
m_Renderers[i].materials = (invisibleObject ? m_InvisibleMaterials[i] : m_OriginalMaterials[i]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The specified item has been unequipped.
|
||||
/// </summary>
|
||||
/// <param name="item">The item that was unequipped.</param>
|
||||
/// <param name="slotID"></param>
|
||||
private void OnUnequipItem(Item item, int slotID)
|
||||
{
|
||||
if (TryUpdateDeathMaterials(false)) {
|
||||
EventHandler.UnregisterEvent<Item, int>(m_GameObject, "OnInventoryUnequipItem", OnUnequipItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The character will respawn. This should be performed before the MaterialSwapper's Respawn method is called.
|
||||
/// </summary>
|
||||
private void OnWillRespawn()
|
||||
{
|
||||
EventHandler.UnregisterEvent<Item, int>(m_GameObject, "OnInventoryUnequipItem", OnUnequipItem);
|
||||
|
||||
for (int i = 0; i < m_Renderers.Count; ++i) {
|
||||
m_Renderers[i].materials = (!m_CharacterLocomotion.FirstPersonPerspective ||
|
||||
(m_RendererThirdPersonObjects[i] == null)) ? m_OriginalMaterials[i] : m_InvisibleMaterials[i];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The GameObject has been destroyed.
|
||||
/// </summary>
|
||||
private void OnDestroy()
|
||||
{
|
||||
EventHandler.UnregisterEvent<bool>(m_GameObject, "OnCameraChangePerspectives", OnChangePerspectives);
|
||||
EventHandler.UnregisterEvent<Item>(m_GameObject, "OnInventoryAddItem", OnAddItem);
|
||||
EventHandler.UnregisterEvent<Vector3, Vector3, GameObject>(m_GameObject, "OnDeath", OnDeath);
|
||||
EventHandler.UnregisterEvent(m_GameObject, "OnWillRespawn", OnWillRespawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cec7620e80ab4db42ae512f733459a5a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences:
|
||||
- m_InvisibleMaterial: {fileID: 2100000, guid: 0a580a5ea04fdab47941095489aa23b7,
|
||||
type: 2}
|
||||
executionOrder: 90
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user