Danro-Jump/Assets/Scripts/Runtime/Gameplay/Spawning/PlatformContentSpawner.cs
Danil Iarosh cefb2fd345 Build initial vertical platformer foundation
Подробные изменения:
- Добавлены сцены Bootstrap, MainMenu и Game с текущей вертикальной 9:16 структурой проекта.
- Добавлены runtime-скрипты gameplay-архитектуры: DI через Extenject, спавнер платформ, прогрессия этапов, one-way платформы, игрок, камера и оборудование JumpPad.
- Добавлены ScriptableObject-этапы сложности, weighted-настройки платформ, оборудования, противников и collectibles.
- Добавлены UI Toolkit ресурсы главного меню, preview-материалы, шрифты, спрайты, анимации и игровые prefab-ассеты.
- Перенесена и оформлена новая COM-система для работы с аппаратными портами и StreamingAssets.
- Обновлены проектные гайды, AGENTS.md, правила Git/Git LFS, .gitignore, Unity Packages и ProjectSettings.
- Удалён локальный skill start-required-mcp-servers из репозитория.
2026-05-11 07:41:14 +03:00

159 lines
4.9 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using Zenject;
namespace DanroJump.Gameplay
{
public sealed class PlatformContentSpawner
{
private readonly DiContainer container;
private readonly Dictionary<PlatformController, List<GameObject>> spawnedContentByPlatform = new();
public PlatformContentSpawner(DiContainer container)
{
this.container = container;
}
public void SpawnContent(
PlatformController platform,
IPlatformContentSource catalog,
System.Random random)
{
ClearSpawnedContent(platform);
if (platform == null || catalog == null)
{
return;
}
SpawnIntoPoints(platform, catalog, PlatformContentKind.Collectible, platform.CollectibleSpawnPoints, random);
SpawnIntoPoints(platform, catalog, PlatformContentKind.Equipment, platform.EquipmentSpawnPoints, random);
SpawnIntoPoints(platform, catalog, PlatformContentKind.Enemy, platform.EnemySpawnPoints, random);
}
public void ClearSpawnedContent(PlatformController platform)
{
if (platform == null)
{
return;
}
if (!ClearTrackedContent(platform))
{
ClearOrphanSpawnedContent(platform);
}
}
public void ClearAll()
{
foreach (var platform in new List<PlatformController>(spawnedContentByPlatform.Keys))
{
ClearSpawnedContent(platform);
}
}
private void SpawnIntoPoints(
PlatformController platform,
IPlatformContentSource catalog,
PlatformContentKind kind,
IReadOnlyList<PlatformSpawnPoint> spawnPoints,
System.Random random)
{
if (spawnPoints == null || !catalog.ShouldSpawn(kind, random) || !catalog.TryGetPrefab(kind, random, out var prefab))
{
return;
}
foreach (var spawnPoint in spawnPoints)
{
if (spawnPoint == null || ShouldSkipOptionalPoint(spawnPoint, random))
{
continue;
}
Spawn(prefab, spawnPoint.Anchor, platform);
}
}
private void Spawn(GameObject prefab, Transform parent, PlatformController platform)
{
var targetParent = parent != null ? parent : platform.transform;
var instance = container.InstantiatePrefab(prefab, targetParent.position, targetParent.rotation, targetParent);
if (!instance.TryGetComponent(out PlatformSpawnedContent _))
{
instance.AddComponent<PlatformSpawnedContent>();
}
if (instance.TryGetComponent(out IPlatformEquipment equipment))
{
equipment.Install(platform);
}
if (!spawnedContentByPlatform.TryGetValue(platform, out var spawnedContent))
{
spawnedContent = new List<GameObject>();
spawnedContentByPlatform.Add(platform, spawnedContent);
}
spawnedContent.Add(instance);
}
private bool ClearTrackedContent(PlatformController platform)
{
if (!spawnedContentByPlatform.TryGetValue(platform, out var spawnedContent))
{
return false;
}
for (var index = spawnedContent.Count - 1; index >= 0; index--)
{
var content = spawnedContent[index];
if (content != null)
{
content.SetActive(false);
Object.Destroy(content);
}
}
spawnedContent.Clear();
spawnedContentByPlatform.Remove(platform);
return true;
}
private static void ClearOrphanSpawnedContent(PlatformController platform)
{
var markers = platform.GetComponentsInChildren<PlatformSpawnedContent>(true);
foreach (var marker in markers)
{
if (marker != null)
{
marker.gameObject.SetActive(false);
Object.Destroy(marker.gameObject);
}
}
}
private static bool ShouldSkipOptionalPoint(PlatformSpawnPoint spawnPoint, System.Random random)
{
if (!spawnPoint.Optional)
{
return false;
}
if (spawnPoint.Weight <= 0f)
{
return true;
}
if (spawnPoint.Weight >= 1f)
{
return false;
}
var roll = random != null ? random.NextDouble() : 0d;
return roll > spawnPoint.Weight;
}
}
}