//////////////////////////////////////////////////////////////// void TickCameraModes(PlayerController player) { AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>(); // 1) Find Target Position Vector2 cameraColliderSize = GetCameraColliderSize(); Vector3 desiredFocusPosition = Vector3.zero; switch (m_CameraMode) { case CameraModes.FocusPlayer: case CameraModes.TransitionToFocusPlayer: case CameraModes.LockOnPlayer: Vector2 movementPrediction = player.SmoothMovingDirection * assetDataCamera.MovementDirectionOffsetPercentages * cameraColliderSize; desiredFocusPosition = player.transform.position + movementPrediction.To3D_Z(); break; case CameraModes.TransitionToAnchorZone: desiredFocusPosition = m_CurrentAnchorZone.GetTargetCameraPosition(cameraColliderSize, PlayerManager.Get().GetPlayerController().transform.position); break; } //////////////////////////////////////////////////////////////// // 2) Find Reachable Target Position float outSideThreshholdFactorX = 1.0f; float outSideThreshholdFactorY = 1.0f; Vector2 reachableDesiredFocusPositionWS = desiredFocusPosition; { Vector2 desiredFocusDelta = desiredFocusPosition.xy() - m_CameraHolder.transform.position.xy(); Vector2 cameraExtendsWS = m_Camera.orthographicSize * new Vector2(1.0f, 1.0f * 9.0f / 16.0f); Vector2 cameraThreshholdWS = cameraExtendsWS * new Vector2(1.0f - assetDataCamera.MoveThreshholdPercentageX, 1.0f - assetDataCamera.MoveThreshholdPercentageY); if (m_DoDebugRendering) { DebugDrawingInterface.DrawPersistentPointBox(m_CameraHolder.transform.position.xy(), 0.2f, Color.gray, m_TickEvery - 1); DebugDrawingInterface.DrawPersistentPointBox(m_FocusPosition, 0.2f, Color.white, m_TickEvery - 1); DebugDrawingInterface.DrawPersistentPointBox(reachableDesiredFocusPositionWS, 0.2f, Color.black, m_TickEvery - 1); Vector2 cameraThreshholdBottomRight = m_CameraHolder.transform.position.xy() - cameraThreshholdWS; DebugDrawingInterface.DrawPersistentLines(new List <Vector3>() { cameraThreshholdBottomRight, cameraThreshholdBottomRight + new Vector2(2 * cameraThreshholdWS.x, 0), cameraThreshholdBottomRight + new Vector2(2 * cameraThreshholdWS.x, 0), cameraThreshholdBottomRight + 2 * cameraThreshholdWS, cameraThreshholdBottomRight + 2 * cameraThreshholdWS, cameraThreshholdBottomRight + new Vector2(0, 2 * cameraThreshholdWS.y), cameraThreshholdBottomRight + new Vector2(0, 2 * cameraThreshholdWS.y), cameraThreshholdBottomRight }, Color.white, m_TickEvery - 1); DebugDrawingInterface.DrawPersistentSSText("Anchor Zone: " + m_CurrentAnchorZone?.ToString(), new Vector2(5, 85), Color.white, m_TickEvery - 1); } if (m_CameraMode == CameraModes.FocusPlayer || m_CameraMode == CameraModes.TransitionToFocusPlayer) { // Modify Target Position if we are focusing the player. float absFocusDeltaX = Mathf.Abs(desiredFocusDelta.x); float absFocusDeltaY = Mathf.Abs(desiredFocusDelta.y); bool isPlayerOutsideOfCameraThreshholdX = absFocusDeltaX > cameraThreshholdWS.x; bool isPlayerOutsideOfCameraThreshholdY = absFocusDeltaY > cameraThreshholdWS.y; outSideThreshholdFactorX = MathExtensions.Remap(absFocusDeltaX, cameraThreshholdWS.x, cameraExtendsWS.x, 1.0f, 1.5f); outSideThreshholdFactorY = MathExtensions.Remap(absFocusDeltaY, cameraThreshholdWS.y, cameraExtendsWS.y, 1.0f, 1.5f); //////////////////////////////////////////////////////////////// reachableDesiredFocusPositionWS = m_CameraHolder.transform.position; if (isPlayerOutsideOfCameraThreshholdX) { if (desiredFocusDelta.x < 0) { reachableDesiredFocusPositionWS.x -= (-cameraThreshholdWS.x - desiredFocusDelta.x); } else { reachableDesiredFocusPositionWS.x -= (cameraThreshholdWS.x - desiredFocusDelta.x); } } if (isPlayerOutsideOfCameraThreshholdY) { if (desiredFocusDelta.y < 0) { reachableDesiredFocusPositionWS.y -= (-cameraThreshholdWS.y - desiredFocusDelta.y); } else { reachableDesiredFocusPositionWS.y -= (cameraThreshholdWS.y - desiredFocusDelta.y); } } } } //////////////////////////////////////////////////////////////// // 3) Find focus position if (m_CameraMode != CameraModes.LockOnPlayer) { m_FocusPosition = new Vector2(Mathf.Lerp(m_FocusPosition.x, reachableDesiredFocusPositionWS.x, assetDataCamera.Smoothness * Time.deltaTime * outSideThreshholdFactorX), Mathf.Lerp(m_FocusPosition.y, reachableDesiredFocusPositionWS.y, assetDataCamera.Smoothness * Time.deltaTime * outSideThreshholdFactorY)); } else { m_FocusPosition = reachableDesiredFocusPositionWS; } Vector2 focusDelta = m_FocusPosition - m_CameraHolder.transform.position.xy(); //////////////////////////////////////////////////////////////// // 4) Check for reached target bool reachedTarget = (Mathf.Abs(focusDelta.x) < 0.1f) && (Mathf.Abs(focusDelta.y) < 0.1f); if (reachedTarget) { switch (m_CameraMode) { case CameraModes.LockOnPlayer: case CameraModes.FocusPlayer: break; case CameraModes.TransitionToFocusPlayer: SetCameraMode(CameraModes.FocusPlayer); break; case CameraModes.TransitionToAnchorZone: SetCameraMode(CameraModes.FocusPlayer); break; } } }
//////////////////////////////////////////////////////////////// void TickCameraMovement() { float SIGNIFICANT_MOVE = 0.01f; AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>(); //////////////////////////////////////////////////////////////// Vector2 unclampedBaseMoveVector = m_FocusPosition - m_CameraHolder.transform.position.xy(); float unclampedBaseMoveMagnitude = unclampedBaseMoveVector.magnitude; // Only for non locked modes float movementSimilarity = Vector2.Dot(m_LastLerpedCameraMove, (m_CameraHolder.transform.position.xy() - m_FocusPosition).normalized); float movementSimilarityFactor = MathExtensions.Remap(movementSimilarity, -1.0f, 1.0f, 0.1f, 1.0f); if (m_CameraMode != CameraModes.LockOnPlayer) { float lerpFactor = assetDataCamera.Smoothness2 * Time.deltaTime; unclampedBaseMoveVector = m_FocusPosition - Vector2.Lerp(m_CameraHolder.transform.position.xy(), m_FocusPosition, assetDataCamera.Smoothness2 * Time.deltaTime * movementSimilarityFactor); // m_FocusPosition - m_Camera.transform.position.xy(); unclampedBaseMoveMagnitude = unclampedBaseMoveVector.magnitude; } m_CollidedXLastTick = false; m_CollidedYLastTick = false; if (m_DoDebugRendering) { DebugDrawingInterface.DrawPersistentLine(m_CameraHolder.transform.position.xy(), m_CameraHolder.transform.position.xy() + unclampedBaseMoveVector, new Color(0.0f, 0.0f, 1.0f, 0.8f), m_TickEvery - 1); DebugDrawingInterface.DrawPersistentLine(m_FocusPosition, m_CameraHolder.transform.position.xy(), new Color(1.0f, 1.0f, 1.0f, 0.3f), m_TickEvery - 1); DebugDrawingInterface.DrawPersistentLine(m_CameraHolder.transform.position.xy(), m_CameraHolder.transform.position.xy() + m_LastLerpedCameraMove, new Color(1.0f, 0.0f, 0.0f, 0.8f), m_TickEvery - 1); DebugDrawingInterface.DrawPersistentSSText("Uncl Lerped. Delta: " + unclampedBaseMoveVector.x + ", Y " + unclampedBaseMoveVector.y, new Vector2(5, 105), Color.white, m_TickEvery - 1); DebugDrawingInterface.DrawPersistentSSText("Camera Mode: " + m_CameraMode.ToString(), new Vector2(5, 135), Color.white, m_TickEvery - 1); DebugDrawingInterface.DrawPersistentSSText("CollidedLastTick X: " + m_CollidedXLastTick.ToString() + ", Y: " + m_CollidedYLastTick.ToString(), new Vector2(5, 165), Color.white, m_TickEvery - 1); } if (Mathf.Abs(unclampedBaseMoveVector.x) < SIGNIFICANT_MOVE && Mathf.Abs(unclampedBaseMoveVector.y) < SIGNIFICANT_MOVE) { return; } //Vector2 clampedDelta = new Vector2(Mathf.Clamp(deltaX, -assetDataCamera.MaximumSpeedFreeCam, assetDataCamera.MaximumSpeedFreeCam), // Mathf.Clamp(deltaY, -assetDataCamera.MaximumSpeedFreeCam, assetDataCamera.MaximumSpeedFreeCam)); // Get colliders we collide with //Vector2 cameraCollider = GetCameraColliderSize(); //float checkDistance = assetDataCamera.MaximumSpeedFreeCam * Mathf.Sqrt(2); //m_RaycastHitCount = Physics2D.BoxCastNonAlloc(m_Camera.transform.position, cameraCollider, 0.0f, unclampedMoveVector, m_RaycastHits, checkDistance, (int) CommonLayerMasks.Camera); //int? colliderIndex = GetFirstNonTriggerCollider(m_RaycastHits, m_RaycastHitCount, ignoreAnchorCollider); //// Early Out: We do not collide with anything, so we can just move //if (!colliderIndex.HasValue) //{ // Vector2 moveVector = unclampedMoveVector; // moveVector.x = Mathf.Clamp(moveVector.x, -assetDataCamera.MaximumSpeedFreeCam, assetDataCamera.MaximumSpeedFreeCam); // moveVector.y = Mathf.Clamp(moveVector.y, -assetDataCamera.MaximumSpeedFreeCam, assetDataCamera.MaximumSpeedFreeCam); // m_Camera.transform.position += moveVector.To3D_Z(); // return; //} //////////////////////////////////////////////////////////////// // 2) Perform movement along these axes bool ignoreAnchorColliders = m_CameraMode == CameraModes.TransitionToAnchorZone || m_CameraMode == CameraModes.TransitionToFocusPlayer || m_CameraMode == CameraModes.LockOnPlayer; Vector2 moveAxisMain = Vector2.right; Vector2 moveAxisSecondary = Vector2.up; Vector2 moveMain = moveAxisMain * Vector2.Dot(unclampedBaseMoveVector, moveAxisMain); Vector2 moveSecondary = moveAxisSecondary * Vector2.Dot(unclampedBaseMoveVector, moveAxisSecondary); Vector2 newPosition = m_CameraHolder.transform.position.xy(); // Movement Main (X only at the moment) bool performMovementMain = Mathf.Abs(moveMain.x) > SIGNIFICANT_MOVE; if (performMovementMain) { Vector2 validPositionAfterMove = newPosition + moveMain; // Move the full move ? float paddingX = m_BaseSizeX * 1.0f / m_ZoomFactor; m_RaycastHitCount = Physics2D.RaycastNonAlloc(newPosition, moveMain, m_RaycastHits, paddingX + moveMain.magnitude, (int)CommonLayerMasks.Camera); int?colliderIndex = GetFirstNonTriggerCollider(m_RaycastHits, m_RaycastHitCount, ignoreAnchorColliders); if (colliderIndex.HasValue) { Debug.Assert(!m_RaycastHits[colliderIndex.Value].collider.isTrigger); //////////////////////////////////////////////////////////////// // No, we hit something: Only move until the collision! validPositionAfterMove.x = m_RaycastHits[colliderIndex.Value].point.x - (moveMain.normalized.x * paddingX); m_CollidedXLastTick = true; } newPosition = validPositionAfterMove; } // Movement Secondary (Y only at the moment) bool performMovementSecondary = Mathf.Abs(moveSecondary.y) > SIGNIFICANT_MOVE; if (performMovementSecondary) { Vector2 validPositionAfterMove = newPosition + moveSecondary; // Move the full move ? float paddingY = m_BaseSizeY * 1.0f / m_ZoomFactor; m_RaycastHitCount = Physics2D.RaycastNonAlloc(newPosition, moveSecondary, m_RaycastHits, paddingY + moveSecondary.magnitude, (int)CommonLayerMasks.Camera); int?colliderIndex = GetFirstNonTriggerCollider(m_RaycastHits, m_RaycastHitCount, ignoreAnchorColliders); if (colliderIndex.HasValue) { Debug.Assert(!m_RaycastHits[colliderIndex.Value].collider.isTrigger); //////////////////////////////////////////////////////////////// // No, we hit something: Only move until the collision! validPositionAfterMove.y = m_RaycastHits[colliderIndex.Value].point.y - (moveSecondary.normalized.y * paddingY); m_CollidedYLastTick = true; } newPosition = validPositionAfterMove; } float startSlowMoveAtDistance = 2.0f; float minMoveFactor = 0.1f; float maxMove = Mathf.Lerp(assetDataCamera.MaximumSpeedFreeCam * minMoveFactor, assetDataCamera.MaximumSpeedFreeCam, unclampedBaseMoveMagnitude / startSlowMoveAtDistance); if (m_CameraMode == CameraModes.LockOnPlayer) { maxMove *= 2.5f; } //DebugDrawingInterface.DrawPersistentSSText("MaxMove " + maxMove.ToString() + " (MoveMagnitude: " + unclampedBaseMoveMagnitude + ")", new Vector2(5, 195), Color.blue, m_TickEvery); Vector2 moveVector = newPosition - m_CameraHolder.transform.position.xy(); moveVector.x = Mathf.Clamp(moveVector.x, -maxMove, maxMove); moveVector.y = Mathf.Clamp(moveVector.y, -maxMove, maxMove); if (m_CameraMode != CameraModes.LockOnPlayer) { m_LastLerpedCameraMove = Vector2.Lerp(m_LastLerpedCameraMove.normalized, moveVector.normalized, movementSimilarityFactor); } else { m_LastLerpedCameraMove = moveVector.normalized; } m_CameraHolder.transform.position += moveVector.To3D_Z(); }
//////////////////////////////////////////////////////////////// public override void Tick() { if (m_PlayerController == null) { // Happens when no level is loaded return; } //////////////////////////////////////////////////////////////// if (m_IsResetting) { return; } //////////////////////////////////////////////////////////////// if (GameCore.Get().GetManager <PhysicsManager>().IsPhysicsSimulationPaused()) { return; } //////////////////////////////////////////////////////////////// // Debug: Tick only every x ticks! if (GameCore.Get().GetCurrentTickCalls() % m_Debug_UpdatePlayerEvery != 0) { return; } //////////////////////////////////////////////////////////////// PlokothInput input = GameCore.Get().GetInput(); if (Input.GetKeyDown(KeyCode.Tab) || Input.GetKeyDown(KeyCode.JoystickButton6)) { StatisticManager.Get().ToggleDrawStats(); } //////////////////////////////////////////////////////////////// // Shall we start the game? if (m_GameState == GameState.Pregameplay) { bool startGameplay = Input.anyKeyDown || input.Player.Jump.ReadValue <float>() != 0.0f || input.Player.Dash.ReadValue <float>() != 0.0f || input.Player.StickDirection.ReadValue <Vector2>().x != 0.0f || input.Player.StickDirection.ReadValue <Vector2>().y != 0.0f; if (!startGameplay) { return; } m_GameState = GameState.Cutscene; //////////////////////////////////////////////////////////////// LogoFadeHandler introLogo = GameObject.FindObjectOfType <LogoFadeHandler>(); if (!introLogo) { Debug.LogError("Could not find introLogo object"); return; } introLogo.StartLogoFade(); } if (m_GameState == GameState.Cutscene) { return; } //////////////////////////////////////////////////////////////// m_PlayerController.Tick(); TickPlatforms(); TickSpawnPoints(); TickBlobs(); TickResetPlants(); if (m_CurrentPlayerSpawnPoint != null && m_DrawCurrentSpawnID) { DebugDrawingInterface.DrawPersistentSSText("SavePoint " + m_CurrentPlayerSpawnPoint._LevelID.ToString() + "_" + m_CurrentPlayerSpawnPoint.Index, new Vector2(Screen.width - 200, 5), Color.white, m_Debug_UpdatePlayerEvery); } }