diff --git a/Backyard CTF/Assets/Scripts/Game.cs b/Backyard CTF/Assets/Scripts/Game.cs index dc11de8..e49a7d4 100644 --- a/Backyard CTF/Assets/Scripts/Game.cs +++ b/Backyard CTF/Assets/Scripts/Game.cs @@ -15,17 +15,39 @@ public class Game : MonoBehaviour gameGO.AddComponent(); } - // Constants - tune later + // =========================================== + // CONFIGURATION - All tunable constants here + // =========================================== + + // Gameplay + public const int UnitsPerTeam = 3; public const float UnitSpeed = 5f; + public const float UnitSize = 1f; + public const float UnitColliderRadius = 0.5f; + + // Vision & Detection public const float VisionRadius = 4f; public const float TagRadius = 0.75f; - public const float RespawnDelay = 3f; + public const float FlagPickupRadius = 0.75f; + + // Timing + public const float RespawnDelay = 5f; public const float FlagReturnDelay = 5f; + + // Scoring public const int WinScore = 3; - // Map dimensions - const float MapWidth = 40f; - const float MapHeight = 30f; + // Map - 9:19 aspect ratio for smartphone (portrait) + public const float MapWidth = 18f; + public const float MapHeight = 38f; + + // Bases + public const float BaseSize = 5f; + public const float BaseInset = 4f; // Distance from map edge + + // Houses + public const float HouseMinSize = 2f; + public const float HouseMaxSize = 4f; // References set during setup public static Game Instance { get; private set; } @@ -82,33 +104,79 @@ public class Game : MonoBehaviour void CreateObstacles() { - // Houses as obstacles - asymmetric backyard layout + // Dense house layout creating multiple route choices + // Layout designed for 18x38 map with bases at corners + // Houses create lanes, chokepoints, and flanking routes + Vector2[] housePositions = { - new(-12f, 8f), - new(-8f, -5f), - new(0f, 3f), - new(5f, -8f), - new(10f, 6f), - new(14f, -3f), + // Bottom section (near player base) - create 3 exit routes + new(-4f, -14f), + new(4f, -12f), + new(0f, -10f), + + // Lower-mid section - force route decisions + new(-6f, -6f), + new(-2f, -4f), + new(3f, -7f), + new(6f, -3f), + + // Center section - dense, creates cat-and-mouse area + new(-5f, 2f), + new(-1f, 0f), + new(2f, 3f), + new(5f, -1f), + new(0f, 5f), + + // Upper-mid section - mirror complexity + new(-6f, 8f), + new(-2f, 10f), + new(4f, 7f), + new(6f, 11f), + + // Top section (near enemy base) - create 3 approach routes + new(-4f, 14f), + new(0f, 12f), + new(5f, 15f), }; Vector2[] houseSizes = { - new(4f, 3f), - new(3f, 4f), - new(5f, 2.5f), - new(3f, 3f), - new(4f, 4f), - new(3.5f, 3f), + // Bottom section + new(3f, 2.5f), + new(2.5f, 3f), + new(2f, 2f), + + // Lower-mid + new(2.5f, 3f), + new(3f, 2f), + new(2f, 2.5f), + new(2.5f, 2.5f), + + // Center - varied sizes for interesting gaps + new(3f, 2f), + new(2f, 3f), + new(2.5f, 2f), + new(2f, 2.5f), + new(2f, 2f), + + // Upper-mid + new(2.5f, 2.5f), + new(2f, 3f), + new(3f, 2.5f), + new(2f, 2f), + + // Top section + new(2.5f, 3f), + new(3f, 2f), + new(2f, 2.5f), }; for (int i = 0; i < housePositions.Length; i++) { - var house = CreateSprite($"House_{i}", new Color(0.4f, 0.4f, 0.4f), houseSizes[i].x, houseSizes[i].y); + var house = CreateSprite($"House_{i}", new Color(0.35f, 0.35f, 0.4f), houseSizes[i].x, houseSizes[i].y); house.transform.position = new Vector3(housePositions[i].x, housePositions[i].y, 0); var collider = house.AddComponent(); - // Size is (1,1) in local space - scale handles actual size - collider.size = Vector2.one; + collider.size = Vector2.one; // Local space - scale handles actual size var sr = house.GetComponent(); sr.sortingOrder = -5; @@ -117,30 +185,30 @@ public class Game : MonoBehaviour void CreateBases() { - // Player base - bottom left - var playerBaseGO = CreateSprite("PlayerBase", new Color(0.2f, 0.3f, 0.8f, 0.5f), 6f, 6f); - playerBaseGO.transform.position = new Vector3(-MapWidth / 2f + 5f, -MapHeight / 2f + 5f, 0); + // Player base - bottom center + var playerBaseGO = CreateSprite("PlayerBase", new Color(0.2f, 0.3f, 0.8f, 0.5f), BaseSize, BaseSize); + playerBaseGO.transform.position = new Vector3(0, -MapHeight / 2f + BaseInset, 0); playerBase = playerBaseGO.transform; var sr1 = playerBaseGO.GetComponent(); sr1.sortingOrder = -8; var playerBaseTrigger = playerBaseGO.AddComponent(); playerBaseTrigger.isTrigger = true; - playerBaseTrigger.size = Vector2.one; // Local space - scale handles actual size + playerBaseTrigger.size = Vector2.one; var playerBaseZone = playerBaseGO.AddComponent(); playerBaseZone.team = Unit.Team.Player; - // Enemy base - top right - var enemyBaseGO = CreateSprite("EnemyBase", new Color(0.8f, 0.2f, 0.2f, 0.5f), 6f, 6f); - enemyBaseGO.transform.position = new Vector3(MapWidth / 2f - 5f, MapHeight / 2f - 5f, 0); + // Enemy base - top center + var enemyBaseGO = CreateSprite("EnemyBase", new Color(0.8f, 0.2f, 0.2f, 0.5f), BaseSize, BaseSize); + enemyBaseGO.transform.position = new Vector3(0, MapHeight / 2f - BaseInset, 0); enemyBase = enemyBaseGO.transform; var sr2 = enemyBaseGO.GetComponent(); sr2.sortingOrder = -8; var enemyBaseTrigger = enemyBaseGO.AddComponent(); enemyBaseTrigger.isTrigger = true; - enemyBaseTrigger.size = Vector2.one; // Local space - scale handles actual size + enemyBaseTrigger.size = Vector2.one; var enemyBaseZone = enemyBaseGO.AddComponent(); enemyBaseZone.team = Unit.Team.Enemy; @@ -157,7 +225,7 @@ public class Game : MonoBehaviour var flagCollider1 = playerFlagGO.AddComponent(); flagCollider1.isTrigger = true; - flagCollider1.radius = 0.75f; + flagCollider1.radius = FlagPickupRadius; var rb1 = playerFlagGO.AddComponent(); rb1.bodyType = RigidbodyType2D.Kinematic; @@ -174,7 +242,7 @@ public class Game : MonoBehaviour var flagCollider2 = enemyFlagGO.AddComponent(); flagCollider2.isTrigger = true; - flagCollider2.radius = 0.75f; + flagCollider2.radius = FlagPickupRadius; var rb2 = enemyFlagGO.AddComponent(); rb2.bodyType = RigidbodyType2D.Kinematic; @@ -185,27 +253,35 @@ public class Game : MonoBehaviour void SpawnUnits() { - // Spawn 5 player units near player base - for (int i = 0; i < 5; i++) + // Spawn player units near player base + for (int i = 0; i < UnitsPerTeam; i++) { - var offset = new Vector3((i - 2) * 1.5f, -2f, 0); + var offset = GetUnitSpawnOffset(i, UnitsPerTeam, isPlayer: true); var unit = CreateUnit($"PlayerUnit_{i}", Unit.Team.Player, playerBase.position + offset); playerUnits.Add(unit); } - // Spawn 5 enemy units near enemy base - for (int i = 0; i < 5; i++) + // Spawn enemy units near enemy base + for (int i = 0; i < UnitsPerTeam; i++) { - var offset = new Vector3((i - 2) * 1.5f, 2f, 0); + var offset = GetUnitSpawnOffset(i, UnitsPerTeam, isPlayer: false); var unit = CreateUnit($"EnemyUnit_{i}", Unit.Team.Enemy, enemyBase.position + offset); enemyUnits.Add(unit); } } + Vector3 GetUnitSpawnOffset(int index, int total, bool isPlayer) + { + float spacing = 1.8f; + float xOffset = (index - (total - 1) / 2f) * spacing; + float yOffset = isPlayer ? -2f : 2f; + return new Vector3(xOffset, yOffset, 0); + } + Unit CreateUnit(string name, Unit.Team team, Vector3 position) { Color color = team == Unit.Team.Player ? new Color(0.3f, 0.5f, 1f) : new Color(1f, 0.3f, 0.3f); - var unitGO = CreateSprite(name, color, 1f, 1f); + var unitGO = CreateSprite(name, color, UnitSize, UnitSize); unitGO.transform.position = position; var unit = unitGO.AddComponent(); @@ -213,7 +289,7 @@ public class Game : MonoBehaviour var collider = unitGO.AddComponent(); collider.isTrigger = true; - collider.radius = 0.5f; + collider.radius = UnitColliderRadius; var rb = unitGO.AddComponent(); rb.bodyType = RigidbodyType2D.Kinematic; @@ -320,13 +396,13 @@ public class Game : MonoBehaviour // Respawn all units at bases for (int i = 0; i < playerUnits.Count; i++) { - var offset = new Vector3((i - 2) * 1.5f, -2f, 0); + var offset = GetUnitSpawnOffset(i, playerUnits.Count, isPlayer: true); playerUnits[i].ForceRespawn(playerBase.position + offset); } for (int i = 0; i < enemyUnits.Count; i++) { - var offset = new Vector3((i - 2) * 1.5f, 2f, 0); + var offset = GetUnitSpawnOffset(i, enemyUnits.Count, isPlayer: false); enemyUnits[i].ForceRespawn(enemyBase.position + offset); } }