miepzerino
2025-03-28 b7518b77da6511a396501b51b5046ed86ce8d98b
#22 Reworked background dynamic generation

Added better background tiling, dynamically generated with height in mind, automatically destroyed when out of sight
4 files modified
294 ■■■■ changed files
Assets/Scenes/GameplayScene.unity 114 ●●●● patch | view | raw | blame | history
Assets/Scripts/PlayerController.cs 4 ●●●● patch | view | raw | blame | history
Assets/Scripts/Tiling.cs 174 ●●●●● patch | view | raw | blame | history
ProjectSettings/TagManager.asset 2 ●●● patch | view | raw | blame | history
Assets/Scenes/GameplayScene.unity
@@ -1127,10 +1127,10 @@
  - {fileID: 690370498}
  m_Father: {fileID: 1633192636}
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  m_AnchorMin: {x: 0, y: 0}
  m_AnchorMax: {x: 0, y: 0}
  m_AnchoredPosition: {x: 0, y: 0}
  m_SizeDelta: {x: 0, y: 0}
  m_AnchorMin: {x: 0, y: 1}
  m_AnchorMax: {x: 0, y: 1}
  m_AnchoredPosition: {x: 799.99994, y: -475.2434}
  m_SizeDelta: {x: 999.9999, y: 650.4868}
  m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &257770452
MonoBehaviour:
@@ -1366,10 +1366,10 @@
  - {fileID: 162135952}
  m_Father: {fileID: 257770451}
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  m_AnchorMin: {x: 0, y: 0}
  m_AnchorMax: {x: 0, y: 0}
  m_AnchoredPosition: {x: 0, y: 0}
  m_SizeDelta: {x: 0, y: 0}
  m_AnchorMin: {x: 0, y: 1}
  m_AnchorMax: {x: 0, y: 1}
  m_AnchoredPosition: {x: 336.83328, y: -325.2434}
  m_SizeDelta: {x: 593.66656, y: 570.4868}
  m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &368852411
MonoBehaviour:
@@ -1602,7 +1602,7 @@
  m_Father: {fileID: 2009171746}
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  m_AnchorMin: {x: 0, y: 0}
  m_AnchorMax: {x: 0, y: 0}
  m_AnchorMax: {x: 1, y: 1}
  m_AnchoredPosition: {x: 0.000030517578, y: -0.49996948}
  m_SizeDelta: {x: 20, y: 0.80810547}
  m_Pivot: {x: 0.5, y: 0.5}
@@ -2172,10 +2172,10 @@
  m_Children: []
  m_Father: {fileID: 257770451}
  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
  m_AnchorMin: {x: 0, y: 0}
  m_AnchorMax: {x: 0, y: 0}
  m_AnchoredPosition: {x: 0, y: 0}
  m_SizeDelta: {x: 0, y: 0}
  m_AnchorMin: {x: 0, y: 1}
  m_AnchorMax: {x: 0, y: 1}
  m_AnchoredPosition: {x: 801.83325, y: -325.2434}
  m_SizeDelta: {x: 316.3333, y: 570.4868}
  m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &690370499
MonoBehaviour:
@@ -2330,7 +2330,7 @@
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
  m_IsActive: 0
--- !u!4 &734382261
Transform:
  m_ObjectHideFlags: 0
@@ -2360,6 +2360,7 @@
  m_EditorClassIdentifier: 
  offsetX: 2
  offsetY: 2
  heightSprites: []
  hasRightBuddy: 0
  hasLeftBuddy: 0
  hasTopBuddy: 1
@@ -3183,7 +3184,7 @@
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
  m_IsActive: 0
--- !u!4 &1049982787
Transform:
  m_ObjectHideFlags: 0
@@ -3213,6 +3214,7 @@
  m_EditorClassIdentifier: 
  offsetX: 2
  offsetY: 2
  heightSprites: []
  hasRightBuddy: 0
  hasLeftBuddy: 0
  hasTopBuddy: 0
@@ -3409,7 +3411,7 @@
  m_AnchorMin: {x: 0, y: 0}
  m_AnchorMax: {x: 1, y: 1}
  m_AnchoredPosition: {x: 0, y: 0}
  m_SizeDelta: {x: 0, y: 0}
  m_SizeDelta: {x: 0, y: -490.48682}
  m_Pivot: {x: 0, y: 1}
--- !u!114 &1165757303
MonoBehaviour:
@@ -3597,8 +3599,9 @@
  - component: {fileID: 1223747240}
  - component: {fileID: 1223747239}
  - component: {fileID: 1223747241}
  m_Layer: 0
  m_Name: Sky
  - component: {fileID: 1223747242}
  m_Layer: 11
  m_Name: BackgroundAll
  m_TagString: Untagged
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
@@ -3613,8 +3616,8 @@
  m_GameObject: {fileID: 1223747237}
  serializedVersion: 2
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: 68, z: -2}
  m_LocalScale: {x: 10, y: 10, z: 1}
  m_LocalPosition: {x: 0, y: 6, z: -2}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_ConstrainProportionsScale: 0
  m_Children: []
  m_Father: {fileID: 796676099}
@@ -3697,13 +3700,65 @@
  m_Script: {fileID: 11500000, guid: bff9938391d7202429e3508a7efde6eb, type: 3}
  m_Name: 
  m_EditorClassIdentifier: 
  offsetX: 2
  offsetY: 2
  offsetX: 0
  offsetY: 0
  heightSprites:
  - minHeight: 6
    maxHeight: 200
    sprite: {fileID: 21300000, guid: 7d5be99b0261348468ab492c35422f1b, type: 3}
  - minHeight: -200
    maxHeight: -8
    sprite: {fileID: 21300000, guid: 58a6eeb45a0e2674ab35114433129f28, type: 3}
  hasRightBuddy: 0
  hasLeftBuddy: 0
  hasTopBuddy: 0
  hasBottomBuddy: 1
  hasBottomBuddy: 0
  reverseScale: 1
--- !u!61 &1223747242
BoxCollider2D:
  m_ObjectHideFlags: 0
  m_CorrespondingSourceObject: {fileID: 0}
  m_PrefabInstance: {fileID: 0}
  m_PrefabAsset: {fileID: 0}
  m_GameObject: {fileID: 1223747237}
  m_Enabled: 1
  m_Density: 1
  m_Material: {fileID: 0}
  m_IncludeLayers:
    serializedVersion: 2
    m_Bits: 0
  m_ExcludeLayers:
    serializedVersion: 2
    m_Bits: 0
  m_LayerOverridePriority: 0
  m_ForceSendLayers:
    serializedVersion: 2
    m_Bits: 4294967295
  m_ForceReceiveLayers:
    serializedVersion: 2
    m_Bits: 4294967295
  m_ContactCaptureLayers:
    serializedVersion: 2
    m_Bits: 4294967295
  m_CallbackLayers:
    serializedVersion: 2
    m_Bits: 4294967295
  m_IsTrigger: 1
  m_UsedByEffector: 0
  m_UsedByComposite: 0
  m_Offset: {x: 0, y: 0}
  m_SpriteTilingProperty:
    border: {x: 0, y: 0, z: 0, w: 0}
    pivot: {x: 0.5, y: 0.5}
    oldSize: {x: 25, y: 14.0625}
    newSize: {x: 84.12234, y: 61.8624}
    adaptiveTilingThreshold: 0.349
    drawMode: 0
    adaptiveTiling: 0
  m_AutoTiling: 0
  serializedVersion: 2
  m_Size: {x: 25, y: 14.0625}
  m_EdgeRadius: 0
--- !u!1 &1235149190
GameObject:
  m_ObjectHideFlags: 0
@@ -4959,7 +5014,7 @@
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
  m_IsActive: 0
--- !u!224 &1633192636
RectTransform:
  m_ObjectHideFlags: 0
@@ -5743,7 +5798,7 @@
  m_Icon: {fileID: 0}
  m_NavMeshLayer: 0
  m_StaticEditorFlags: 0
  m_IsActive: 1
  m_IsActive: 0
--- !u!4 &2045670860
Transform:
  m_ObjectHideFlags: 0
@@ -5753,8 +5808,8 @@
  m_GameObject: {fileID: 2045670859}
  serializedVersion: 2
  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
  m_LocalPosition: {x: 0, y: -72, z: -1}
  m_LocalScale: {x: 10, y: 10, z: 1}
  m_LocalPosition: {x: 0, y: -7, z: -1}
  m_LocalScale: {x: 1, y: 1, z: 1}
  m_ConstrainProportionsScale: 0
  m_Children: []
  m_Father: {fileID: 796676099}
@@ -5839,9 +5894,10 @@
  m_EditorClassIdentifier: 
  offsetX: 2
  offsetY: 2
  heightSprites: []
  hasRightBuddy: 0
  hasLeftBuddy: 0
  hasTopBuddy: 1
  hasTopBuddy: 0
  hasBottomBuddy: 0
  reverseScale: 1
--- !u!1 &2064964499
@@ -6426,7 +6482,7 @@
      objectReference: {fileID: 0}
    - target: {fileID: 6633370595712293001, guid: e3c75e717a72154478a8806cd96eb126, type: 3}
      propertyPath: m_AnchoredPosition.x
      value: 288.33334
      value: 288.33328
      objectReference: {fileID: 0}
    - target: {fileID: 6633370595712293001, guid: e3c75e717a72154478a8806cd96eb126, type: 3}
      propertyPath: m_AnchoredPosition.y
Assets/Scripts/PlayerController.cs
@@ -154,6 +154,10 @@
    private void Awake()
    {
        if(Debug.isDebugBuild)
        {
            moveSpeed = 25f;
        }
        rb = GetComponent<Rigidbody2D>();
        animator = GetComponent<Animator>();
        animator_rotor = rotorGO.GetComponent<Animator>();
Assets/Scripts/Tiling.cs
@@ -5,8 +5,17 @@
[RequireComponent(typeof(SpriteRenderer))]
public class Tiling : MonoBehaviour
{
    [System.Serializable]
    public class HeightSpritePair
    {
        public float minHeight;
        public float maxHeight;
        public Sprite sprite;
    }
    public int offsetX = 2;
    public int offsetY = 2;
    public HeightSpritePair[] heightSprites;
    public bool hasRightBuddy = false;
    public bool hasLeftBuddy = false;
@@ -19,65 +28,198 @@
    private float spriteHeight = 0f;
    private Camera cam;
    private Transform myTransform;
    private SpriteRenderer spriteRenderer;
    private void Awake()
    {
        cam = Camera.main;
        myTransform = transform;
        spriteRenderer = GetComponent<SpriteRenderer>();
    }
    // Start is called before the first frame update
    void Start()
    {
        SpriteRenderer spriteRenderer = GetComponent<SpriteRenderer>();
        UpdateSpriteForHeight();
        spriteWidth = spriteRenderer.sprite.bounds.size.x;
        spriteHeight = spriteRenderer.sprite.bounds.size.y;
        //GenerateBackground();
    }
    // Update is called once per frame
    void Update()
    {
        if (CheckOffscreenAndDestroy()) return; // Return early if destroyed
        CheckHorizontalTiling();
        CheckVerticalTiling();
    }
    private void UpdateSpriteForHeight()
    {
        if (heightSprites == null || heightSprites.Length == 0) return;
        float worldY = transform.position.y;
        Sprite oldSprite = spriteRenderer.sprite;
        foreach (HeightSpritePair pair in heightSprites)
        {
            if (pair.sprite == null) continue; // Skip invalid sprites
            if ((pair.minHeight == 0 && pair.maxHeight == 0) ||
                (worldY >= pair.minHeight && worldY <= pair.maxHeight))
            {
                if (oldSprite != pair.sprite)
                {
                    spriteRenderer.sprite = pair.sprite;
                    // Update sprite dimensions if sprite changed
                    spriteWidth = spriteRenderer.sprite.bounds.size.x;
                    spriteHeight = spriteRenderer.sprite.bounds.size.y;
                }
                break;
            }
        }
    }
    private void CheckHorizontalTiling()
    {
        if (!hasLeftBuddy || !hasRightBuddy)
        {
            float camHorizontalExtend = cam.orthographicSize * Screen.width / Screen.height;
            float edgeVisiblePositionRight = (transform.position.x + spriteWidth / 2) - camHorizontalExtend;
            float edgeVisiblePositionLeft = (transform.position.x - spriteWidth / 2) + camHorizontalExtend;
            if (cam.transform.position.x >= edgeVisiblePositionRight - offsetX && !hasRightBuddy)
            {
                MakeNewRightOrLeftBuddy(1);
                MakeNewBuddy(1, 0);
                hasRightBuddy = true;
            }
            else if (cam.transform.position.x <= edgeVisiblePositionLeft + offsetX && !hasLeftBuddy)
            {
                MakeNewRightOrLeftBuddy(-1);
                MakeNewBuddy(-1, 0);
                hasLeftBuddy = true;
            }
        }
    }
    private void MakeNewRightOrLeftBuddy(int rightOrLeft)
    private void CheckVerticalTiling()
    {
        Vector3 newPosition = new Vector3(myTransform.position.x + spriteWidth * rightOrLeft, myTransform.position.y, myTransform.position.z);
        if (!hasTopBuddy || !hasBottomBuddy)
        {
            float camVerticalExtend = cam.orthographicSize;
            float edgeVisiblePositionTop = (transform.position.y + spriteHeight / 2) - camVerticalExtend;
            float edgeVisiblePositionBottom = (transform.position.y - spriteHeight / 2) + camVerticalExtend;
            if (cam.transform.position.y >= edgeVisiblePositionTop - offsetY && !hasTopBuddy)
            {
                MakeNewBuddy(0, 1);
                hasTopBuddy = true;
            }
            else if (cam.transform.position.y <= edgeVisiblePositionBottom + offsetY && !hasBottomBuddy)
            {
                MakeNewBuddy(0, -1);
                hasBottomBuddy = true;
            }
        }
    }
    private void MakeNewBuddy(int rightOrLeft, int topOrBottom)
    {
        Vector3 newPosition = new Vector3(
            myTransform.position.x + spriteWidth * rightOrLeft,
            myTransform.position.y + spriteHeight * topOrBottom,
            myTransform.position.z
        );
        Transform newBuddy = Instantiate(myTransform, newPosition, myTransform.rotation);
        Tiling buddyTiling = newBuddy.GetComponent<Tiling>();
        if (reverseScale)
        {
            newBuddy.localScale = new Vector3(newBuddy.localScale.x * -1, newBuddy.localScale.y, newBuddy.localScale.z);
            newBuddy.localScale = new Vector3(
                rightOrLeft != 0 ? newBuddy.localScale.x * -1 : newBuddy.localScale.x,
                topOrBottom != 0 ? newBuddy.localScale.y * -1 : newBuddy.localScale.y,
                newBuddy.localScale.z
            );
        }
        newBuddy.parent = myTransform.parent;
        newBuddy.name = myTransform.name;
        if (rightOrLeft > 0)
        if (rightOrLeft > 0) buddyTiling.hasLeftBuddy = true;
        else if (rightOrLeft < 0) buddyTiling.hasRightBuddy = true;
        if (topOrBottom > 0) buddyTiling.hasBottomBuddy = true;
        else if (topOrBottom < 0) buddyTiling.hasTopBuddy = true;
        buddyTiling.UpdateSpriteForHeight();
    }
    private bool CheckOffscreenAndDestroy()
        {
            newBuddy.GetComponent<Tiling>().hasLeftBuddy = true;
        }
        else if (rightOrLeft < 0)
        Vector3 viewportPosition = cam.WorldToViewportPoint(transform.position);
        float buffer = 1.5f;
        if (viewportPosition.x < -buffer || viewportPosition.x > 1 + buffer ||
            viewportPosition.y < -buffer || viewportPosition.y > 1 + buffer)
        {
            newBuddy.GetComponent<Tiling>().hasRightBuddy = true;
            NotifyNeighbors();
            Destroy(gameObject);
            return true;
        }
        return false;
    }
    private void NotifyNeighbors()
    {
        // Use a slightly smaller size than the sprite to ensure we only hit immediate neighbors
        Vector2 checkSize = new Vector2(spriteWidth * 0.9f, spriteHeight * 0.9f);
        Vector2 position = transform.position;
        ContactFilter2D filter = new ContactFilter2D().NoFilter();
        Collider2D[] results = new Collider2D[1];
        // Check each direction using OverlapBox
        // Right neighbor
        if (Physics2D.OverlapBox(position + new Vector2(spriteWidth, 0),
            checkSize, 0f,
            filter, results) > 0)
        {
            Tiling rightTile = results[0].GetComponent<Tiling>();
            if (rightTile != null) rightTile.hasLeftBuddy = false;
        }
        // Left neighbor
        if (Physics2D.OverlapBox(position + new Vector2(-spriteWidth, 0),
            checkSize, 0f,
            filter, results) > 0)
        {
            Tiling leftTile = results[0].GetComponent<Tiling>();
            if (leftTile != null) leftTile.hasRightBuddy = false;
        }
        // Top neighbor
        if (Physics2D.OverlapBox(position + new Vector2(0, spriteHeight),
            checkSize, 0f,
            filter, results) > 0)
        {
            Tiling topTile = results[0].GetComponent<Tiling>();
            if (topTile != null) topTile.hasBottomBuddy = false;
        }
        // Bottom neighbor
        if (Physics2D.OverlapBox(position + new Vector2(0, -spriteHeight),
            checkSize, 0f,
            filter, results) > 0)
        {
            Tiling bottomTile = results[0].GetComponent<Tiling>();
            if (bottomTile != null) bottomTile.hasTopBuddy = false;
        }
    }
    //private void OnDrawGizmos()
    //{
    //    if (!Application.isPlaying) return;
    //    Vector2 checkSize = new Vector2(spriteWidth * 0.9f, spriteHeight * 0.9f);
    //    Gizmos.color = Color.yellow;
    //    // Draw detection boxes for each direction
    //    Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(spriteWidth, 0), checkSize);
    //    Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(-spriteWidth, 0), checkSize);
    //    Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(0, spriteHeight), checkSize);
    //    Gizmos.DrawWireCube((Vector2)transform.position + new Vector2(0, -spriteHeight), checkSize);
    //}
}
ProjectSettings/TagManager.asset
@@ -16,7 +16,7 @@
  - PlayerHitbox
  - GroundDetection
  - Pickup
  -
  - Background
  - 
  - 
  -