using System.Collections.Generic; using UnityEngine; namespace ServiceSim { /// /// ロボットがいま引いている道を、床の上に細い線で出す(依頼 v9 の 6 章)。 /// /// 色は仕事で変える: /// 料理を載せているとき(卓へ向かっている)… だいだい /// 空で戻るとき・待機 … 水色 /// /// 見た目だけ。当たりも NavMesh も持たないので、 /// ロボットのセンサー・人のよけ方・道探しには入らない。 /// RobotSpec.showPathLine を外すと出さない(測る回でも出してよいが、切れるようにする)。 /// /// 置き場所: ロボットの prefab には足さない。ロボットが自分で子として作る /// (材料も prefab も要らないようにして、シーンの組み立てを変えないため)。 /// [RequireComponent(typeof(LineRenderer))] public class RobotPathLine : MonoBehaviour { /// この部品を置く子の名前 public const string RootName = "PathLine"; static readonly Color CarryColor = new Color(1f, 0.55f, 0.1f, 0.9f); // 料理を載せている static readonly Color EmptyColor = new Color(0.25f, 0.75f, 1f, 0.9f); // 空で戻る LineRenderer _line; readonly List _points = new List(); /// /// ロボットの下に線を作る(無ければ)。材料はその場で作るので、 /// prefab や .asset をいじらなくていい。URP でも読める shader を順に試す /// public static RobotPathLine Attach(Transform robot, float widthM) { if (robot == null) return null; Transform t = robot.Find(RootName); GameObject go; if (t != null) go = t.gameObject; else { go = new GameObject(RootName); go.transform.SetParent(robot, false); } if (go.GetComponent() == null) go.AddComponent(); RobotPathLine p = go.GetComponent(); if (p == null) p = go.AddComponent(); p.Setup(widthM); return p; } void Setup(float widthM) { if (_line == null) _line = GetComponent(); _line.useWorldSpace = true; // 親が回っても線は曲がらない _line.alignment = LineAlignment.View; _line.textureMode = LineTextureMode.Stretch; _line.numCapVertices = 2; _line.numCornerVertices = 2; _line.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; _line.receiveShadows = false; _line.widthMultiplier = Mathf.Max(0.005f, widthM); _line.positionCount = 0; if (_line.sharedMaterial == null) { Shader s = Shader.Find("Universal Render Pipeline/Unlit"); if (s == null) s = Shader.Find("Sprites/Default"); if (s == null) s = Shader.Find("Unlit/Color"); if (s != null) { Material m = new Material(s); m.name = "Mat_RobotPathLine"; _line.sharedMaterial = m; } } } /// /// 線を出し直す。points は道の曲がり角(世界の座標)。 /// carrying は料理を載せているか。heightM は床から浮かせる高さ。 /// public void Show(IReadOnlyList points, int fromIndex, Vector3 here, bool carrying, float heightM) { if (_line == null) _line = GetComponent(); _points.Clear(); _points.Add(new Vector3(here.x, heightM, here.z)); if (points != null) for (int i = Mathf.Max(0, fromIndex); i < points.Count; i++) _points.Add(new Vector3(points[i].x, heightM, points[i].z)); if (_points.Count < 2) { _line.positionCount = 0; return; } _line.positionCount = _points.Count; for (int i = 0; i < _points.Count; i++) _line.SetPosition(i, _points[i]); Color c = carrying ? CarryColor : EmptyColor; _line.startColor = c; _line.endColor = new Color(c.r, c.g, c.b, c.a * 0.35f); if (_line.sharedMaterial != null && _line.sharedMaterial.HasProperty("_BaseColor")) _line.sharedMaterial.SetColor("_BaseColor", c); } /// 線を消す public void Hide() { if (_line == null) _line = GetComponent(); _line.positionCount = 0; } } }