/// <summary> /// Initialize the camera to follow the character. /// </summary> /// <param name="character">The character to initialize. Can be null.</param> private void InitializeCharacter(GameObject character) { #if UNITY_EDITOR if (!Application.isPlaying) { return; } #endif if (character == m_Character) { return; } // If the character is not null then the previous character should be notified that there is no longer a camera attached. if (m_Character != null) { EventHandler.ExecuteEvent <CameraController>(m_Character, "OnCharacterAttachCamera", null); EventHandler.ExecuteEvent <ILookSource>(m_Character, "OnCharacterAttachLookSource", null); EventHandler.UnregisterEvent <Vector3>(m_Character, "OnCameraPositionalForce", AddPositionalForce); EventHandler.UnregisterEvent <Vector3>(m_Character, "OnCameraRotationalForce", AddRotationalForce); EventHandler.UnregisterEvent <Vector3, Vector3, float>(m_Character, "OnAddSecondaryCameraForce", OnAddSecondaryForce); EventHandler.UnregisterEvent <bool>(m_Character, "OnCharacterImmediateTransformChange", OnImmediateTransformChange); EventHandler.UnregisterEvent(m_Character, "OnAnimatorSnapped", PositionImmediately); EventHandler.UnregisterEvent <Ability, bool>(m_Character, "OnCharacterAbilityActive", OnAbilityActive); EventHandler.UnregisterEvent <ItemAbility, bool>(m_Character, "OnCharacterItemAbilityActive", OnItemAbilityActive); EventHandler.UnregisterEvent <bool>(m_Character, "OnCameraChangePerspectives", OnChangePerspectives); StateManager.LinkGameObjects(m_Character, m_GameObject, false); } // The character should no longer be using the zoom state if the camera is no longer attached. if (m_Zoom && m_Character != null) { SetZoom(false); } // Set the character values. if (enabled = (character != null)) { m_Character = character; m_CharacterTransform = m_Character.transform; m_CharacterLocomotion = character.GetCachedComponent <UltimateCharacterLocomotion>(); m_CharacterInventory = character.GetCachedComponent <InventoryBase>(); InitializeAnchor(); } else { m_Character = null; m_CharacterTransform = null; m_CharacterLocomotion = null; m_CharacterInventory = null; } // Notify the view types of the character that is being attached. for (int i = 0; i < m_ViewTypes.Length; ++i) { m_ViewTypes[i].AttachCharacter(m_Character); } if (m_Character != null) { m_ViewType.ChangeViewType(true, 0, 0, m_CharacterTransform.rotation); if (m_ViewType.RotatePriority) { KinematicObjectManager.SetCameraRotation(m_KinematicObjectIndex, m_ViewType.Rotate(0, 0, true)); KinematicObjectManager.SetCameraPosition(m_KinematicObjectIndex, m_ViewType.Move(true)); } else { KinematicObjectManager.SetCameraPosition(m_KinematicObjectIndex, m_ViewType.Move(true)); KinematicObjectManager.SetCameraRotation(m_KinematicObjectIndex, m_ViewType.Rotate(0, 0, true)); } m_ViewType.UpdateFieldOfView(true); // Registered for any interested events. EventHandler.RegisterEvent <Vector3>(m_Character, "OnCameraPositionalForce", AddPositionalForce); EventHandler.RegisterEvent <Vector3>(m_Character, "OnCameraRotationalForce", AddRotationalForce); EventHandler.RegisterEvent <Vector3, Vector3, float>(m_Character, "OnAddSecondaryCameraForce", OnAddSecondaryForce); EventHandler.RegisterEvent <bool>(m_Character, "OnCharacterImmediateTransformChange", OnImmediateTransformChange); EventHandler.RegisterEvent(m_Character, "OnAnimatorSnapped", PositionImmediately); EventHandler.RegisterEvent <Ability, bool>(m_Character, "OnCharacterAbilityActive", OnAbilityActive); EventHandler.RegisterEvent <ItemAbility, bool>(m_Character, "OnCharacterItemAbilityActive", OnItemAbilityActive); EventHandler.RegisterEvent <bool>(m_Character, "OnCameraChangePerspectives", OnChangePerspectives); // Notify the camera components of the attached character. EventHandler.ExecuteEvent <GameObject>(m_GameObject, "OnCameraAttachCharacter", character); // Notify the character of the attached camera. EventHandler.ExecuteEvent <CameraController>(m_Character, "OnCharacterAttachCamera", this); EventHandler.ExecuteEvent <ILookSource>(m_Character, "OnCharacterAttachLookSource", this); EventHandler.ExecuteEvent <bool>(m_Character, "OnCameraWillChangePerspectives", m_ViewType.FirstPersonPerspective); EventHandler.ExecuteEvent <bool>(m_Character, "OnCameraChangePerspectives", m_ViewType.FirstPersonPerspective); StateManager.LinkGameObjects(m_Character, m_GameObject, true); #if UNITY_EDITOR // Show a warning if the movement type isn't what is recommended for the current view type. Only show this when the character is initially attached // because a mismatch is most likely when initially setting up the character. var recommendedMovementTypes = m_ViewType.GetType().GetCustomAttributes(typeof(RecommendedMovementType), true); if (recommendedMovementTypes != null && recommendedMovementTypes.Length > 0) { var movementType = m_CharacterLocomotion.ActiveMovementType; var isRecommendedMovementType = false; for (int i = 0; i < recommendedMovementTypes.Length; ++i) { var recommendedMovementType = recommendedMovementTypes[0] as RecommendedMovementType; if (recommendedMovementType.Type.IsInstanceOfType(movementType)) { isRecommendedMovementType = true; break; } } if (!isRecommendedMovementType) { Debug.LogWarning($"Warning: The {UnityEngineUtility.GetFriendlyName(movementType.GetType())} MovementType is active while the ViewType " + $"recommends using {UnityEngineUtility.GetFriendlyName((recommendedMovementTypes[0] as RecommendedMovementType).Type)}."); } } #endif } else { // Notify the camera components of the attached character. EventHandler.ExecuteEvent <GameObject>(m_GameObject, "OnCameraAttachCharacter", character); } }
/// <summary> /// Sets the view type to the object with the specified type. /// </summary> /// <param name="type">The type of the ViewType which should be set.</param> /// <param name="immediateTransition">Should the ViewType be transitioned immediately?</param> public void SetViewType(System.Type type, bool immediateTransition) { if ((m_ViewType != null && m_ViewType.GetType() == type) || type == null) { return; } // The ViewTypes may not be deserialized yet. if (m_ViewTypeNameMap.Count == 0) { DeserializeViewTypes(); } int index; if (!m_ViewTypeNameMap.TryGetValue(type.FullName, out index)) { Debug.LogError("Error: Unable to find the view type with name " + type.FullName); return; } float pitch = 0f, yaw = 0f; var characterRotation = Quaternion.identity; // ViewType will be null on startup. if (m_ViewType != null && m_Character != null && Application.isPlaying) { pitch = m_ViewType.Pitch; yaw = m_ViewType.Yaw; characterRotation = m_ViewType.CharacterRotation; m_ViewType.ChangeViewType(false, 0, yaw, characterRotation); EventHandler.ExecuteEvent(m_GameObject, "OnCameraChangeViewTypes", m_ViewType, false); if (m_OnChangeViewTypesEvent != null) { m_OnChangeViewTypesEvent.Invoke(m_ViewType, false); } } var originalViewType = m_ViewType; m_ViewTypeFullName = type.FullName; m_ViewType = m_ViewTypes[index]; // Keep the first/third person view type updated to be able to switch back to the last active type. if (m_ViewType.FirstPersonPerspective) { m_FirstPersonViewTypeFullName = m_ViewTypeFullName; m_FirstPersonViewType = m_ViewType; } else { m_ThirdPersonViewTypeFullName = m_ViewTypeFullName; m_ThirdPersonViewType = m_ViewType; } // If the original view type is not null then the view type has been changed at runtime. Transition to that new view type. if (originalViewType != null && m_Character != null && Application.isPlaying) { m_ViewType.ChangeViewType(true, pitch, yaw, characterRotation); EventHandler.ExecuteEvent(m_GameObject, "OnCameraChangeViewTypes", m_ViewType, true); if (m_OnChangeViewTypesEvent != null) { m_OnChangeViewTypesEvent.Invoke(m_ViewType, true); } if (originalViewType.FirstPersonPerspective != m_ViewType.FirstPersonPerspective) { EventHandler.ExecuteEvent <bool>(m_Character, "OnCameraWillChangePerspectives", m_ViewType.FirstPersonPerspective); } // Use the transitioner if it exists. if (!immediateTransition && m_Transitioner != null) { // StartTransition will return success if the transition is started. if (m_Transitioner.StartTransition(originalViewType, m_ViewType)) { return; } else if (m_Transitioner.IsTransitioning) { m_Transitioner.StopTransition(false); } } else { // If there isn't a transitioner then immediately move to the target position. if (m_ViewType.RotatePriority) { KinematicObjectManager.SetCameraRotation(m_KinematicObjectIndex, m_ViewType.Rotate(0, 0, true)); KinematicObjectManager.SetCameraPosition(m_KinematicObjectIndex, m_ViewType.Move(true)); } else { KinematicObjectManager.SetCameraPosition(m_KinematicObjectIndex, m_ViewType.Move(true)); KinematicObjectManager.SetCameraRotation(m_KinematicObjectIndex, m_ViewType.Rotate(0, 0, true)); } } // Execute the perspective event if the transitioner does not exist or is not active. The transitioner will execute this event when it finishes. if (originalViewType.FirstPersonPerspective != m_ViewType.FirstPersonPerspective) { EventHandler.ExecuteEvent <bool>(m_Character, "OnCameraChangePerspectives", m_ViewType.FirstPersonPerspective); if (m_OnChangePerspectivesEvent != null) { m_OnChangePerspectivesEvent.Invoke(m_ViewType.FirstPersonPerspective); } } } }