using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; namespace Ironspore { public static class WorldFactory { static readonly Dictionary materials = new Dictionary(); public enum Surface { Painted, Concrete, BareMetal } public static Material Material(Color color, bool glow = false, Surface surface = Surface.Painted) { string key = ColorUtility.ToHtmlStringRGB(color) + (glow ? "g" : "") + (int)surface; if (materials.TryGetValue(key, out var cached) && cached) return cached; var mat = new Material(Shader.Find("Standard")); mat.color = color; mat.SetFloat("_Metallic", surface == Surface.BareMetal ? .78f : surface == Surface.Concrete ? 0 : .04f); mat.SetFloat("_Glossiness", surface == Surface.Concrete ? .15f : surface == Surface.BareMetal ? .48f : .32f); mat.enableInstancing = true; if (glow) { mat.EnableKeyword("_EMISSION"); mat.SetColor("_EmissionColor", color * 1.25f); } materials[key] = mat; return mat; } public static GameObject Box(string name, Vector3 position, Vector3 scale, Color color, Transform parent, bool collision = true, bool glow = false) { return Primitive(PrimitiveType.Cube, name, position, scale, color, parent, collision, glow); } public static GameObject Cylinder(string name, Vector3 position, Vector3 scale, Color color, Transform parent, bool collision = true) { return Primitive(PrimitiveType.Cylinder, name, position, scale, color, parent, collision, false); } public static GameObject Primitive(PrimitiveType type, string name, Vector3 position, Vector3 scale, Color color, Transform parent, bool collision, bool glow) { var obj = GameObject.CreatePrimitive(type); obj.name = name; obj.transform.SetParent(parent); obj.transform.position = position; obj.transform.localScale = scale; var renderer = obj.GetComponent(); var surface = name == "Ground" || name == "AccessRamp" ? Surface.Concrete : name == "ContainerRib" || name == "CanopyRail" ? Surface.BareMetal : Surface.Painted; renderer.sharedMaterial = Material(color, glow, surface); bool detail = name == "FloorSeam" || name == "AmberStripe" || name == "CrateLatch" || name == "RelayScreen" || name == "LandingLight" || name == "CanopyIndicator" || name.EndsWith("WorkFixture"); renderer.shadowCastingMode = detail || name == "EnemyBolt" ? ShadowCastingMode.Off : ShadowCastingMode.On; renderer.receiveShadows = !glow; if (name == "EnemyBolt") obj.layer = 10; if (!collision) Object.Destroy(obj.GetComponent()); return obj; } public static GameObject Cockpit(Transform camera) { var root = new GameObject("CockpitFrame"); root.transform.SetParent(camera, false); foreach (int side in new[] { -1, 1 }) { var frame = Box("CanopyRail", Vector3.zero, new Vector3(.045f, .8f, .06f), new Color(.08f, .16f, .19f), root.transform, false); frame.transform.localPosition = new Vector3(side * .48f, -.05f, .7f); frame.transform.localRotation = Quaternion.Euler(0, 0, side * -12); var indicator = Box("CanopyIndicator", Vector3.zero, new Vector3(.018f, .27f, .065f), new Color(.05f, .9f, .75f), root.transform, false, true); indicator.transform.localPosition = new Vector3(side * .48f, -.15f, .66f); } var dashboard = Box("Dashboard", Vector3.zero, new Vector3(1.3f, .14f, .2f), new Color(.07f, .13f, .16f), root.transform, false); dashboard.transform.localPosition = new Vector3(0, -.42f, .75f); foreach (var child in root.GetComponentsInChildren()) child.gameObject.layer = 8; foreach (var renderer in root.GetComponentsInChildren()) { renderer.shadowCastingMode = ShadowCastingMode.Off; renderer.lightProbeUsage = LightProbeUsage.Off; renderer.reflectionProbeUsage = ReflectionProbeUsage.Off; } root.SetActive(false); return root; } public static void Label(string key, Vector3 position, Color color, Transform parent) { var obj = new GameObject("Sign"); obj.transform.SetParent(parent); obj.transform.position = position; obj.layer = 11; var label = obj.AddComponent(); label.fontSize = 40; label.characterSize = .09f; label.anchor = TextAnchor.MiddleCenter; label.color = color; var renderer = obj.GetComponent(); renderer.shadowCastingMode = ShadowCastingMode.Off; renderer.receiveShadows = false; renderer.lightProbeUsage = LightProbeUsage.Off; renderer.reflectionProbeUsage = ReflectionProbeUsage.Off; obj.AddComponent().Initialize(key); obj.AddComponent(); } public static void Tracer(Vector3 from, Vector3 to, Color color) { var obj = new GameObject("ShotTrace"); var line = obj.AddComponent(); obj.layer = 11; line.shadowCastingMode = ShadowCastingMode.Off; line.receiveShadows = false; line.lightProbeUsage = LightProbeUsage.Off; line.reflectionProbeUsage = ReflectionProbeUsage.Off; line.positionCount = 2; line.SetPosition(0, from); line.SetPosition(1, to); line.startWidth = .045f; line.endWidth = .015f; line.sharedMaterial = Material(color, true); Object.Destroy(obj, .07f); } } public sealed class FaceCamera : MonoBehaviour { void LateUpdate() { var c = Camera.main; if (!c) c = Object.FindAnyObjectByType(); if (c) transform.rotation = c.transform.rotation; } } public static class GameAudio { public static void Cue(float frequency, float length, float volume = .12f) { int count = (int)(22050 * length); var data = new float[count]; for (int i = 0; i < count; i++) { float t = i / 22050f; data[i] = Mathf.Sin(t * frequency * Mathf.PI * 2) * Mathf.Exp(-t / length * 6); } var clip = AudioClip.Create("SynthCue", count, 1, 22050, false); clip.SetData(data, 0); var camera = Object.FindAnyObjectByType(); if (camera) AudioSource.PlayClipAtPoint(clip, camera.transform.position, volume); Object.Destroy(clip, length + 1); } } }