Карта на земле (X/Z): замок, города, лагеря, ресурсные точки, отряды и метки разведки -- примитивы, подписи смотрят в камеру; наклонная перспективная камера с тем же поведением (перетаскивание, щипок, тап); туман -- в текстуре земли; солнце и 3D-рендерер URP для камеры (Map3D). Логика и окна не менялись. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
107 lines
4.9 KiB
C#
107 lines
4.9 KiB
C#
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;
|
||
}
|
||
}
|