274 lines
12 KiB
C#
274 lines
12 KiB
C#
using UnityEngine;
|
|
|
|
namespace Vanguard.App
|
|
{
|
|
public enum SceneTheme
|
|
{
|
|
Login,
|
|
Lobby,
|
|
DeckBuilder,
|
|
Battle,
|
|
}
|
|
|
|
/// <summary>
|
|
/// Простой 3D-фон для экранов: камера, свет, пол и тематические
|
|
/// примитивы. Это заготовка под будущие модели и арт; UI остаётся
|
|
/// отдельным Canvas-слоем.
|
|
/// </summary>
|
|
public static class SceneEnvironment
|
|
{
|
|
private const string RootName = "Vanguard 3D Environment";
|
|
|
|
public static void Build(SceneTheme theme)
|
|
{
|
|
if (GameObject.Find(RootName) != null)
|
|
return;
|
|
|
|
var root = new GameObject(RootName);
|
|
var palette = GetPalette(theme);
|
|
|
|
SetCamera(theme, palette);
|
|
SetLight(theme, palette);
|
|
RenderSettings.ambientLight = palette.Ambient;
|
|
RenderSettings.fog = true;
|
|
RenderSettings.fogMode = FogMode.Exponential;
|
|
RenderSettings.fogColor = palette.Background;
|
|
RenderSettings.fogDensity = 0.012f;
|
|
|
|
CreateFloor(root.transform, palette);
|
|
Decorate(theme, root.transform, palette);
|
|
}
|
|
|
|
private static void SetCamera(SceneTheme theme, ScenePalette palette)
|
|
{
|
|
var camera = Camera.main;
|
|
if (camera == null)
|
|
{
|
|
var go = new GameObject("Main Camera");
|
|
go.tag = "MainCamera";
|
|
camera = go.AddComponent<Camera>();
|
|
}
|
|
|
|
camera.clearFlags = CameraClearFlags.SolidColor;
|
|
camera.backgroundColor = palette.Background;
|
|
camera.fieldOfView = theme == SceneTheme.Battle ? 50f : 52f;
|
|
camera.transform.position = theme switch
|
|
{
|
|
SceneTheme.Battle => new Vector3(1.4f, 9f, -5.2f),
|
|
SceneTheme.Login => new Vector3(0f, 2.4f, -9.5f),
|
|
_ => new Vector3(0f, 3.2f, -10f),
|
|
};
|
|
camera.transform.rotation = theme == SceneTheme.Battle
|
|
? Quaternion.Euler(60.5f, 0f, 0f)
|
|
: Quaternion.Euler(8f, 0f, 0f);
|
|
}
|
|
|
|
private static void SetLight(SceneTheme theme, ScenePalette palette)
|
|
{
|
|
var light = Object.FindAnyObjectByType<Light>();
|
|
if (light == null)
|
|
{
|
|
var go = new GameObject("Directional Light");
|
|
light = go.AddComponent<Light>();
|
|
light.type = LightType.Directional;
|
|
}
|
|
|
|
light.color = palette.Light;
|
|
light.intensity = theme == SceneTheme.Battle ? 1.15f : 0.9f;
|
|
light.transform.rotation = Quaternion.Euler(48f, -32f, 0f);
|
|
light.shadows = LightShadows.Soft;
|
|
|
|
if (theme == SceneTheme.Login)
|
|
{
|
|
PointLight("Neon Blue", new Vector3(-6f, 2.2f, 0f), new Color(0.16f, 0.42f, 1f), 2.4f, 11f);
|
|
PointLight("Neon Magenta", new Vector3(6f, 2.2f, 0f), new Color(0.72f, 0.18f, 0.95f), 1.8f, 10f);
|
|
}
|
|
}
|
|
|
|
private static void PointLight(string name, Vector3 position, Color color, float intensity, float range)
|
|
{
|
|
var go = new GameObject(name);
|
|
var light = go.AddComponent<Light>();
|
|
light.type = LightType.Point;
|
|
light.color = color;
|
|
light.intensity = intensity;
|
|
light.range = range;
|
|
light.shadows = LightShadows.None;
|
|
go.transform.position = position;
|
|
}
|
|
|
|
private static void CreateFloor(Transform root, ScenePalette palette)
|
|
{
|
|
var floor = GameObject.CreatePrimitive(PrimitiveType.Plane);
|
|
floor.name = "Floor";
|
|
floor.transform.SetParent(root, false);
|
|
floor.transform.localScale = new Vector3(4f, 1f, 4f);
|
|
floor.transform.position = new Vector3(0f, -0.02f, 2f);
|
|
Paint(floor, palette.Floor, 0f);
|
|
}
|
|
|
|
private static void Decorate(SceneTheme theme, Transform root, ScenePalette palette)
|
|
{
|
|
switch (theme)
|
|
{
|
|
case SceneTheme.Login:
|
|
Cube(root, "Column L", new Vector3(-5.5f, 2.4f, 2f), new Vector3(1f, 5f, 1f), palette.Structure);
|
|
Cube(root, "Column R", new Vector3(5.5f, 2.4f, 2f), new Vector3(1f, 5f, 1f), palette.Structure);
|
|
Cube(root, "Neon L", new Vector3(-4.95f, 2.4f, 2f), new Vector3(0.08f, 4.4f, 0.08f), palette.Accent, 2.2f);
|
|
Cube(root, "Neon R", new Vector3(4.95f, 2.4f, 2f), new Vector3(0.08f, 4.4f, 0.08f), palette.Accent, 2.2f);
|
|
Cube(root, "Backdrop", new Vector3(0f, 3.2f, 8f), new Vector3(16f, 7f, 0.4f), palette.Structure);
|
|
Cube(root, "Emblem", new Vector3(0f, 3.4f, 7.7f), new Vector3(2.4f, 2.4f, 0.2f), palette.Accent, 1.6f);
|
|
|
|
// Карточный стол и несколько карт — нижний план, форма остаётся по центру.
|
|
Cube(root, "Card Table", new Vector3(0f, -0.55f, 1.5f), new Vector3(11f, 0.5f, 5.5f), palette.Structure);
|
|
Cube(root, "Table Neon", new Vector3(0f, -0.28f, 1.5f), new Vector3(10.4f, 0.03f, 0.08f), palette.Accent, 1.8f);
|
|
Cube(root, "Card A", new Vector3(-3.4f, -0.22f, 2.2f), new Vector3(1.35f, 0.05f, 2.0f), new Color(0.10f, 0.18f, 0.38f), 0.6f);
|
|
Cube(root, "Card B", new Vector3(-1.8f, -0.18f, 2.7f), new Vector3(1.35f, 0.05f, 2.0f), new Color(0.30f, 0.08f, 0.16f), 0.5f);
|
|
Cube(root, "Card C", new Vector3(3.0f, -0.18f, 2.5f), new Vector3(1.35f, 0.05f, 2.0f), new Color(0.08f, 0.22f, 0.28f), 0.5f);
|
|
Cube(root, "Card D", new Vector3(4.4f, -0.22f, 2.0f), new Vector3(1.35f, 0.05f, 2.0f), new Color(0.22f, 0.16f, 0.36f), 0.6f);
|
|
|
|
// Парящие карты по краям — рамка вокруг центральной панели.
|
|
Cube(root, "Float L", new Vector3(-7.2f, 2.9f, 1.0f), new Vector3(1.5f, 0.06f, 2.2f), new Color(0.10f, 0.16f, 0.34f), 0.8f);
|
|
Cube(root, "Float R", new Vector3(7.2f, 2.4f, 1.2f), new Vector3(1.5f, 0.06f, 2.2f), new Color(0.28f, 0.08f, 0.18f), 0.8f);
|
|
break;
|
|
|
|
case SceneTheme.Lobby:
|
|
for (var i = -1; i <= 1; i += 2)
|
|
{
|
|
Cube(root, "Pillar " + i, new Vector3(i * 7f, 2.5f, 3f), new Vector3(1.2f, 5f, 1.2f), palette.Structure);
|
|
Cube(root, "Table " + i, new Vector3(i * 3.6f, 0.55f, 0.5f), new Vector3(3f, 1f, 3f), palette.Structure);
|
|
}
|
|
Cube(root, "Back Wall", new Vector3(0f, 3f, 9f), new Vector3(18f, 6f, 0.5f), palette.Structure);
|
|
Cube(root, "Lobby Light", new Vector3(0f, 5.2f, 4f), new Vector3(6f, 0.2f, 1f), palette.Accent, 1.8f);
|
|
break;
|
|
|
|
case SceneTheme.DeckBuilder:
|
|
Cube(root, "Table", new Vector3(0f, 0.5f, 2f), new Vector3(11f, 1f, 6f), palette.Structure);
|
|
Cube(root, "Deck Stack", new Vector3(-3.8f, 1.3f, 3.2f), new Vector3(1.5f, 1.4f, 2.2f), palette.Accent, 0.8f);
|
|
Cube(root, "Mat", new Vector3(1.5f, 1.06f, 3f), new Vector3(5f, 0.08f, 3.5f), palette.Floor);
|
|
break;
|
|
|
|
case SceneTheme.Battle:
|
|
// Сам стол и круги строит GameBoard3D. Здесь только фон.
|
|
Cube(root, "Back Wall", new Vector3(0f, 4.2f, 9.5f), new Vector3(24f, 8.4f, 0.5f), palette.Structure);
|
|
Cube(root, "Pillar L", new Vector3(-8.4f, 2.5f, 4.4f), new Vector3(0.8f, 5f, 0.8f), palette.Structure);
|
|
Cube(root, "Pillar R", new Vector3(8.4f, 2.5f, 4.4f), new Vector3(0.8f, 5f, 0.8f), palette.Structure);
|
|
Cube(root, "Back Light", new Vector3(0f, 5.4f, 9f), new Vector3(6.5f, 0.16f, 0.8f), palette.Accent, 1.8f);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void Cube(
|
|
Transform parent,
|
|
string name,
|
|
Vector3 position,
|
|
Vector3 scale,
|
|
Color color,
|
|
float emission = 0f)
|
|
{
|
|
var cube = GameObject.CreatePrimitive(PrimitiveType.Cube);
|
|
cube.name = name;
|
|
cube.transform.SetParent(parent, false);
|
|
cube.transform.position = position;
|
|
cube.transform.localScale = scale;
|
|
Paint(cube, color, emission);
|
|
}
|
|
|
|
private static void Paint(GameObject target, Color color, float emission)
|
|
{
|
|
var renderer = target.GetComponent<Renderer>();
|
|
if (renderer == null)
|
|
return;
|
|
|
|
var shader = Shader.Find("Universal Render Pipeline/Lit");
|
|
if (shader == null)
|
|
shader = Shader.Find("Standard");
|
|
|
|
var material = new Material(shader);
|
|
if (material.HasProperty("_BaseColor"))
|
|
material.SetColor("_BaseColor", color);
|
|
else if (material.HasProperty("_Color"))
|
|
material.color = color;
|
|
|
|
if (emission > 0f)
|
|
{
|
|
material.EnableKeyword("_EMISSION");
|
|
material.SetColor("_EmissionColor", color * emission);
|
|
}
|
|
|
|
renderer.material = material;
|
|
}
|
|
|
|
private static ScenePalette GetPalette(SceneTheme theme)
|
|
{
|
|
switch (theme)
|
|
{
|
|
case SceneTheme.Login:
|
|
return new ScenePalette(
|
|
new Color(0.015f, 0.02f, 0.045f),
|
|
new Color(0.035f, 0.045f, 0.075f),
|
|
new Color(0.10f, 0.12f, 0.18f),
|
|
new Color(0.20f, 0.42f, 0.95f),
|
|
new Color(0.75f, 0.82f, 1f),
|
|
new Color(0.04f, 0.05f, 0.09f),
|
|
new Color(0.10f, 0.20f, 0.40f),
|
|
new Color(0.40f, 0.12f, 0.10f));
|
|
|
|
case SceneTheme.Battle:
|
|
return new ScenePalette(
|
|
new Color(0.035f, 0.025f, 0.03f),
|
|
new Color(0.08f, 0.06f, 0.07f),
|
|
new Color(0.18f, 0.12f, 0.12f),
|
|
new Color(0.85f, 0.55f, 0.24f),
|
|
new Color(1f, 0.88f, 0.66f),
|
|
new Color(0.05f, 0.08f, 0.14f),
|
|
new Color(0.10f, 0.22f, 0.42f),
|
|
new Color(0.42f, 0.10f, 0.10f));
|
|
|
|
default:
|
|
return new ScenePalette(
|
|
new Color(0.02f, 0.03f, 0.055f),
|
|
new Color(0.06f, 0.075f, 0.11f),
|
|
new Color(0.12f, 0.15f, 0.20f),
|
|
new Color(0.30f, 0.55f, 0.85f),
|
|
new Color(0.82f, 0.88f, 1f),
|
|
new Color(0.08f, 0.11f, 0.17f),
|
|
new Color(0.16f, 0.30f, 0.52f),
|
|
new Color(0.38f, 0.12f, 0.12f));
|
|
}
|
|
}
|
|
|
|
private sealed class ScenePalette
|
|
{
|
|
public ScenePalette(
|
|
Color background,
|
|
Color floor,
|
|
Color structure,
|
|
Color accent,
|
|
Color light,
|
|
Color ambient,
|
|
Color zone,
|
|
Color enemyZone)
|
|
{
|
|
Background = background;
|
|
Floor = floor;
|
|
Structure = structure;
|
|
Accent = accent;
|
|
Light = light;
|
|
Ambient = ambient;
|
|
Zone = zone;
|
|
EnemyZone = enemyZone;
|
|
}
|
|
|
|
public Color Background { get; }
|
|
public Color Floor { get; }
|
|
public Color Structure { get; }
|
|
public Color Accent { get; }
|
|
public Color Light { get; }
|
|
public Color Ambient { get; }
|
|
public Color Zone { get; }
|
|
public Color EnemyZone { get; }
|
|
}
|
|
}
|
|
}
|