コード例 #1
0
    ////////////////////////////////////////////////////////////////

    public void OnPlayerLeftAnchorZone(CameraAnchorZone anchorZone)
    {
        //Debug.Log("Exit Anchor Zone");

        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        m_PreviousScaleFactor = m_ZoomFactor;
        m_DesiredScaleFactor  = 1.0f;
        m_ZoomTimeRemaining   = assetDataCamera.ZoomTime;

        if (m_CurrentAnchorZone != anchorZone)
        {
            // Valid Case: If two zones are close by, it can happen that we first enter the new zone, then leave the old zone. Unity Events I guess.
            return;
        }

        ////////////////////////////////////////////////////////////////

        m_CurrentAnchorZone?.SetCameraCollidersActive(false);

        m_CurrentAnchorZone = null;

        if (m_CameraMode != CameraModes.LockOnPlayer)
        {
            SetCameraMode(CameraModes.TransitionToFocusPlayer);
        }
    }
コード例 #2
0
    ////////////////////////////////////////////////////////////////

    public void TickTrauma()
    {
        if (m_CurrentTrauma == 0.0f)
        {
            return;
        }

        ////////////////////////////////////////////////////////////////

        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        m_CurrentTrauma -= assetDataCamera.ReduceTraumaPerTickBy;

        if (m_CurrentTrauma <= 0.0f)
        {
            // End Trauma!
            ResetTrauma();
            m_Camera.transform.localPosition = Vector3.zero;
            return;
        }

        m_CurrentSmoothedTrauma = Mathf.Lerp(m_CurrentSmoothedTrauma, m_CurrentTrauma, 0.2f);

        float currentTraumaSQ = m_CurrentSmoothedTrauma * m_CurrentSmoothedTrauma;

        float noise1 = Mathf.PerlinNoise(Time.time * assetDataCamera.ScreenShakeSpeed, 0.0f) * assetDataCamera.ScreenShakeMaxAmountX - assetDataCamera.ScreenShakeMaxAmountX / 2.0f;
        float noise2 = Mathf.PerlinNoise(0.0f, Time.time * assetDataCamera.ScreenShakeSpeed) * assetDataCamera.ScreenShakeMaxAmountY - assetDataCamera.ScreenShakeMaxAmountY / 2.0f;

        Vector2 screenShakePositionOffset = new Vector2(currentTraumaSQ * noise1, currentTraumaSQ * noise2);

        m_Camera.transform.localPosition = screenShakePositionOffset.To3D_Z();
    }
コード例 #3
0
ファイル: ParallaxManager.cs プロジェクト: Ranackk/Plokoth
    ////////////////////////////////////////////////////////////////

    void SetupParallaxLayers()
    {
        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();
        SceneContext    context         = SceneContext.MetaContext();

        m_ParallaxCoreObject = new GameObject("~ ParallaxRenderer");
        m_ParallaxCoreObject.transform.parent = GameCore.Get().transform;

        for (int i = 0; i < assetDataCamera._ParallaxMaxLayers; i++)
        {
            GameObject parallaxObject = new GameObject("Layer " + i);
            parallaxObject.transform.parent = m_ParallaxCoreObject.transform;
            SpriteRenderer spriteRenderer = parallaxObject.AddComponent <SpriteRenderer>();
            spriteRenderer.sprite           = null;
            spriteRenderer.sortingLayerName = "Background";
            spriteRenderer.sortingOrder     = i;
            spriteRenderer.drawMode         = SpriteDrawMode.Tiled;
            spriteRenderer.tileMode         = SpriteTileMode.Continuous;

            ParallaxLayer layer = new ParallaxLayer()
            {
                Renderer     = spriteRenderer,
                DimensionsWS = Vector2.one
            };

            m_ParallaxLayers.Add(layer);
        }

        context.Unset();
    }
コード例 #4
0
    ////////////////////////////////////////////////////////////////

    void TickCameraScale()
    {
        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        if (m_ZoomTimeRemaining > 0.0f)
        {
            m_ZoomTimeRemaining -= Time.fixedDeltaTime;

            float newScaleFactor = Mathf.LerpAngle(m_PreviousScaleFactor, m_DesiredScaleFactor, 1.0f - (m_ZoomTimeRemaining / assetDataCamera.ZoomTime));
            SetCameraZoom(newScaleFactor);
        }
    }
コード例 #5
0
    ////////////////////////////////////////////////////////////////

    public void OnPlayerEnteredAnchorZone(CameraAnchorZone anchorZone)
    {
        //Debug.Log("Enter Anchor Zone");

        m_CurrentAnchorZone?.SetCameraCollidersActive(false);
        m_CurrentAnchorZone = anchorZone;
        SetCameraMode(CameraModes.TransitionToAnchorZone);

        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        m_PreviousScaleFactor = m_ZoomFactor;
        m_DesiredScaleFactor  = anchorZone.CameraZoom;
        m_ZoomTimeRemaining   = assetDataCamera.ZoomTime;
        anchorZone.SetCameraCollidersActive(true);
    }
コード例 #6
0
    ////////////////////////////////////////////////////////////////

    public override void Initialize()
    {
        JSDK.Events.EventManager.Get().AddListener <PlayerResetEvent>(OnPlayerReset);
        JSDK.Events.EventManager.Get().AddListener <PlayerDeathEvent>(OnPlayerDeath);

        m_CameraMode        = CameraModes.FocusPlayer;
        m_CurrentAnchorZone = null;

        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        {
            SceneContext context = SceneContext.MetaContext();
            m_Camera       = Camera.main;
            m_CameraHolder = m_Camera.transform.parent.gameObject;
            m_BaseSizeY    = assetDataCamera.SizeY / 2.0f;
            m_BaseSizeX    = m_BaseSizeY * Screen.width / (float)Screen.height;
            SetCameraZoom(1.0f);

            m_ScreenEffectRenderer = m_CameraHolder.GetComponentInChildren <MeshRenderer>();
            m_ScreenEffectRenderer.transform.position = m_ScreenEffectRenderer.transform.position.xy().To3D_Z();
            context.Unset();
        }
    }
コード例 #7
0
    ////////////////////////////////////////////////////////////////

    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();
    }
コード例 #8
0
    ////////////////////////////////////////////////////////////////

    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;
            }
        }
    }
コード例 #9
0
    ////////////////////////////////////////////////////////////////

    void OnPlayerDeath(PlayerDeathEvent e)
    {
        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        AddTrauma(assetDataCamera.TraumaOnPlayerDeath);
    }
コード例 #10
0
ファイル: PlayerManager.cs プロジェクト: Ranackk/Plokoth
    ////////////////////////////////////////////////////////////////

    public void PopBlob(BlobComponent blob)
    {
        int blobHiveIndex = -1;

        for (int i = 0; i < m_BlobHives.Count; i++)
        {
            if (!m_BlobHives[i]._Hive.Equals(blob.ParentBlobHive))
            {
                continue;
            }

            blobHiveIndex = i;
            break;
        }

        if (blobHiveIndex == -1)
        {
            Debug.LogError("Could not find parent blob hive in playerManager for blob-to-be-plopped " + blob.gameObject.name);
            return;
        }

        BlobHiveData data = m_BlobHives[blobHiveIndex];

        ////////////////////////////////////////////////////////////////

        AssetDataEntities assetDataBlobs = AssetManager.GetAssetData <AssetDataEntities>();

        data._PloppedTimers[blob.ParentBlobInHiveID] = 10000;         //< We dont want plops to regrow. // assetDataBlobs.PloppedFor;

        blob.TransitionToState(BlobState.Destroyed, false);
        EventManager.Get().FireEvent(new PlaySoundEvent(Sounds.FX_SmallBlop, blob.gameObject));

        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        CameraManager.Get().AddTrauma(assetDataCamera.TraumaOnBlobPop);

        m_PlayerController.RegainDash(PlayerController.RegainDashContext.TemporaryReset);

        ////////////////////////////////////////////////////////////////
        // Check if the hive is now deactivated

        if (data._Hive.Deactivatebale)
        {
            bool deactiveBlobHive = true;
            for (int i = 0; i < data._PloppedTimers.Length; i++)
            {
                if (data._PloppedTimers[i] == 0)
                {
                    deactiveBlobHive = false;
                    break;
                }
            }

            if (deactiveBlobHive)
            {
                data._Active = false;
                data._Hive.SetRelatedObjectsActive(false);
            }
        }

        ////////////////////////////////////////////////////////////////

        m_BlobHives[blobHiveIndex] = data;
    }
コード例 #11
0
ファイル: ParallaxManager.cs プロジェクト: Ranackk/Plokoth
    ////////////////////////////////////////////////////////////////

    public void SwitchParallaxLayersToArea(AreaID newAreaID, LevelID rootLevel)
    {
        AssetDataCamera assetDataCamera = AssetManager.GetAssetData <AssetDataCamera>();

        bool success = assetDataCamera._ParallaxLayerDictionary.TryGetValue(newAreaID, out AssetDataCamera.ParallaxAreaData parallaxAreaData);

        if (!success || parallaxAreaData._LayerDatas.Count == 0)
        {
            Debug.LogError("Could not find parallaxAreaData dictionary entry for area " + newAreaID.ToString());
            return;
        }


        ////////////////////////////////////////////////////////////////

        Debug.Assert(parallaxAreaData._LayerDatas.Count <= assetDataCamera._ParallaxMaxLayers, "Area " + newAreaID.ToString() + " defines more parallax layers than _ParallaxMaxLayers allows. Consider changing that!");

        Vector2 cameraDimensionsWS = new Vector2(16.0f / 9.0f * assetDataCamera.SizeY, assetDataCamera.SizeY);

        {
            SceneContext metaContext = SceneContext.MetaContext();

            m_CurrentAreaRootWS       = parallaxAreaData.generated_AreaBoundsForParallax.position;
            m_CurrentAreaDimensionsWS = parallaxAreaData.generated_AreaBoundsForParallax.size;

            for (int i = 0; i < assetDataCamera._ParallaxMaxLayers; i++)
            {
                if (parallaxAreaData._LayerDatas.Count <= i)
                {
                    m_ParallaxLayers[i].Renderer.sprite = null;
                    m_ParallaxLayers[i].Renderer.size   = Vector2.one;
                    m_ParallaxLayers[i].DimensionsWS    = Vector2.one;
                }
                else
                {
                    /*
                     * Parallax Images come in a 4k by 4k format
                     * They always make up 100% of their parallax layers height
                     * They tile in x-Direction
                     *
                     * Parallax Layers are sized by multiplying the area size with a factor
                     * Then, a parallax renderer is scaled up to make sure that the one sprite it renders fills out the full layer.
                     * This scales influence is only for the renderer, all other logic stays the same.
                     */

                    AssetDataCamera.ParallaxLayerData layerData = parallaxAreaData._LayerDatas[i];

                    m_ParallaxLayers[i].Renderer.sprite = layerData._Sprite;

                    if (layerData._Sprite == null)
                    {
                        continue;
                    }

                    Vector2 coveredDimensionsWS = Vector2.one;
                    switch (layerData._OrientLayerSizeAt)
                    {
                    case AssetDataCamera.ParallaxLayerData.OrientSizeAt.Area:
                        coveredDimensionsWS = m_CurrentAreaDimensionsWS * layerData._LayerToAreaSizeRatio; break;

                    case AssetDataCamera.ParallaxLayerData.OrientSizeAt.Screen:
                        coveredDimensionsWS = cameraDimensionsWS * layerData._LayerToScreenSizeRatio; break;

                    default:
                        Debug.LogError("Did you miss a new enum entry here?");
                        break;
                    }

                    float rendererScaleFactor = coveredDimensionsWS.y / cameraDimensionsWS.y;

                    m_ParallaxLayers[i].Renderer.transform.localScale = Vector3.one * rendererScaleFactor;

                    // > Make it so that the sprite renderer renders the sprite exactly once in y axis
                    // > Then, we can just set the width to how wide (/scaleFactor) we want to be and tiling will do the rest for us.
                    Vector2 rendererSize = new Vector2(coveredDimensionsWS.x / rendererScaleFactor, layerData._Sprite.texture.height / layerData._Sprite.pixelsPerUnit);

                    m_ParallaxLayers[i].Renderer.size = rendererSize;
                    m_ParallaxLayers[i].DimensionsWS  = rendererSize * rendererScaleFactor;
                }
            }

            metaContext.Unset();
        }

        m_CurrentAreaID = newAreaID;

        UpdateParallaxLayerPositions();
    }