This commit is contained in:
2026-06-09 09:18:17 +07:00
parent 3578a2750c
commit 71a096556a
5777 changed files with 6675 additions and 13 deletions

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 5ab59ed1e4731cd4fb487f3cc20a3b40
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,130 +0,0 @@
/// ---------------------------------------------
/// 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);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: f2b3cd302b28cf54ebb3823309cb9bbf
timeCreated: 1528491971
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 2a98f71974871654fab0879a6e52b779
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,179 +0,0 @@
/// ---------------------------------------------
/// 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);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 453263f004c12c74e871dd76b4dfa8c4
timeCreated: 1522777146
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,68 +0,0 @@
/// ---------------------------------------------
/// 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;
}
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 156bcc35929b82b49bb622963c6def6a
timeCreated: 1522787067
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 43f20180f83eae546a73c2ef4bcf7a84
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,118 +0,0 @@
/// ---------------------------------------------
/// 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);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: b69f0bb5b55e47d48b4f800ecd868c42
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,52 +0,0 @@
/// ---------------------------------------------
/// 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;
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 3eed0ebe602b43044a30ae7371109403
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,58 +0,0 @@
/// ---------------------------------------------
/// 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;
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: faea5c3719ad489438350ba14709cb6e
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,184 +0,0 @@
/// ---------------------------------------------
/// 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();
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 73c649042e866c54bb54d666c7a5dba8
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,222 +0,0 @@
/// ---------------------------------------------
/// 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);
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 3dc906d2f18da4649803c9590337dbf8
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,157 +0,0 @@
/// ---------------------------------------------
/// 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();
}
}
}

View File

@@ -1,12 +0,0 @@
fileFormatVersion: 2
guid: 8dffcf3d2e895ac4aaf74325240d28f2
timeCreated: 1480847939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,270 +0,0 @@
/// ---------------------------------------------
/// 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);
}
}
}

View File

@@ -1,13 +0,0 @@
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: