/// <summary> /// Rotates the actor to the view over time /// </summary> protected virtual void RotateToView(float rSpeed) { // Grab the angle needed to get to our target forward Vector3 lCameraForward = mMotionController._CameraTransform.forward; float lAvatarToCamera = NumberHelper.GetHorizontalAngle(mMotionController._Transform.forward, lCameraForward, mMotionController._Transform.up); if (lAvatarToCamera == 0f) { return; } // If we have a camera, force it to the direction of the character BaseCameraRig lCameraRig = mMotionController.CameraRig as BaseCameraRig; if (lCameraRig is BaseCameraRig) { (lCameraRig).FrameLockForward = true; } float lInputFromSign = Mathf.Sign(lAvatarToCamera); float lInputFromAngle = Mathf.Abs(lAvatarToCamera); float lRotationAngle = (rSpeed / 60f) * TimeManager.Relative60FPSDeltaTime; // Establish the link if we're close enough if (lInputFromAngle <= lRotationAngle) { lRotationAngle = lInputFromAngle; } // Use the information and AC to determine our final rotation mRotation = Quaternion.AngleAxis(lInputFromSign * lRotationAngle, mMotionController._Transform.up); }
/// <summary> /// When we want to rotate based on the camera direction, we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateCount"></param> /// <param name="rCamera"></param> private void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (mMotionController._CameraTransform == null) { return; } float lToCameraAngle = Vector3Ext.HorizontalAngleTo(mMotionController._Transform.forward, mMotionController._CameraTransform.forward, mMotionController._Transform.up); if (!mLinkRotation && Mathf.Abs(lToCameraAngle) <= _RotationSpeed * rDeltaTime) { mLinkRotation = true; } if (!mLinkRotation) { float lRotationAngle = Mathf.Abs(lToCameraAngle); float lRotationSign = Mathf.Sign(lToCameraAngle); lToCameraAngle = lRotationSign * Mathf.Min(_RotationSpeed * rDeltaTime, lRotationAngle); } Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up); mActorController.Yaw = mActorController.Yaw * lRotation; mActorController._Transform.rotation = mActorController.Tilt * mActorController.Yaw; }
/// <summary> /// Instantiate a camera rig using a prefab /// </summary> /// <param name="rCameraPrefab"></param> /// <returns></returns> public static BaseCameraRig InstantiateCamera(BaseCameraRig rCameraPrefab) { if (rCameraPrefab == null) { return(null); } //// If there is another main camera in the scene, disable it first to avoid conflicts //Camera lMainCamera = Camera.main; //if (lMainCamera != null) //{ // lMainCamera.gameObject.SetActive(false); // Transform lParent = lMainCamera.transform.parent; // if (lParent != null) // { // lParent.gameObject.SetActive(false); // } //} BaseCameraRig lCameraRig = GameObject.Instantiate(rCameraPrefab); if (lCameraRig != null) { lCameraRig.name = rCameraPrefab.name; lCameraRig.Transform.Reset(); } return(lCameraRig); }
protected virtual void OnEnable() { if (string.IsNullOrEmpty(DisplayText)) { SetDefaultDisplayText(); } mHasRequiredPacks = CheckRequiredMotionPacks(); // If there are no saved preferences for certain prefabs, load the default ones if (CombatantHealthBarPrefab == null) { CombatantHealthBarPrefab = Resources.Load <BasicCombatantHUD>("UI/Combatant HUD"); } if (PlayerHealthBarPrefab == null) { PlayerHealthBarPrefab = Resources.Load <BasicCombatantHUD>("UI/Player HUD"); } if (ReticlePrefab == null) { ReticlePrefab = Resources.Load <Reticle>("UI/Reticle"); } #if OOTII_CC CameraPrefab = Resources.Load <CameraController>("Camera Rig [Advanced]"); #else CameraPrefab = Resources.Load <BaseCameraRig>("Camera Rig [Orbit]"); #endif InitializeModules(); }
/// <summary> /// When we want to rotate based on the camera direction (which input does), we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateCount"></param> /// <param name="rCamera"></param> private void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (!_ForceCameraRotation) { return; } if (!IsTargetLocked) { return; } float lSpeed = 360f; Vector3 lTargetPosition = _Target.position; Combatant lTargetCombatant = _Target.GetComponent <Combatant>(); if (lTargetCombatant != null) { lTargetPosition = lTargetCombatant.CombatOrigin; } Vector3 lForward = (lTargetPosition - mMotionController.CameraRig.Transform.position).normalized; mMotionController.CameraRig.SetTargetForward(lForward, lSpeed); }
/// <summary> /// When we want to raycast based on the camera direction, we need to do it AFTER we process the camera. /// Otherwise, we can get small stutters during camera rotation. /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateIndex"></param> /// <param name="rCamera"></param> protected void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (!mIsShuttingDown) { bool lIsClicked = false; // Determine if we're done choosing a target if (!_ContinuousSelect && mInputSource != null && mInputSource.IsJustPressed(_ActionAlias)) { lIsClicked = true; } // Determine if we should actively look for a target if (_ContinuousSelect || lIsClicked) { bool lRayHit = Raycast(true); if (lRayHit) { lRayHit = ValidateTarget(); } if (!lRayHit) { if (mSelectedTarget != null) { RemoveMaterial(mSelectedTarget.gameObject, mMaterialInstance); } mSelectedTarget = null; transform.position = new Vector3(0f, (mOwner != null ? mOwner.transform.position.y : 0f) - 200f, 0f); } } } }
/// <summary> /// Awake is called when the script instance is being loaded. /// </summary> public override void Awake() { base.Awake(); // We extract the camera so we can tap into the events. Otherwise, our raycast values will // refer to the last frame's position and we'll get stuttering if (!_UseMouse && TargetingReticle.Instance != null) { mCameraRig = BaseCameraRig.ExtractCameraRig(TargetingReticle.Instance.RaycastRoot); } }
/// <summary> /// When we want to raycast based on the camera direction, we need to do it AFTER we process the camera. /// Otherwise, we can get small stutters during camera rotation. /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateIndex"></param> /// <param name="rCamera"></param> protected void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (!mIsShuttingDown) { bool lRayHit = Raycast(true); if (lRayHit) { ValidatePosition(); } } }
/// <summary> /// When we want to rotate based on the camera direction (which input does), we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateCount"></param> /// <param name="rCamera"></param> private void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (mMotionController._CameraTransform == null) { return; } // Get out early if we we aren't modifying the view. if (mMotionController._InputSource != null && mMotionController._InputSource.ViewX == 0f) { return; } // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space. Quaternion lInvTilt = QuaternionExt.FromToRotation(mMotionController._Transform.up, Vector3.up); // Forward direction of the actor in "natural up" Vector3 lControllerForward = lInvTilt * mMotionController._Transform.forward; // Camera forward in "natural up" Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward; // Create a quaternion that gets us from our world-forward to our camera direction. Quaternion lToCamera = Quaternion.LookRotation(lCameraForward, Vector3.up); // Transform joystick from world space to camera space. Now the input is relative // to how the camera is facing. Vector3 lMoveDirection = lToCamera * mMotionController.State.InputForward; float lInputFromAvatarAngle = NumberHelper.GetHorizontalAngle(lControllerForward, lMoveDirection); // Clear the link if we're out of rotation range if (Mathf.Abs(lInputFromAvatarAngle) > _RotationSpeed * rDeltaTime * 5f) { mIsRotationLocked = false; } // We only want to do this is we're very very close to the desired angle. This will remove any stuttering if (_RotationSpeed == 0f || mIsRotationLocked || Mathf.Abs(lInputFromAvatarAngle) < _RotationSpeed * rDeltaTime * 1f) { mIsRotationLocked = true; // Since we're after the camera update, we have to force the rotation outside the normal flow Quaternion lRotation = Quaternion.AngleAxis(lInputFromAvatarAngle, Vector3.up); mActorController.Yaw = mActorController.Yaw * lRotation; mActorController._Transform.rotation = mActorController.Tilt * mActorController.Yaw; } }
/// <summary> /// Creates the Input Source, Camera and Game Core, assigns references, and sets the player's Layer and Tag /// </summary> /// <param name="rMotionController"></param> protected virtual void SetupPlayer(MotionController rMotionController) { // Find or create the input source GameObject lInputSourceGO = InputSetupHelper.GetOrCreateInputSource(ViewActivator); rMotionController.InputSourceOwner = lInputSourceGO; // Find or create the camera BaseCameraRig lCameraRig = CameraSetupHelper.FindSceneCameraRig(); if (lCameraRig == null) { lCameraRig = CreateCameraRig(); } rMotionController.CameraTransform = lCameraRig.transform; ReflectionHelper.SetProperty(lCameraRig, "InputSourceOwner", lInputSourceGO); if (UseCameraAnchor) { GameObject lCameraAnchorGO = null; BaseCameraAnchor lCameraAnchor = CameraSetupHelper.GetOrCreateCameraAnchor(out lCameraAnchorGO); lCameraAnchor.Root = rMotionController.gameObject.transform; lCameraAnchor.RootOffset = AnchorTargetOffset; lCameraAnchor.RotateWithTarget = AnchorRotatesWithTarget; if (AnchorRotatesWithTarget) { lCameraAnchor.RotationRoot = rMotionController.gameObject.transform; } lCameraAnchor.MovementLerp = AnchorMovementLerp; lCameraRig.Anchor = lCameraAnchorGO.transform; } else { CameraSetupHelper.DisableCameraAnchors(); lCameraRig.Anchor = rMotionController.transform; } if (AddGameCore) { SceneSetupHelper.ConfigureGameCore(lInputSourceGO); } // Set player's layer and tag rMotionController.gameObject.layer = PlayerLayer; rMotionController.gameObject.tag = "Player"; }
/// <summary> /// When we want to rotate based on the camera direction (which input does), we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateCount"></param> /// <param name="rCamera"></param> protected virtual void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (!_RotateWithCamera) { return; } if (_RequireTarget && mCombatant != null && mCombatant.IsTargetLocked) { return; } // Get out early if we we aren't modifying the view. if (mMotionController._InputSource != null && mMotionController._InputSource.ViewX == 0f) { return; } // We do the inverse tilt so we calculate the rotation in "natural up" space vs. "actor up" space. Quaternion lInvTilt = QuaternionExt.FromToRotation(mMotionController._Transform.up, Vector3.up); // Forward direction of the actor in "natural up" Vector3 lActorForward = lInvTilt * mMotionController._Transform.forward; // Camera forward in "natural up" Vector3 lCameraForward = lInvTilt * mMotionController._CameraTransform.forward; // Get the rotation angle to the camera float lActorToCameraAngle = NumberHelper.GetHorizontalAngle(lActorForward, lCameraForward); // Clear the link if we're out of rotation range if (Mathf.Abs(lActorToCameraAngle) > _RotationSpeed * rDeltaTime * 5f) { mIsRotationLocked = false; } // We only want to do this is we're very very close to the desired angle. This will remove any stuttering if (_RotationSpeed == 0f || mIsRotationLocked || Mathf.Abs(lActorToCameraAngle) < _RotationSpeed * rDeltaTime * 1f) { mIsRotationLocked = true; // Since we're after the camera update, we have to force the rotation outside the normal flow Quaternion lRotation = Quaternion.AngleAxis(lActorToCameraAngle, Vector3.up); mActorController.Yaw = mActorController.Yaw * lRotation; mActorController._Transform.rotation = mActorController.Tilt * mActorController.Yaw; } }
/// <summary> /// When we want to rotate based on the camera direction, we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateCount"></param> /// <param name="rCamera"></param> private void OnCameraUpdated(float rDeltaTime, int rUpdateCount, BaseCameraRig rCamera) { if (mMotionController._CameraTransform == null) { return; } float lToCameraAngle = Vector3Ext.HorizontalAngleTo(mMotionController._Transform.forward, mMotionController._CameraTransform.forward, mMotionController._Transform.up); float lRotationAngle = Mathf.Abs(lToCameraAngle); float lRotationSign = Mathf.Sign(lToCameraAngle); if (!mLinkRotation && lRotationAngle <= (_RotationSpeed / 60f) * TimeManager.Relative60FPSDeltaTime) { mLinkRotation = true; } // Record the velocity for our idle pivoting if (lRotationAngle < 1f) { float lVelocitySign = Mathf.Sign(mYawVelocity); mYawVelocity = mYawVelocity - (lVelocitySign * rDeltaTime * 10f); if (Mathf.Sign(mYawVelocity) != lVelocitySign) { mYawVelocity = 0f; } } else { mYawVelocity = lRotationSign * 12f; } // If we're not linked, rotate smoothly if (!mLinkRotation) { lToCameraAngle = lRotationSign * Mathf.Min((_RotationSpeed / 60f) * TimeManager.Relative60FPSDeltaTime, lRotationAngle); } Quaternion lRotation = Quaternion.AngleAxis(lToCameraAngle, Vector3.up); mActorController.Yaw = mActorController.Yaw * lRotation; mActorController._Transform.rotation = mActorController.Tilt * mActorController.Yaw; }
/// <summary> /// Get the active camera rig based on the current configuration /// </summary> /// <returns></returns> protected virtual BaseCameraRig CreateCameraRig() { BaseCameraRig lCameraRig = null; if (UseCameraPrefab && CameraPrefab != null) { lCameraRig = CameraSetupHelper.InstantiateCamera(CameraPrefab); } else { #if OOTII_CC lCameraRig = CameraSetupHelper.CreateCameraRig <CameraController>(); CameraSetupHelper.SetupThirdPersonCamera(lCameraRig); #else lCameraRig = CameraSetupHelper.CreateCameraRig <OrbitRig>(); #endif } return(lCameraRig); }
/// <summary> /// When we want to rotate based on the camera direction, we need to tweak the actor /// rotation AFTER we process the camera. Otherwise, we can get small stutters during camera rotation. /// /// This is the only way to keep them totally in sync. It also means we can't run any of our AC processing /// as the AC already ran. So, we do minimal work here /// </summary> /// <param name="rDeltaTime"></param> /// <param name="rUpdateIndex"></param> /// <param name="rCamera"></param> protected void OnCameraUpdated(float rDeltaTime, int rUpdateIndex, BaseCameraRig rCamera) { if (mMotionController._CameraTransform == null) { return; } // Grab the angle needed to get to our target forward Vector3 lActorInputForward = rCamera._Transform.rotation * mStoredInputForward; float lInputFromAvatar = NumberHelper.GetHorizontalAngle(mMotionController._Transform.forward, lActorInputForward); if (lInputFromAvatar == 0f) { return; } float lInputFromSign = Mathf.Sign(lInputFromAvatar); float lInputFromAngle = Mathf.Abs(lInputFromAvatar); float lRotationAngle = mDegreesPer60FPSTick * TimeManager.Relative60FPSDeltaTime; // Break the link if we have too far to rotate if (lInputFromAngle > lRotationAngle * _LinkFactor) { mIsLinked = false; } // Establish the link if we're close enough if (mIsLinked || lInputFromAngle < lRotationAngle) { mIsLinked = true; lRotationAngle = lInputFromAngle; } // Use the information and AC to determine our final rotation Quaternion lRotation = Quaternion.AngleAxis(lInputFromSign * lRotationAngle, Vector3.up); mActorController.Yaw = mActorController.Yaw * lRotation; mActorController._Transform.rotation = mActorController.Tilt * mActorController.Yaw; }
/// <summary> /// Configure the camera rig with the default Third Person Camera settings /// </summary> /// <param name="rBaseCameraRig"></param> public static void SetupThirdPersonCamera(BaseCameraRig rBaseCameraRig) { CameraController lController = (CameraController)rBaseCameraRig; if (lController == null) { return; } lController.AnchorOffset = new Vector3(0, 1.8f, 0); // First disable all camera motors so they can be reset for (int i = 0; i < lController.Motors.Count; i++) { lController.Motors[i]._IsActive = false; lController.Motors[i].IsEnabled = false; if (i < lController.MotorDefinitions.Count) { lController.MotorDefinitions[i] = lController.Motors[i].SerializeMotor(); } } lController.IsCollisionsEnabled = true; // Follow motor OrbitFollowMotor lMotor = lController.GetMotor <OrbitFollowMotor>("3rd Person Follow"); if (lMotor == null) { lMotor = new OrbitFollowMotor(); lController.Motors.Add(lMotor); lController.MotorDefinitions.Add(""); lMotor.Name = "3rd Person Follow"; lMotor.RigController = lController; lMotor.MaxDistance = 3f; } lMotor.IsEnabled = true; lController.EditorMotorIndex = lController.Motors.IndexOf(lMotor); lController.MotorDefinitions[lController.EditorMotorIndex] = lMotor.SerializeMotor(); lController._ActiveMotorIndex = lController.EditorMotorIndex; // Fixed motor OrbitFixedMotor lMotor2 = lController.GetMotor <OrbitFixedMotor>("3rd Person Fixed"); if (lMotor2 == null) { lMotor2 = new OrbitFixedMotor(); lController.Motors.Add(lMotor2); lController.MotorDefinitions.Add(""); lMotor2.Name = "3rd Person Fixed"; lMotor2.RigController = lController; lMotor2.MaxDistance = 3f; } lMotor2.IsEnabled = true; lController.MotorDefinitions[lController.Motors.IndexOf(lMotor2)] = lMotor2.SerializeMotor(); // Targeting motor OrbitFixedMotor lMotor3 = lController.GetMotor <OrbitFixedMotor>("Targeting"); if (lMotor3 == null) { lMotor3 = new OrbitFixedMotor(); lController.Motors.Add(lMotor3); lController.MotorDefinitions.Add(""); lMotor3.Name = "Targeting"; lMotor3.RigController = lController; lMotor3.Offset = new Vector3(0.5f, 0f, 0f); lMotor3.MaxDistance = 1f; lMotor3.RotateAnchor = true; lMotor3.RotateAnchorAlias = "Camera Rotate Character"; } lMotor3.IsEnabled = true; lController.MotorDefinitions[lController.Motors.IndexOf(lMotor3)] = lMotor3.SerializeMotor(); // Targeting In transition TransitionMotor lTransition = lController.GetMotor <TransitionMotor>("Targeting In"); if (lTransition == null) { lTransition = new TransitionMotor(); lController.Motors.Add(lTransition); lController.MotorDefinitions.Add(""); lTransition.Name = "Targeting In"; lTransition.RigController = lController; lTransition.ActionAlias = "Camera Aim"; lTransition.ActionAliasEventType = 0; lTransition.StartMotorIndex = 0; lTransition.EndMotorIndex = 2; lTransition.TransitionTime = 0.15f; lTransition.ActorStances = "2,10,15"; } lTransition.IsEnabled = true; lController.MotorDefinitions[lController.Motors.IndexOf(lTransition)] = lTransition.SerializeMotor(); // Targeting out transition TransitionMotor lTransition2 = lController.GetMotor <TransitionMotor>("Targeting Out"); if (lTransition2 == null) { lTransition2 = new TransitionMotor(); lController.Motors.Add(lTransition2); lController.MotorDefinitions.Add(""); lTransition2.Name = "Targeting Out"; lTransition2.RigController = lController; lTransition2.ActionAlias = "Camera Aim"; lTransition2.ActionAliasEventType = 1; lTransition2.StartMotorIndex = 2; lTransition2.EndMotorIndex = 0; lTransition2.TransitionTime = 0.25f; } lTransition2.IsEnabled = true; lController.MotorDefinitions[lController.Motors.IndexOf(lTransition2)] = lTransition2.SerializeMotor(); // Set to "Advanced" properties lController.EditorTabIndex = 1; }