Подробные изменения: - Добавлены сцены 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 из репозитория.
159 lines
4.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|