154 lines
6.4 KiB
C#
154 lines
6.4 KiB
C#
using System.Collections.Generic;
|
|
using Core.Domain;
|
|
using UnityEngine;
|
|
|
|
namespace Infrastructure.Unity
|
|
{
|
|
public class LevelGenerator : MonoBehaviour
|
|
{
|
|
[Header("Prefabs")]
|
|
[SerializeField] private TileViewAdapter tilePrefab;
|
|
[SerializeField] private ParticleSystem tileBreakVfxPrefab;
|
|
[SerializeField] private JumpPadAdapter jumpPadPrefab;
|
|
[SerializeField] private TeleporterAdapter teleporterPrefab;
|
|
|
|
[Header("Settings")]
|
|
[SerializeField] private int gridSizeX = 10;
|
|
[SerializeField] private int gridSizeY = 10;
|
|
[SerializeField] private int floorsCount = 3;
|
|
[SerializeField] private float floorHeightDistance = 15f;
|
|
[SerializeField] private float decayTime = 0.5f;
|
|
[SerializeField] private float fallingTime = 2.0f;
|
|
[SerializeField] private float minimumDistanceBetweenTeleporters = 3f;
|
|
|
|
public float FloorHeightDistance => floorHeightDistance;
|
|
public int FloorsCount => floorsCount;
|
|
public int GridSizeX => gridSizeX;
|
|
public int GridSizeY => gridSizeY;
|
|
|
|
private TilePool _tilePool;
|
|
|
|
public void Generate(SoundManager soundManager, List<Tile> allTiles, Dictionary<string, TileViewAdapter> tileViews, CameraController camera, RumbleManager rumble)
|
|
{
|
|
_tilePool = new TilePool(tilePrefab, transform);
|
|
|
|
GenerateFloor(0, MapPatterns.GenerateSquare(gridSizeX, gridSizeY), soundManager, allTiles, tileViews, camera, rumble);
|
|
GenerateFloor(1, MapPatterns.GenerateDonut(gridSizeX, Mathf.FloorToInt(gridSizeX / 3f)), soundManager, allTiles, tileViews, camera, rumble);
|
|
GenerateFloor(2, MapPatterns.GenerateCircle(gridSizeX), soundManager, allTiles, tileViews, camera, rumble);
|
|
}
|
|
|
|
private void GenerateFloor(int floorIndex, List<Vector2Int> coordinates, SoundManager soundManager,
|
|
List<Tile> allTiles, Dictionary<string, TileViewAdapter> tileViews, CameraController camera, RumbleManager rumble)
|
|
{
|
|
var yOffset = -(floorIndex * floorHeightDistance);
|
|
var xOffset = gridSizeX / 2f;
|
|
var zOffset = gridSizeY / 2f;
|
|
|
|
foreach (var coord in coordinates)
|
|
{
|
|
var pos = new Vector3(coord.x - xOffset, yOffset, coord.y - zOffset);
|
|
CreateTile(pos, $"{floorIndex}_{coord.x}_{coord.y}", floorIndex, soundManager, allTiles, tileViews, camera, rumble);
|
|
}
|
|
|
|
if (floorIndex > 0 && jumpPadPrefab)
|
|
{
|
|
var validSpot = coordinates[Random.Range(0, coordinates.Count)];
|
|
var padPos = new Vector3(validSpot.x - xOffset, yOffset + 0.6f, validSpot.y - zOffset);
|
|
|
|
Instantiate(jumpPadPrefab, padPos, Quaternion.identity, transform);
|
|
}
|
|
|
|
if (floorIndex > 0 && teleporterPrefab && coordinates.Count > 5)
|
|
{
|
|
// Spawn a pair of teleporters
|
|
var indexA = Random.Range(0, coordinates.Count);
|
|
int indexB;
|
|
do
|
|
{
|
|
indexB = Random.Range(0, coordinates.Count);
|
|
} while (indexB == indexA);
|
|
|
|
var spotA = coordinates[indexA];
|
|
var spotB = coordinates[indexB];
|
|
|
|
var posA = new Vector3(spotA.x - xOffset, yOffset + 0.6f, spotA.y - zOffset);
|
|
var posB = new Vector3(spotB.x - xOffset, yOffset + 0.6f, spotB.y - zOffset);
|
|
|
|
// check if positions are not too close
|
|
if (Vector3.Distance(posA, posB) < minimumDistanceBetweenTeleporters)
|
|
{
|
|
// find a new position for teleporter B
|
|
for (var i = 0; i < coordinates.Count; i++)
|
|
{
|
|
if (i == indexA) continue;
|
|
|
|
var newSpotB = coordinates[i];
|
|
var newPosB = new Vector3(newSpotB.x - xOffset, yOffset + 0.6f, newSpotB.y - zOffset);
|
|
if (Vector3.Distance(posA, newPosB) >= minimumDistanceBetweenTeleporters)
|
|
{
|
|
posB = newPosB;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var telA = Instantiate(teleporterPrefab, posA, Quaternion.identity, transform);
|
|
var telB = Instantiate(teleporterPrefab, posB, Quaternion.identity, transform);
|
|
|
|
telA.Initialize(telB.transform);
|
|
telB.Initialize(telA.transform);
|
|
|
|
System.Action onTeleport = () =>
|
|
{
|
|
camera?.Shake(0.2f, 0.2f);
|
|
rumble?.PulseMedium();
|
|
};
|
|
|
|
telA.OnTeleport += onTeleport;
|
|
telB.OnTeleport += onTeleport;
|
|
}
|
|
}
|
|
|
|
private void CreateTile(Vector3 position, string id, int floorIndex, SoundManager soundManager,
|
|
List<Tile> allTiles, Dictionary<string, TileViewAdapter> tileViews, CameraController camera, RumbleManager rumble)
|
|
{
|
|
var go = _tilePool.Get();
|
|
go.transform.position = position;
|
|
go.transform.rotation = Quaternion.identity;
|
|
go.transform.localScale = Vector3.one * 0.95f;
|
|
|
|
// 15% chance to be Fragile
|
|
var isFragile = Random.value < 0.15f;
|
|
var type = isFragile ? TileType.Fragile : TileType.Normal;
|
|
|
|
var tileLogic = new Tile(id, floorIndex, decayTime, fallingTime, type);
|
|
|
|
go.Initialize(tileLogic, (t) => _tilePool.Return(t));
|
|
|
|
tileLogic.OnStateChanged += (t) =>
|
|
{
|
|
if (t.CurrentState == TileState.Warning)
|
|
{
|
|
soundManager?.PlayTileWarning(position);
|
|
}
|
|
else if (t.CurrentState == TileState.Falling)
|
|
{
|
|
soundManager?.PlayTileBreak(position);
|
|
if (t.Type == TileType.Fragile)
|
|
{
|
|
camera?.Shake(0.1f, 0.05f);
|
|
rumble?.PulseLight();
|
|
}
|
|
|
|
if (tileBreakVfxPrefab)
|
|
{
|
|
Instantiate(tileBreakVfxPrefab, position, Quaternion.identity);
|
|
}
|
|
}
|
|
};
|
|
|
|
allTiles.Add(tileLogic);
|
|
tileViews.Add(id, go);
|
|
}
|
|
}
|
|
} |