This commit is contained in:
2026-06-14 23:57:44 +07:00
parent 20f9010787
commit 78d7b2f5a7
5775 changed files with 4796241 additions and 5 deletions

View File

@@ -0,0 +1,83 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes
{
using Opsive.Shared.Events;
using Opsive.UltimateCharacterController.Character.Abilities;
using UnityEngine;
/// <summary>
/// The Combat ViewType a first person prespective that allows the camera and character to rotate together.
/// </summary>
[UltimateCharacterController.Camera.ViewTypes.RecommendedMovementType(typeof(Character.MovementTypes.Combat))]
[UltimateCharacterController.StateSystem.AddState("Zoom", "f08c1d8b08898574baa7bd27c1b05e62")]
public class Combat : FirstPerson
{
private bool m_RotateWithCharacter;
/// <summary>
/// Attaches the view type to the specified character.
/// </summary>
/// <param name="character">The character to attach the camera to.</param>
public override void AttachCharacter(GameObject character)
{
if (m_Character != null) {
EventHandler.UnregisterEvent<Ability, bool>(m_Character, "OnCharacterAbilityActive", OnAbilityActive);
}
base.AttachCharacter(character);
if (m_Character != null) {
m_RotateWithCharacter = false;
EventHandler.RegisterEvent<Ability, bool>(m_Character, "OnCharacterAbilityActive", OnAbilityActive);
}
}
/// <summary>
/// Rotates the camera according to the horizontal and vertical movement values.
/// </summary>
/// <param name="horizontalMovement">-1 to 1 value specifying the amount of horizontal movement.</param>
/// <param name="verticalMovement">-1 to 1 value specifying the amount of vertical movement.</param>
/// <param name="immediatePosition">Should the camera be positioned immediately?</param>
/// <returns>The updated rotation.</returns>
public override Quaternion Rotate(float horizontalMovement, float verticalMovement, bool immediatePosition)
{
// The character may be controlling the rotation rather than the camera.
if (m_RotateWithCharacter || m_CharacterLocomotion.UsingRootMotionRotation) {
m_CharacterRotation = m_CharacterTransform.rotation;
} else {
if (m_Pitch > 90 || m_Pitch < -90) {
horizontalMovement *= -1;
}
m_Yaw += horizontalMovement;
}
return base.Rotate(horizontalMovement, verticalMovement, immediatePosition);
}
/// <summary>
/// The character's ability has been started or stopped.
/// </summary>
/// <param name="ability">The ability which was started or stopped.</param>
/// <param name="active">True if the ability was started, false if it was stopped.</param>
private void OnAbilityActive(Ability ability, bool active)
{
if (!(ability is MoveTowards)) {
return;
}
// Rotate with the camera so the camera will follow the character's rotation when the character is getting into position for Move Towards.
m_RotateWithCharacter = active;
// When rotate with character is enabled the CharacterRotation quaternion will update to the character's current rotation so the camera moves with the
// character rather than the character moving with the camera. Set to yaw to 0 to prevent a snapping when the CharacterRotation quaternion is updated.
if (m_RotateWithCharacter) {
m_Yaw = 0;
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,113 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes
{
using Opsive.UltimateCharacterController.Utility;
using Opsive.UltimateCharacterController.FirstPersonController.Character;
using UnityEngine;
/// <summary>
/// The FreeLook ViewType is a first person view type that allows the camera to rotate independently of the character's direction.
/// </summary>
[UltimateCharacterController.Camera.ViewTypes.RecommendedMovementType(typeof(Character.MovementTypes.FreeLook))]
[UltimateCharacterController.StateSystem.AddState("Zoom", "538aa537a9f445e40b8a2c2758627962")]
public class FreeLook : FirstPerson
{
[Tooltip("The minimum yaw angle (in degrees).")]
[SerializeField] protected float m_MinYawLimit = -90;
[Tooltip("The maximum yaw angle (in degrees).")]
[SerializeField] protected float m_MaxYawLimit = 90;
[Tooltip("The speed in which the camera should rotate towards the yaw limit when out of bounds.")]
[Range(0, 1)] [SerializeField] protected float m_YawLimitLerpSpeed = 0.7f;
public float MinYawLimit { get { return m_MinYawLimit; } set { m_MinYawLimit = value; } }
public float MaxYawLimit { get { return m_MaxYawLimit; } set { m_MaxYawLimit = value; } }
public float YawLimitLerpSpeed { get { return m_YawLimitLerpSpeed; } set { m_YawLimitLerpSpeed = value; } }
private Transform m_FirstPersonObjectsTransform;
private Vector3 m_LookDirection;
/// <summary>
/// Attaches the camera to the specified character.
/// </summary>
/// <param name="character">The character to attach the camera to.</param>
public override void AttachCharacter(GameObject character)
{
m_FirstPersonObjectsTransform = null;
base.AttachCharacter(character);
if (m_Character != null) {
var firstPersonObjects = m_Character.GetComponentInChildren<FirstPersonObjects>(true);
if (firstPersonObjects == null) {
// The component may have already been changed to be a child of the camera.
firstPersonObjects = m_GameObject.GetComponentInChildren<FirstPersonObjects>(true);
}
// FirstPersonObjects won't exist if the character carries no items.
if (firstPersonObjects != null) {
m_FirstPersonObjectsTransform = firstPersonObjects.transform;
}
}
}
/// <summary>
/// Rotates the camera according to the horizontal and vertical movement values.
/// </summary>
/// <param name="horizontalMovement">-1 to 1 value specifying the amount of horizontal movement.</param>
/// <param name="verticalMovement">-1 to 1 value specifying the amount of vertical movement.</param>
/// <param name="immediatePosition">Should the camera be positioned immediately?</param>
/// <returns>The updated rotation.</returns>
public override Quaternion Rotate(float horizontalMovement, float verticalMovement, bool immediatePosition)
{
// Update the rotation. The yaw may have a limit.
if (Mathf.Abs(m_MinYawLimit - m_MaxYawLimit) < 360) {
// Determine the new rotation with the updated yaw.
var targetRotation = MathUtility.TransformQuaternion(m_CharacterRotation, Quaternion.Euler(m_Pitch, m_Yaw, 0));
var diff = MathUtility.InverseTransformQuaternion(Quaternion.LookRotation(Vector3.forward, m_CharacterLocomotion.Up), targetRotation * Quaternion.Inverse(m_CharacterTransform.rotation));
// The rotation shouldn't extend beyond the min and max yaw limit.
var targetYaw = MathUtility.ClampAngle(diff.eulerAngles.y, horizontalMovement, m_MinYawLimit, m_MaxYawLimit);
m_Yaw += Mathf.Lerp(0, Mathf.DeltaAngle(diff.eulerAngles.y, targetYaw), m_YawLimitLerpSpeed);
} else {
m_Yaw += horizontalMovement;
}
// Return the rotation.
return base.Rotate(horizontalMovement, verticalMovement, immediatePosition);
}
/// <summary>
/// Returns the direction that the character is looking.
/// </summary>
/// <param name="lookPosition">The position that the character is looking from.</param>
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
/// <param name="layerMask">The LayerMask value of the objects that the look direction can hit.</param>
/// <param name="useRecoil">Should recoil be included in the look direction?</param>
/// <returns>The direction that the character is looking.</returns>
public override Vector3 LookDirection(Vector3 lookPosition, bool characterLookDirection, int layerMask, bool useRecoil)
{
var rotation = m_FirstPersonObjectsTransform != null ? m_FirstPersonObjectsTransform.rotation : m_CameraController.Anchor.rotation;
// Cast a ray from the camera point in the forward direction. The look direction is then the vector from the look position to the hit point.
RaycastHit hit;
Vector3 hitPoint;
if (Physics.Raycast(m_Transform.position, rotation * Vector3.forward, out hit, m_LookDirectionDistance, layerMask, QueryTriggerInteraction.Ignore)) {
hitPoint = hit.point;
} else {
Vector3 position;
if (useRecoil) {
position = GetAnchorTransformPoint(m_PositionSpring.Value + m_SecondaryPositionSpring.Value);
} else {
position = lookPosition;
}
m_LookDirection.Set(0, 0, m_LookDirectionDistance);
hitPoint = MathUtility.TransformPoint(position, rotation, m_LookDirection);
}
return (hitPoint - lookPosition).normalized;
}
}
}

View File

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

View File

@@ -0,0 +1,430 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.FirstPersonController.Camera
{
using Opsive.Shared.Events;
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.FirstPersonController.Character.Identifiers;
using Opsive.UltimateCharacterController.FirstPersonController.Items;
using Opsive.UltimateCharacterController.Camera;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Identifiers;
using Opsive.UltimateCharacterController.Items;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Swaps the first and third person materials so multiple cameras can render the scene within the same instance.
/// </summary>
public class MaterialSwapper : MonoBehaviour
{
/// <summary>
/// Specifies which renderers should be swapped.
/// </summary>
private enum SwapMask
{
FirstPerson = 1, // The first person perspective renderers should be swapped.
ThirdPerson = 2, // The third person perspective renderers should be swapped.
}
[Tooltip("The material used to make the object invisible but still cast shadows.")]
[SerializeField] protected Material m_InvisibleMaterial;
private GameObject m_GameObject;
private Camera m_Camera;
private CameraController m_CameraController;
private UltimateCharacterLocomotion m_CharacterLocomotion;
private SwapMask m_SwapMask = 0;
private HashSet<Renderer> m_AddedFirstPersonRenderers;
private List<Renderer> m_FirstPersonRenderers;
private List<Material[]> m_FirstPersonOriginalMaterials;
private List<Material[]> m_FirstPersonInvisibleMaterials;
private HashSet<GameObject> m_FirstPersonBaseObjects;
private HashSet<Renderer> m_AddedThirdPersonRenderers;
private List<Renderer> m_ThirdPersonRenderers;
private List<Material[]> m_ThirdPersonOriginalMaterials;
private List<Material[]> m_ThirdPersonInvisibleMaterials;
#if THIRD_PERSON_CONTROLLER
private ThirdPersonController.Camera.ObjectFader m_ObjectFader;
#endif
/// <summary>
/// Initializes the default values.
/// </summary>
private void Awake()
{
m_GameObject = gameObject;
m_CameraController = m_GameObject.GetCachedComponent<CameraController>();
if (m_CameraController == null) {
// If the camera controller is null then the component has been added to the first person child camera.
m_CameraController = gameObject.GetCachedParentComponent<CameraController>();
m_SwapMask = SwapMask.FirstPerson;
} else {
var viewTypes = m_CameraController.ViewTypes;
// The component exists on the main camera GameObject. If there is no child first person camera then the single component is responsible for
// swapping both first and third person renderer materials.
for (int i = 0; i < viewTypes.Length; ++i) {
if (viewTypes[i] is ViewTypes.FirstPerson) {
var firstPersonViewType = viewTypes[i] as ViewTypes.FirstPerson;
#if ULTIMATE_CHARACTER_CONTROLLER_LWRP || ULTIMATE_CHARACTER_CONTROLLER_UNIVERSALRP
m_SwapMask = firstPersonViewType.OverlayRenderType == ViewTypes.FirstPerson.ObjectOverlayRenderType.SecondCamera ? SwapMask.ThirdPerson : (SwapMask.FirstPerson | SwapMask.ThirdPerson);
#else
m_SwapMask = firstPersonViewType.UseFirstPersonCamera ? SwapMask.ThirdPerson : (SwapMask.FirstPerson | SwapMask.ThirdPerson);
#endif
#if UNITY_EDITOR
if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
// Ensure the child camera has the Material Swapper component.
if (firstPersonViewType.FirstPersonCamera != null) {
var firstPersonMaterialSwapper = firstPersonViewType.FirstPersonCamera.GetComponent<MaterialSwapper>();
if (firstPersonMaterialSwapper == null) {
Debug.LogWarning("Warning: The First Person Camera should have the Material Swapper component added to the GameObject.");
}
}
}
#endif
break;
}
}
#if THIRD_PERSON_CONTROLLER
m_ObjectFader = m_CameraController.GetComponent<ThirdPersonController.Camera.ObjectFader>();
#endif
}
m_Camera = m_CameraController.GetComponent<Camera>();
// Instantiate the storage objects based on the swap mode.
if ((m_SwapMask & SwapMask.FirstPerson) != 0) {
m_AddedFirstPersonRenderers = new HashSet<Renderer>();
m_FirstPersonRenderers = new List<Renderer>();
m_FirstPersonOriginalMaterials = new List<Material[]>();
m_FirstPersonInvisibleMaterials = new List<Material[]>();
m_FirstPersonBaseObjects = new HashSet<GameObject>();
}
if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
m_AddedThirdPersonRenderers = new HashSet<Renderer>();
m_ThirdPersonRenderers = new List<Renderer>();
m_ThirdPersonOriginalMaterials = new List<Material[]>();
m_ThirdPersonInvisibleMaterials = new List<Material[]>();
}
enabled = false;
EventHandler.RegisterEvent<GameObject>(m_CameraController.gameObject, "OnCameraAttachCharacter", OnAttachCharacter);
}
#if UNIVERSAL_RENDER_PIPELINE
/// <summary>
/// The component has been enabled.
/// </summary>
private void OnEnable()
{
UnityEngine.Rendering.RenderPipelineManager.beginCameraRendering += BeginCameraRendering;
UnityEngine.Rendering.RenderPipelineManager.endCameraRendering += EndCameraRendering;
}
#endif
/// <summary>
/// Attaches the component to the specified character.
/// </summary>
/// <param name="character">The handler to attach the camera to.</param>
protected virtual void OnAttachCharacter(GameObject character)
{
// Don't do anything if the character is the same.
if (m_CharacterLocomotion != null && character == m_CharacterLocomotion.gameObject) {
return;
}
if (m_CharacterLocomotion != null) {
// The character is being changed.
if (m_FirstPersonRenderers != null) {
m_AddedFirstPersonRenderers.Clear();
m_FirstPersonRenderers.Clear();
m_FirstPersonOriginalMaterials.Clear();
m_FirstPersonInvisibleMaterials.Clear();
m_FirstPersonBaseObjects.Clear();
}
if (m_ThirdPersonRenderers != null) {
m_AddedThirdPersonRenderers.Clear();
m_ThirdPersonRenderers.Clear();
m_ThirdPersonOriginalMaterials.Clear();
m_ThirdPersonInvisibleMaterials.Clear();
}
EventHandler.UnregisterEvent<bool>(m_CharacterLocomotion.gameObject, "OnCameraChangePerspectives", OnChangePerspectives);
EventHandler.UnregisterEvent<Item>(m_CharacterLocomotion.gameObject, "OnInventoryAddItem", OnAddItem);
EventHandler.UnregisterEvent(m_CharacterLocomotion.gameObject, "OnRespawn", OnRespawn);
EventHandler.ExecuteEvent(m_CharacterLocomotion.gameObject, "OnCharacterIndependentFade", false, false);
m_CharacterLocomotion = null;
}
enabled = character != null;
if (character == null) {
return;
}
m_CharacterLocomotion = character.GetCachedComponent<UltimateCharacterLocomotion>();
#if THIRD_PERSON_CONTROLLER
// Force the character into using third person materials so the correct materials can be cached.
var perspectiveMonitor = character.GetCachedComponent<ThirdPersonController.Character.PerspectiveMonitor>();
perspectiveMonitor.UpdateThirdPersonMaterials(true);
#endif
if ((m_SwapMask & SwapMask.FirstPerson) != 0) {
var firstPersonBaseObjects = character.GetComponentsInChildren<FirstPersonBaseObject>(true);
for (int i = 0; i < firstPersonBaseObjects.Length; ++i) {
CacheFirstPersonRenderers(firstPersonBaseObjects[i].gameObject);
// Remember the base objects so they are not added again if a runtime item is picked up.
m_FirstPersonBaseObjects.Add(firstPersonBaseObjects[i].gameObject);
}
}
if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
var thirdPersonObjects = character.GetComponentsInChildren<ThirdPersonObject>(true);
for (int i = 0; i < thirdPersonObjects.Length; ++i) {
CacheThirdPersonRenderers(thirdPersonObjects[i].gameObject);
}
}
#if THIRD_PERSON_CONTROLLER
perspectiveMonitor.UpdateThirdPersonMaterials(false);
#endif
EventHandler.RegisterEvent<bool>(m_CharacterLocomotion.gameObject, "OnCameraChangePerspectives", OnChangePerspectives);
EventHandler.RegisterEvent<Item>(m_CharacterLocomotion.gameObject, "OnInventoryAddItem", OnAddItem);
EventHandler.RegisterEvent(m_CharacterLocomotion.gameObject, "OnRespawn", OnRespawn);
EventHandler.ExecuteEvent(m_CharacterLocomotion.gameObject, "OnCharacterIndependentFade", true, false);
// Assume the first person objects are not rendering.
EnableThirdPersonMaterials();
}
/// <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)
{
enabled = firstPersonPerspective
#if THIRD_PERSON_CONTROLLER
|| m_ObjectFader != null
#endif
;
if (!enabled) {
EnableThirdPersonMaterials();
}
}
/// <summary>
/// The inventory has added the specified item.
/// </summary>
/// <param name="item">The item that was added.</param>
private void OnAddItem(Item item)
{
var perspectiveItems = item.GetComponents<PerspectiveItem>();
for (int i = 0; i < perspectiveItems.Length; ++i) {
if (perspectiveItems[i].FirstPersonItem) {
if ((m_SwapMask & SwapMask.FirstPerson) != 0) {
GameObject firstPersonObject;
if (m_FirstPersonBaseObjects.Contains(perspectiveItems[i].Object)) {
firstPersonObject = (perspectiveItems[i] as FirstPersonPerspectiveItem).VisibleItem;
} else {
firstPersonObject = perspectiveItems[i].Object;
m_FirstPersonBaseObjects.Add(firstPersonObject);
}
CacheFirstPersonRenderers(firstPersonObject);
}
} else if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
CacheThirdPersonRenderers(perspectiveItems[i].Object);
}
}
}
/// <summary>
/// Caches the renderers on the specified first person object.
/// </summary>
/// <param name="firstPersonObject">The first person object to cache the renderers of.</param>
private void CacheFirstPersonRenderers(GameObject firstPersonObject)
{
if (firstPersonObject == null) {
return;
}
var renderers = firstPersonObject.GetComponentsInChildren<Renderer>(true);
var emptyMaterial = new Material[0];
for (int i = 0; i < renderers.Length; ++i) {
if (m_AddedFirstPersonRenderers.Contains(renderers[i])) {
continue;
}
m_AddedFirstPersonRenderers.Add(renderers[i]);
m_FirstPersonRenderers.Add(renderers[i]);
m_FirstPersonOriginalMaterials.Add(renderers[i].materials);
m_FirstPersonInvisibleMaterials.Add(emptyMaterial);
}
}
/// <summary>
/// Caches the renderers on the specified third person object.
/// </summary>
/// <param name="thirdPersonObject">The third person object to cache the renderers of.</param>
private void CacheThirdPersonRenderers(GameObject thirdPersonObject)
{
if (thirdPersonObject == null) {
return;
}
var renderers = thirdPersonObject.GetComponentsInChildren<Renderer>(true);
for (int i = 0; i < renderers.Length; ++i) {
if (m_AddedThirdPersonRenderers.Contains(renderers[i])) {
continue;
}
m_AddedThirdPersonRenderers.Add(renderers[i]);
m_ThirdPersonRenderers.Add(renderers[i]);
m_ThirdPersonOriginalMaterials.Add(renderers[i].materials);
var invisibleMaterials = new Material[renderers[i].materials.Length];
for (int j = 0; j < invisibleMaterials.Length; ++j) {
invisibleMaterials[j] = m_InvisibleMaterial;
}
m_ThirdPersonInvisibleMaterials.Add(invisibleMaterials);
}
}
#if !UNIVERSAL_RENDER_PIPELINE
/// <summary>
/// The camera has started to render.
/// </summary>
private void OnPreRender()
{
BeginCameraRendering(m_Camera);
}
/// <summary>
/// The camera has stopped rendering.
/// </summary>
private void OnPostRender()
{
EndCameraRendering(m_Camera);
}
#endif
/// <summary>
/// The camera has started to render.
/// </summary>
/// <param name="context">The context of the SRP.</param>
/// <param name="camera">The camera that is rendering.</param>
#if UNIVERSAL_RENDER_PIPELINE
private void BeginCameraRendering(ScriptableRenderContext context, Camera camera)
#else
private void BeginCameraRendering(Camera camera)
#endif
{
if (camera != m_Camera) {
return;
}
#if THIRD_PERSON_CONTROLLER
if (m_ObjectFader != null) {
m_ObjectFader.MultiCameraRender(true);
}
#endif
if (!m_CharacterLocomotion.FirstPersonPerspective) {
return;
}
// Swap the first person objects to the original material so the current camera can see the arms mesh.
if ((m_SwapMask & SwapMask.FirstPerson) != 0) {
for (int i = 0; i < m_FirstPersonRenderers.Count; ++i) {
m_FirstPersonRenderers[i].materials = m_FirstPersonOriginalMaterials[i];
}
}
// The third person objects should be swapped to the invisible materials because the arms material will be rendered.
if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
for (int i = 0; i < m_ThirdPersonRenderers.Count; ++i) {
m_ThirdPersonRenderers[i].materials = m_ThirdPersonInvisibleMaterials[i];
}
}
}
/// <summary>
/// The camera has stopped rendering.
/// </summary>
/// <param name="context">The context of the SRP.</param>
/// <param name="camera">The camera that stopped rendering.</param>
#if UNIVERSAL_RENDER_PIPELINE
private void EndCameraRendering(ScriptableRenderContext context, Camera camera)
#else
private void EndCameraRendering(Camera camera)
#endif
{
if (camera != m_Camera) {
return;
}
#if THIRD_PERSON_CONTROLLER
if (m_ObjectFader != null) {
m_ObjectFader.MultiCameraRender(false);
}
#endif
if (!m_CharacterLocomotion.FirstPersonPerspective) {
return;
}
EnableThirdPersonMaterials();
}
/// <summary>
/// Swaps the materials for the third person mateirals.
/// </summary>
private void EnableThirdPersonMaterials()
{
// Swap the first person objects back to the invisible material so the separate arms are not seen by other cameras.
if ((m_SwapMask & SwapMask.FirstPerson) != 0) {
for (int i = 0; i < m_FirstPersonRenderers.Count; ++i) {
m_FirstPersonRenderers[i].materials = m_FirstPersonInvisibleMaterials[i];
}
}
// The third person objects should be swapped back to the original materials so the full mesh is rendered by other cameras.
if ((m_SwapMask & SwapMask.ThirdPerson) != 0) {
for (int i = 0; i < m_ThirdPersonRenderers.Count; ++i) {
m_ThirdPersonRenderers[i].materials = m_ThirdPersonOriginalMaterials[i];
}
}
}
/// <summary>
/// The character has respawned.
/// </summary>
private void OnRespawn()
{
OnChangePerspectives(m_CharacterLocomotion.FirstPersonPerspective);
}
#if UNIVERSAL_RENDER_PIPELINE
/// <summary>
/// The component has been disabled.
/// </summary>
private void OnDisable()
{
UnityEngine.Rendering.RenderPipelineManager.beginCameraRendering -= BeginCameraRendering;
UnityEngine.Rendering.RenderPipelineManager.endCameraRendering -= EndCameraRendering;
}
#endif
/// <summary>
/// The camera has been destroyed.
/// </summary>
private void OnDestroy()
{
OnAttachCharacter(null);
EventHandler.UnregisterEvent<GameObject>(m_CameraController.gameObject, "OnCameraAttachCharacter", OnAttachCharacter);
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 156a6ba7c7ad70d47a20a1845e89d7e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_InvisibleMaterial: {fileID: 2100000, guid: 0a580a5ea04fdab47941095489aa23b7,
type: 2}
executionOrder: 80
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
/// ---------------------------------------------
/// Ultimate Character Controller
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.UltimateCharacterController.FirstPersonController.Camera.ViewTypes
{
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController.Camera;
using Opsive.UltimateCharacterController.Camera.ViewTypes;
using Opsive.UltimateCharacterController.Utility;
using UnityEngine;
/// <summary>
/// The TransformLook ViewType is a first person view type that will have the camera look in the forward direction relative to the target transform.
/// </summary>
public class TransformLook : ViewType
{
[Tooltip("The object that determines the position of the camera.")]
[SerializeField] protected Transform m_MoveTarget;
[Tooltip("The object that determines the rotation of the camera.")]
[SerializeField] protected Transform m_RotationTarget;
[Tooltip("The offset relative to the move target.")]
[SerializeField] protected Vector3 m_Offset = new Vector3(0, 0.2f, 0.2f);
[Tooltip("The radius of the camera's collision sphere to prevent it from clipping with other objects.")]
[SerializeField] protected float m_CollisionRadius = 0.05f;
[Tooltip("The speed at which the camera should move.")]
[SerializeField] protected float m_MoveSpeed = 10;
[Tooltip("The speed at which the view type should rotate towards the target rotation.")]
[Range(0, 1)] [SerializeField] protected float m_RotationalLerpSpeed = 0.9f;
[Tooltip("Should the pitch be restricted? If false the pitch can be changed by the player.")]
[SerializeField] protected bool m_RestrictPitch = true;
[Tooltip("The minimum pitch angle (in degrees), used if the pitch is not restricted.")]
[HideInInspector] [SerializeField] protected float m_MinPitchLimit = -72;
[Tooltip("The maximum pitch angle (in degrees), used if the pitch is not restricted.")]
[HideInInspector] [SerializeField] protected float m_MaxPitchLimit = 72;
[Tooltip("Should the yaw be restricted? If false the yaw can be changed by the player.")]
[SerializeField] protected bool m_RestrictYaw = true;
public Transform MoveTarget { get { return m_MoveTarget; } set { m_MoveTarget = value; } }
public Transform RotationTarget { get { return m_RotationTarget; } set { m_RotationTarget = value; } }
public Vector3 Offset { get { return m_Offset; } set { m_Offset = value; } }
public float CollisionRadius { get { return m_CollisionRadius; } set { m_CollisionRadius = value; } }
public float MoveSpeed { get { return m_MoveSpeed; } set { m_MoveSpeed = value; } }
public float RotationalLerpSpeed { get { return m_RotationalLerpSpeed; } set { m_RotationalLerpSpeed = value; } }
public bool RestrictPitch { get { return m_RestrictPitch; } set { m_RestrictPitch = value; } }
public float MinPitchLimit { get { return m_MinPitchLimit; } set { m_MinPitchLimit = value; } }
public float MaxPitchLimit { get { return m_MaxPitchLimit; } set { m_MaxPitchLimit = value; } }
public bool RestrictYaw { get { return m_RestrictYaw; } set { m_RestrictYaw = value; } }
public override Quaternion CharacterRotation { get { return m_CharacterTransform.rotation; } }
public override bool FirstPersonPerspective { get { return true; } }
public override float LookDirectionDistance { get { return m_Offset.magnitude; } }
public override float Pitch { get { return m_Pitch; } }
public override float Yaw { get { return m_Yaw; } }
private UnityEngine.Camera m_Camera;
private RaycastHit m_RaycastHit;
private float m_Pitch;
private float m_Yaw;
/// <summary>
/// Initializes the view type to the specified camera controller.
/// </summary>
/// <param name="cameraController">The camera controller to initialize the view type to.</param>
public override void Initialize(CameraController cameraController)
{
base.Initialize(cameraController);
m_Camera = cameraController.gameObject.GetCachedComponent<UnityEngine.Camera>();
}
/// <summary>
/// Attaches the view type to the specified character.
/// </summary>
/// <param name="character">The character to attach the camera to.</param>
public override void AttachCharacter(GameObject character)
{
base.AttachCharacter(character);
if (m_MoveTarget == null || m_RotationTarget == null) {
if (m_Character == null) {
return;
}
Transform moveTarget = m_CharacterTransform, rotationTarget = m_CharacterTransform;
var characterAnimator = m_Character.GetCachedComponent<Animator>();
if (characterAnimator != null) {
moveTarget = characterAnimator.GetBoneTransform(HumanBodyBones.Head);
rotationTarget = characterAnimator.GetBoneTransform(HumanBodyBones.Hips);
}
m_MoveTarget = moveTarget;
m_RotationTarget = rotationTarget;
}
}
/// <summary>
/// The view type has changed.
/// </summary>
/// <param name="activate">Should the current view type be activated?</param>
/// <param name="pitch">The pitch of the camera (in degrees).</param>
/// <param name="yaw">The yaw of the camera (in degrees).</param>
/// <param name="characterRotation">The rotation of the character.</param>
public override void ChangeViewType(bool activate, float pitch, float yaw, Quaternion characterRotation)
{
if (activate) {
m_Pitch = m_RestrictPitch ? 0 : pitch;
m_Yaw = m_RestrictYaw ? 0 : yaw;
}
}
/// <summary>
/// Reset the ViewType's variables.
/// </summary>
/// <param name="characterRotation">The rotation of the character.</param>
public override void Reset(Quaternion characterRotation)
{
m_Pitch = 0;
m_Yaw = 0;
}
/// <summary>
/// Rotates the camera to face in the same direction as the target.
/// </summary>
/// <param name="horizontalMovement">-1 to 1 value specifying the amount of horizontal movement.</param>
/// <param name="verticalMovement">-1 to 1 value specifying the amount of vertical movement.</param>
/// <param name="immediateUpdate">Should the camera be updated immediately?</param>
/// <returns>The updated rotation.</returns>
public override Quaternion Rotate(float horizontalMovement, float verticalMovement, bool immediateUpdate)
{
var rotation = m_RotationTarget.rotation;
if (!immediateUpdate) {
rotation = Quaternion.Slerp(m_Transform.rotation, rotation, m_RotationalLerpSpeed);
}
// Update the pitch and yaw if they are not restricted.
if (!m_RestrictPitch) {
if (Mathf.Abs(m_MinPitchLimit - m_MaxPitchLimit) < 180) {
m_Pitch = MathUtility.ClampAngle(m_Pitch, -verticalMovement, m_MinPitchLimit, m_MaxPitchLimit);
} else {
m_Pitch -= verticalMovement;
}
}
if (!m_RestrictYaw) {
if (m_Pitch > 90 || m_Pitch < -90) {
horizontalMovement *= -1;
}
m_Yaw = MathUtility.ClampInnerAngle(m_Yaw + horizontalMovement);
}
return rotation * Quaternion.Euler(m_Pitch, m_Yaw, 0);
}
/// <summary>
/// Moves the camera to be in the target position.
/// </summary>
/// <param name="immediateUpdate">Should the camera be updated immediately?</param>
/// <returns>The updated position.</returns>
public override Vector3 Move(bool immediateUpdate)
{
// Ensure there aren't any objects obstructing the distance between the anchor offset and the target position.
var collisionLayerEnabled = m_CharacterLocomotion.CollisionLayerEnabled;
m_CharacterLocomotion.EnableColliderCollisionLayer(false);
var targetPosition = m_MoveTarget.TransformPoint(m_Offset);
var direction = targetPosition - m_MoveTarget.position;
if (Physics.SphereCast(m_MoveTarget.position, m_CollisionRadius, direction.normalized, out m_RaycastHit, direction.magnitude + m_Camera.nearClipPlane,
m_CharacterLayerManager.IgnoreInvisibleCharacterWaterLayers, QueryTriggerInteraction.Ignore)) {
// Move the camera in if an object obstructed the view.
targetPosition = m_RaycastHit.point + m_RaycastHit.normal * (m_Camera.nearClipPlane + m_CharacterLocomotion.ColliderSpacing);
}
m_CharacterLocomotion.EnableColliderCollisionLayer(collisionLayerEnabled);
return Vector3.MoveTowards(m_Transform.position, targetPosition, immediateUpdate ? float.MaxValue : Time.deltaTime * m_MoveSpeed);
}
/// <summary>
/// Returns the direction that the character is looking.
/// </summary>
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
/// <returns>The direction that the character is looking.</returns>
public override Vector3 LookDirection(bool characterLookDirection)
{
return m_CharacterTransform.forward;
}
/// <summary>
/// Returns the direction that the character is looking.
/// </summary>
/// <param name="lookPosition">The position that the character is looking from.</param>
/// <param name="characterLookDirection">Is the character look direction being retrieved?</param>
/// <param name="layerMask">The LayerMask value of the objects that the look direction can hit.</param>
/// <param name="useRecoil">Should recoil be included in the look direction?</param>
/// <returns>The direction that the character is looking.</returns>
public override Vector3 LookDirection(Vector3 lookPosition, bool characterLookDirection, int layerMask, bool useRecoil)
{
return m_CharacterTransform.forward;
}
}
}

View File

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