Files
MVP1/Assets/Scripts/WorldMap/Map3D.cs
T
AlexanderandClaude Opus 5.5 9a6e5a2e7b Карта мира в 2.5D на примитивах
Карта на земле (X/Z): замок, города, лагеря, ресурсные точки, отряды и метки разведки -- примитивы,
подписи смотрят в камеру; наклонная перспективная камера с тем же поведением (перетаскивание, щипок, тап);
туман -- в текстуре земли; солнце и 3D-рендерер URP для камеры (Map3D). Логика и окна не менялись.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 14:55:41 +01:00

107 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
// 3D НА ПРИМИТИВАХ: общие помощники для карты мира и 3D-поселения (переход на 2.5D, 04.11.2026).
// Материал берётся у встроенного примитива (шейдер URP по умолчанию точно есть в сборке), цвета кешируются.
// Подписи (TextMeshPro) поворачиваются к камере (FaceCamera).
public static class Map3D
{
static Material baseMaterial;
static readonly Dictionary<Color, Material> materials = new Dictionary<Color, Material>();
public static Material Mat(Color color)
{
if (baseMaterial == null)
{
var probe = GameObject.CreatePrimitive(PrimitiveType.Cube);
baseMaterial = new Material(probe.GetComponent<Renderer>().sharedMaterial);
Object.Destroy(probe);
materials.Clear();
}
if (!materials.TryGetValue(color, out var m) || m == null)
{
m = new Material(baseMaterial) { color = color };
materials[color] = m;
}
return m;
}
// Объект на земле: основание size.x * size.y (по X и Z), высота height, низ -- на уровне ground.y
public static Renderer Block(Transform parent, string name, PrimitiveType type, Color color, Vector3 ground, Vector2 size, float height,
bool collider = false)
{
var go = GameObject.CreatePrimitive(type);
go.name = name;
if (!collider) Object.Destroy(go.GetComponent<Collider>());
go.transform.SetParent(parent, false);
// У цилиндра высота -- 2 единицы при масштабе 1
float scaleY = type == PrimitiveType.Cylinder || type == PrimitiveType.Capsule ? height / 2f : height;
go.transform.localScale = new Vector3(size.x, scaleY, size.y);
go.transform.position = ground + Vector3.up * height / 2f;
var r = go.GetComponent<Renderer>();
r.sharedMaterial = Mat(color);
return r;
}
// Подпись над объектом, всегда лицом к камере
public static TextMeshPro Label(Transform parent, string text, Vector3 position, float fontSize)
{
var go = new GameObject("Label");
go.transform.SetParent(parent, false);
go.transform.position = position;
var tmp = go.AddComponent<TextMeshPro>();
tmp.text = text;
tmp.fontSize = fontSize;
tmp.alignment = TextAlignmentOptions.Center;
tmp.rectTransform.sizeDelta = new Vector2(6f, 1.6f);
tmp.color = Color.white;
tmp.outlineWidth = 0.25f;
tmp.outlineColor = Color.black;
go.AddComponent<FaceCamera>();
return tmp;
}
// Камере -- обычный 3D-рендерер URP (второй в списке; добавляет Tools -> Bogatyri -> 3D-город).
// Нет его -- остаётся рендерер по умолчанию, и в лог пишется, что делать.
public static void UseRenderer3D(Camera cam)
{
var pipeline = GraphicsSettings.currentRenderPipeline as UniversalRenderPipelineAsset;
var data = cam != null ? cam.GetUniversalAdditionalCameraData() : null;
if (pipeline == null || data == null) return;
var list = pipeline.rendererDataList;
for (int i = 0; i < list.Length; i++)
if (list[i] is UniversalRendererData) { data.SetRenderer(i); return; }
Debug.LogWarning("[3D] В URP нет обычного 3D-рендерера: выполните Tools -> Bogatyri -> 3D-город: создать сцену City3D (он добавится). Без него 3D рисуется без света.");
}
// Солнце и общий свет, если в сцене их нет (2D-сцены света не имели)
public static void EnsureSun()
{
foreach (var l in Object.FindObjectsByType<Light>(FindObjectsSortMode.None))
if (l.type == LightType.Directional) return;
var sunGo = new GameObject("Sun");
var sun = sunGo.AddComponent<Light>();
sun.type = LightType.Directional;
sun.intensity = 1.15f;
sun.shadows = LightShadows.Soft;
sunGo.transform.rotation = Quaternion.Euler(50f, -30f, 0f);
RenderSettings.ambientMode = AmbientMode.Flat;
RenderSettings.ambientLight = new Color(0.55f, 0.58f, 0.62f);
}
}
// Подпись поворачивается к камере (наклонный вид 2.5D)
public class FaceCamera : MonoBehaviour
{
static Camera cam;
void LateUpdate()
{
if (cam == null) cam = Camera.main;
if (cam != null) transform.rotation = cam.transform.rotation;
}
}