using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq.Expressions; using System.Reflection; using System.Threading.Tasks; using TMPro; using UnityEditor; using UnityEditor.Media; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Networking; using UnityEngine.UI; // Big text generated here: // https://patorjk.com/software/taag/#p=display&f=Terrace public class DemoClipRecorder : MonoBehaviour { public string uploadUrl; public bool followSceneCamera = true; public bool startRecordingOnPlay = true; [HideInInspector] public bool is_recording = false; private string current_clip_file_path; private RenderTexture camera_render_tex; private Texture2D texture; private MediaEncoder encoder = null; private const int DEFAULT_FRAME_RATE = 30; private float last_frame_time; private GameObject canvas_obj; private List sliders; private List numbers; private List checkboxes; private List colors; private static int num_knobs = 0; public virtual IEnumerator RunDemo() { yield return null; } /* ░█████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░███████ ░███████ ░██░████ ░████████ ░██░████████ ░████████ ░█████████ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██░██ ░██ ░██ ░██ ░██ ░██ ░█████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██░██ ░██ ░██ ░███ ░██ ░██ ░███████ ░███████ ░███████ ░██ ░█████░██ ░██░██ ░██ ░█████░██ ░██ ░███████ */ public void StartRecording() { string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyVideos); string video_folder = Path.Combine(documentsPath, gameObject.name); VideoTrackAttributes videoAttr = new VideoTrackAttributes { bitRateMode = VideoBitrateMode.Medium, frameRate = new MediaRational(DEFAULT_FRAME_RATE), width = (uint)camera_render_tex.width, height = (uint)camera_render_tex.height, includeAlpha = false }; EditorApplication.playModeStateChanged += OnPlayModeExit; StartRecording(video_folder, videoAttr); } public void StartRecording(string dir, VideoTrackAttributes videoTrackAttributes) { if(!is_recording && encoder == null) { if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } current_clip_file_path = Path.Combine(dir, DateTime.Now.ToString("yyy-MM-dd-HH-mm-ss") + ".webm"); encoder = new MediaEncoder(current_clip_file_path, videoTrackAttributes); is_recording = true; } } public void RecordingFrame() { RenderTexture curr_active = RenderTexture.active; RenderTexture.active = camera_render_tex; texture.ReadPixels(new Rect(0, 0, camera_render_tex.width, camera_render_tex.height), 0, 0); texture.Apply(); RenderTexture.active = curr_active; encoder.AddFrame(texture); } public virtual void StopRecording() { if(is_recording) { is_recording = false; encoder.Dispose(); Debug.Log($"Demo Clip Saved To {current_clip_file_path}"); var _ = UploadClip(); current_clip_file_path = null; encoder = null; } } public void CameraToSceneView(){ SceneView lastActiveSceneView = SceneView.lastActiveSceneView; if (lastActiveSceneView == null) { Debug.LogWarning("No active Scene View found."); return; } transform.position = lastActiveSceneView.camera.transform.position; transform.rotation = lastActiveSceneView.camera.transform.rotation; } /* ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░████████ ░██ ░███████ ░██████ ░████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██████ ░██░█████ ░██ ░███████ ░█████░██ ░█████░██ ░██ ░██ */ [Serializable] class ClipUploadResponse { public bool ok; public string videoId; } private async Task UploadClip() { // Do basic url sanitization / check it exists and is valid if(string.IsNullOrEmpty(uploadUrl)) { string line1 = " Your Demo Clip Has Nowhere To Go ): Consider adding an upload url."; string line2 = "If you are making this clip for a UCSC class, go to page for your assignent at https://gallery.democlips.dev."; string line3 = "Then click on \"Upload Clip\", then \"Generate Upload Link\" and finally copy that link into \"Upload URL\" field of the DemoClipGenerator script."; Debug.Log($"{line1}\n{line2}\n{line3}"); return; } byte[] videoBytes = File.ReadAllBytes(current_clip_file_path); Debug.Log("Begining clip upload to " + uploadUrl); using (UnityWebRequest request = new UnityWebRequest(uploadUrl, "POST")) { // Set the raw body data request.uploadHandler = new UploadHandlerRaw(videoBytes); request.downloadHandler = new DownloadHandlerBuffer(); // Set the Content-Type header for WebM video request.SetRequestHeader("Content-Type", "video/webm"); // Optional: Add other headers if needed // request.SetRequestHeader("Authorization", "Bearer your-token"); Debug.Log($"Uploading {videoBytes.Length} bytes to {uploadUrl}"); // Send the request await request.SendWebRequest(); // Handle the response if (request.result == UnityWebRequest.Result.Success) { ClipUploadResponse response_json = JsonUtility.FromJson(request.downloadHandler.text); string video_url = "https://gallery.democlips.dev/v/" + response_json.videoId; Debug.Log($"Upload Successful!! You can view and edit your clip here: {video_url}"); } else { Debug.LogError($"Upload failed: {request.error}"); Debug.LogError($"Status Code: {request.responseCode}"); Debug.LogError($"Response: {request.downloadHandler.text}"); } } } /* ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░████████ ░████████ ░███████ ░████████ ░███████ ░██ ░████ ░██ ░██░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██░██ ░██░██ ░██░██ ░██ ░██ ░██ ░█████████ ░██ ░███████ ░████ ░████ ░██░██ ░███ ░██ ░███ ░██ ░██ ░██ ░███ ░███ ░██ ░█████░██ ░█████░██ ░███████ ░████ ░███████ ░██ ░███████ */ public void AddCheckbox(Expression> field_exp, string label = null) { DemoCheckbox checkbox = new DemoCheckbox(field_exp, label); checkbox.SetCanvas(canvas_obj); checkbox.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); checkboxes.Add(checkbox); num_knobs++; } public void AddColor(Expression> field_exp, string label = null) { DemoColor color = new DemoColor(field_exp, label); color.SetCanvas(canvas_obj); color.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); colors.Add(color); num_knobs++; } public void AddNumber(Expression> field_exp, string label = null) { DemoNumber number = new DemoNumber(field_exp, label); number.SetCanvas(canvas_obj); number.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); numbers.Add(number); num_knobs++; } public void AddNumber(Expression> field_exp, string label = null) { DemoNumber number = new DemoNumber(field_exp, label); number.SetCanvas(canvas_obj); number.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); numbers.Add(number); num_knobs++; } public void AddSlider(Expression> field_exp, string label = null) { DemoSlider slider = new DemoSlider(field_exp, label); slider.SetCanvas(canvas_obj); slider.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); sliders.Add(slider); num_knobs++; } public void AddSlider(Expression> field_exp, string label = null) { DemoSlider slider = new DemoSlider(field_exp, label); slider.SetCanvas(canvas_obj); slider.setUIPosition(Vector3.down * (20f + 35f * num_knobs)); sliders.Add(slider); num_knobs++; } /* ░███████ ░████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░████████ ░██████ ░██ ░██ ░██ ░████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░█████████ ░██ ░███████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░███████ ░███████ ░██ ░█████░██ ░█████░██ ░██ ░████ ░████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░████████ ░██████ ░██ ░██ ░██ ░███████ ░██░████ ░████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██░██ ░██ ░███ ░██ ░██ ░█████████ ░██ ░██ ░███████ ░██ ░██ ░██░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██░██ ░██░██ ░██ ░██ ░█████████ ░███████ ░██ ░██ ░█████░██ ░███ ░██ ░███████ ░██ */ void Start() { string line1 = "Welcome to the Unity Demo Clip Recorder"; string line2 = $"This tool helps you easiy record clips of your unity projects"; string line3 = $"For more information check out the Demo Clip Docs"; Debug.Log($"{line1}\n{line2}\n{line3}"); Camera cam = GetComponent(); camera_render_tex = new RenderTexture(1280, 720, 0, RenderTextureFormat.ARGB32) { depthStencilFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.D32_SFloat_S8_UInt }; cam.targetTexture = camera_render_tex; texture = new Texture2D(camera_render_tex.width, camera_render_tex.height); canvas_obj = DemoClipPrefabs.canvas_prefab(cam); last_frame_time = Time.time; sliders = new List(); numbers = new List(); checkboxes = new List(); colors = new List(); num_knobs = 0; if(startRecordingOnPlay) { StartRecording(); } StartCoroutine(RunDemo()); } void Update() { if(Time.time - last_frame_time < 1f/DEFAULT_FRAME_RATE) { return; } last_frame_time = Time.time; foreach(DemoSlider slider in sliders) { slider.Update(); } foreach(DemoNumber number in numbers) { number.Update(); } foreach(DemoCheckbox checkbox in checkboxes) { checkbox.Update(); } foreach(DemoColor color in colors) { color.Update(); } if(followSceneCamera) { CameraToSceneView(); } if(is_recording) { RecordingFrame(); } } public virtual void OnPlayModeExit(PlayModeStateChange state) { if (state == PlayModeStateChange.ExitingPlayMode) { Debug.Log("Exiting Play Mode"); StopRecording(); } } } /* ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░████████ ░███████ ░████████ ░███████ ░███████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░██ ░██ ░██ ░███████ ░██░█████ ░███████ */ public abstract class DemoKnob { protected Func field; protected FieldInfo field_info; protected string label; protected UIBehaviour ui_component; public DemoKnob(Expression> field_exp, string label = null) { Expression body = field_exp.Body; while (body.NodeType == ExpressionType.Convert || body.NodeType == ExpressionType.ConvertChecked) { body = ((UnaryExpression)body).Operand; } var memberExpression = (MemberExpression)body; string field_name = memberExpression.Member.Name; this.label = label != null ? label : field_name; field = field_exp.Compile(); field_info = memberExpression.Member.DeclaringType.GetField(field_name); } public abstract void Update(); public void SetCanvas(GameObject canvas_obj) { Transform trans = ui_component.transform.parent; while(trans.name != label + "_ui") { trans = trans.parent; } trans.SetParent(canvas_obj.transform.GetChild(0)); } public void setUIPosition(Vector3 pos) { RectTransform trans = (RectTransform)ui_component.transform.parent; while(trans.name != label + "_ui") { trans = (RectTransform)trans.parent; } trans.anchoredPosition3D = pos; trans.localScale = Vector3.one; trans.localRotation = Quaternion.Euler(Vector3.zero); } } public class DemoCheckbox: DemoKnob { public DemoCheckbox(Expression> field_exp, string label = null): base(field_exp, label) { construct(); } private void construct() { ui_component = DemoClipPrefabs.checkbox_prefab(label, 350); } public override void Update() { ((Toggle)ui_component).isOn = field(); } } public class DemoColor: DemoKnob { public DemoColor(Expression> field_exp, string label = null): base(field_exp, label) { construct(); } private void construct() { ui_component = DemoClipPrefabs.color_prefab(label, 350); } public override void Update() { Color color = field(); color.a = 255; ((Image)ui_component).color = color; } } public class DemoNumber: DemoKnob { public DemoNumber(Expression> field_exp, string label = null): base(field_exp, label) { construct(); } public DemoNumber(Expression> field_exp, string label = null): base(fieldExpToFloat(field_exp), label) { construct(); } private static Expression> fieldExpToFloat(Expression> field_exp) { Expression convertedBody = Expression.Convert(field_exp.Body, typeof(float)); return Expression.Lambda>(convertedBody, field_exp.Parameters); } private void construct() { ui_component = DemoClipPrefabs.number_prefab(label, 350); } public override void Update() { ((TMP_InputField)ui_component).text = field().ToString(); } } public class DemoSlider: DemoKnob { public DemoSlider(Expression> field_exp, string label = null): base(field_exp, label) { construct(); } public DemoSlider(Expression> field_exp, string label = null): base(fieldExpToFloat(field_exp), label) { construct(); } private static Expression> fieldExpToFloat(Expression> field_exp) { Expression convertedBody = Expression.Convert(field_exp.Body, typeof(float)); return Expression.Lambda>(convertedBody, field_exp.Parameters); } private void construct(float min = float.NaN, float max = float.NaN) { if ((float.IsNaN(min) || float.IsNaN(max)) && field_info != null) { RangeAttribute rangeAttribute = field_info.GetCustomAttribute(); if (rangeAttribute != null) { if(float.IsNaN(min)) min = rangeAttribute.min; if(float.IsNaN(max)) max = rangeAttribute.max; } } if(!float.IsNaN(min) && !float.IsNaN(max)) { ui_component = DemoClipPrefabs.slider_prefab(label, 350, min, max); } else { Debug.LogError($"AddSlider Failed for {label}. Please supply a min and max as the last 2 parameters of AddSlider, or use a variable with a Unity Range annotation."); } } public override void Update() { if(ui_component is Slider slider_component) { slider_component.value = field(); } else if(ui_component is TMP_InputField number_component) { number_component.text = field().ToString(); } } } /* ░██████████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░████████ ░██░████████ ░███████ ░██░████ ░█████████ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░██ ░██ ░██████████ ░█████░██ ░██ ░████ ░███████ ░██ */ [CustomEditor(typeof(DemoClipRecorder))] public class DemoClipRecorderEditor : Editor { public override void OnInspectorGUI() { DrawDefaultInspector(); DemoClipRecorder recorder = (DemoClipRecorder)target; if(!recorder.is_recording) { if (GUILayout.Button("Start Recording")) { recorder.StartRecording(); } } else { if (GUILayout.Button("Stop Recording")) { recorder.StopRecording(); } } } } /* ░█████████ ░████ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██░████ ░███████ ░████████ ░██████ ░████████ ░███████ ░█████████ ░███ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░██ ░█████████ ░██ ░███████ ░██ ░██ ░███████ ░██ ░██ ░██ ░██ ░██ ░██ ░███ ░██ ░██ ░██ ░██ ░███████ ░██ ░█████░██ ░██░█████ ░███████ */ class DemoClipPrefabs { public static GameObject canvas_prefab(Camera cam) { GameObject canvas_obj = new GameObject("DemoClipCanvas", typeof(RectTransform)); Canvas canvas_component = canvas_obj.AddComponent(); canvas_component.renderMode = RenderMode.ScreenSpaceCamera; canvas_component.worldCamera = cam; canvas_component.planeDistance = 1; CanvasScaler scaler_component = canvas_obj.AddComponent(); scaler_component.uiScaleMode = CanvasScaler.ScaleMode.ScaleWithScreenSize; scaler_component.referenceResolution = new Vector2(800, 600); scaler_component.screenMatchMode = CanvasScaler.ScreenMatchMode.MatchWidthOrHeight; scaler_component.matchWidthOrHeight = 0; scaler_component.referencePixelsPerUnit = 100; GraphicRaycaster graphic_raycaster_component = canvas_obj.AddComponent(); graphic_raycaster_component.ignoreReversedGraphics = true; graphic_raycaster_component.blockingObjects = GraphicRaycaster.BlockingObjects.None; graphic_raycaster_component.blockingMask = 0; GameObject panel_obj = new GameObject("Knob Panel", typeof(RectTransform)); RectTransform panel_obj_transform = (RectTransform)panel_obj.transform; panel_obj_transform.SetParent(canvas_obj.transform); panel_obj_transform.anchorMin = new Vector2(0f, 1f); panel_obj_transform.anchorMax = new Vector2(0f, 1f); panel_obj_transform.anchoredPosition3D = new Vector3(210f, -170f, 0f); panel_obj_transform.localScale = Vector3.one; panel_obj_transform.localRotation = Quaternion.Euler(Vector3.zero); panel_obj_transform.sizeDelta = new Vector2(400f, 325f); Image background = panel_obj.AddComponent(); Sprite background_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Background.psd"); background.sprite = background_sprite; Color background_color = new Color(0.8f, 0.8f, 0.8f, 0.3f); background.color = background_color; background.type = Image.Type.Sliced; background.fillCenter = true; panel_obj.AddComponent(); return canvas_obj; } private static GameObject base_knob_prefab(string label, float label_width) { GameObject knob_obj = new GameObject(label + "_ui", typeof(RectTransform)); RectTransform knob_transform = (RectTransform)knob_obj.transform; knob_transform.anchorMin = new Vector2(0.5f, 1f); knob_transform.anchorMax = new Vector2(0.5f, 1f); knob_transform.sizeDelta = new Vector2(350, 30); GameObject label_obj = new GameObject("Label", typeof(RectTransform)); RectTransform label_transform = (RectTransform)label_obj.transform; label_obj.transform.SetParent(knob_obj.transform); label_transform.anchorMin = new Vector2(0f, 0.5f); label_transform.anchorMax = new Vector2(0f, 0.5f); label_transform.sizeDelta = new Vector2(label_width, 30); label_transform.localScale = Vector3.one; label_transform.localRotation = Quaternion.Euler(Vector3.zero); label_transform.anchoredPosition3D = Vector3.right * label_width/2f; label_obj.AddComponent().cullTransparentMesh = true; TextMeshProUGUI label_text = label_obj.AddComponent(); label_text.SetText(label); label_text.fontSize = 24; label_text.fontStyle = FontStyles.Bold; label_text.alignment = TextAlignmentOptions.Left; Material label_text_material = new Material(label_text.fontSharedMaterial); label_text.fontSharedMaterial = label_text_material; label_text_material.EnableKeyword("OUTLINE_ON"); label_text_material.SetFloat(ShaderUtilities.ID_OutlineWidth, 0.25f); label_text_material.SetColor(ShaderUtilities.ID_OutlineColor, Color.black); label_text.UpdateMeshPadding(); return knob_obj; } private static void base_data_settings(GameObject data_component, float data_width) { RectTransform number_transform = (RectTransform)data_component.transform; number_transform.anchorMin = new Vector2(1f, 0.5f); number_transform.anchorMax = new Vector2(1f, 0.5f); number_transform.sizeDelta = new Vector2(data_width, 30); number_transform.localScale = Vector3.one; number_transform.localRotation = Quaternion.Euler(Vector3.zero); number_transform.anchoredPosition3D = Vector3.left * data_width/2f; } public static Toggle checkbox_prefab(string label, float prefab_width) { const float label_width = 320; GameObject knob_obj = base_knob_prefab(label, label_width); GameObject checkbox_obj = new GameObject("Toggle", typeof(RectTransform)); checkbox_obj.transform.SetParent(knob_obj.transform); base_data_settings(checkbox_obj, prefab_width - label_width); Toggle checkbox_component = checkbox_obj.AddComponent(); GameObject background_obj = new GameObject("Background", typeof(RectTransform)); RectTransform background_transform = (RectTransform)background_obj.transform; background_transform.SetParent(checkbox_obj.transform); background_transform.anchorMin = new Vector2(0f, 0f); background_transform.anchorMax = new Vector2(1f, 1f); background_transform.offsetMax = new Vector2(-2f, -2f); background_transform.offsetMin = new Vector2(2f, 2f); Image background_image = background_obj.AddComponent(); Sprite background_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/UISprite.psd"); checkbox_component.targetGraphic = background_image; background_image.sprite = background_sprite; background_image.type = Image.Type.Sliced; background_image.fillCenter = true; GameObject checkmark_obj = new GameObject("Checkmark", typeof(RectTransform)); RectTransform checkmark_transform = (RectTransform)checkmark_obj.transform; checkmark_transform.SetParent(background_transform); checkmark_transform.anchorMin = new Vector2(0.5f, 0.5f); checkmark_transform.anchorMax = new Vector2(0.5f, 0.5f); checkmark_transform.offsetMax = new Vector2(0f, 0f); checkmark_transform.offsetMin = new Vector2(0f, 0f); checkmark_transform.sizeDelta = new Vector2(20f, 20f); Image checkmark_image = checkmark_obj.AddComponent(); Sprite checkmark_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Checkmark.psd"); checkmark_image.sprite = checkmark_sprite; checkbox_component.graphic = checkmark_image; return checkbox_component; } public static Image color_prefab(string label, float prefab_width) { const float label_width = 275; GameObject knob_obj = base_knob_prefab(label, label_width); GameObject image_obj = new GameObject("Color", typeof(RectTransform)); image_obj.transform.SetParent(knob_obj.transform); base_data_settings(image_obj, prefab_width - label_width); Image image_component = image_obj.AddComponent(); return image_component; } public static TMP_InputField number_prefab(string label, float prefab_width) { const float label_width = 275; GameObject knob_obj = base_knob_prefab(label, label_width); GameObject number_obj = new GameObject("Number", typeof(RectTransform)); number_obj.transform.SetParent(knob_obj.transform); base_data_settings(number_obj, prefab_width - label_width); number_obj.AddComponent(); Image background = number_obj.AddComponent(); Sprite background_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/InputFieldBackground.psd"); background.sprite = background_sprite; background.type = Image.Type.Sliced; background.fillCenter = true; GameObject text_area_obj = new GameObject("TextArea", typeof(RectTransform)); RectTransform text_area_transform = (RectTransform)text_area_obj.transform; text_area_transform.SetParent(number_obj.transform); text_area_transform.anchorMin = new Vector2(0f, 0f); text_area_transform.anchorMax = new Vector2(1f, 1f); text_area_transform.offsetMax = new Vector2(-10f, -7f); text_area_transform.offsetMin = new Vector2(10f, 6f); RectMask2D rect_mask = text_area_obj.AddComponent(); rect_mask.padding = new Vector4(-8f, -5f, -8f, -5f); GameObject text_obj = new GameObject("Text", typeof(RectTransform)); RectTransform text_transform = (RectTransform)text_obj.transform; text_transform.SetParent(text_area_transform); text_obj.AddComponent(); TextMeshProUGUI text_component = text_obj.AddComponent(); text_component.fontSize = 14; text_component.alignment = TextAlignmentOptions.Center; text_component.color = Color.black; text_transform.anchorMin = new Vector2(0f, 0f); text_transform.anchorMax = new Vector2(1f, 1f); text_transform.offsetMax = new Vector2(0f, 0f); text_transform.offsetMin = new Vector2(0f, 0f); TMP_InputField input_component = number_obj.AddComponent(); input_component.textViewport = text_area_transform; input_component.textComponent = text_component; return input_component; } public static Slider slider_prefab(string label, float prefab_width, float min, float max) { const float label_width = 175; GameObject knob_obj = base_knob_prefab(label, label_width); GameObject slider_obj = new GameObject("Slider", typeof(RectTransform)); RectTransform slider_obj_transform = (RectTransform)slider_obj.transform; slider_obj_transform.SetParent(knob_obj.transform); base_data_settings(slider_obj, prefab_width - label_width); slider_obj_transform.sizeDelta = new Vector2(slider_obj_transform.sizeDelta.x, 20); slider_obj.AddComponent(); Slider slider_component = slider_obj.AddComponent(); slider_component.minValue = min; slider_component.maxValue = max; GameObject background_obj = new GameObject("Background", typeof(RectTransform)); RectTransform background_transform = (RectTransform)background_obj.transform; background_transform.SetParent(slider_obj.transform); background_transform.anchorMin = new Vector2(0f, 0.25f); background_transform.anchorMax = new Vector2(1f, 0.75f); background_transform.offsetMax = new Vector2(0f, 0f); background_transform.offsetMin = new Vector2(0f, 0f); Image background = background_obj.AddComponent(); Sprite background_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Background.psd"); background.sprite = background_sprite; background.type = Image.Type.Sliced; background.fillCenter = true; GameObject fill_area_obj = new GameObject("Fill Area", typeof(RectTransform)); RectTransform fill_area_obj_transform = (RectTransform)fill_area_obj.transform; fill_area_obj_transform.SetParent(slider_obj.transform); fill_area_obj_transform.anchorMin = new Vector2(0f, 0.25f); fill_area_obj_transform.anchorMax = new Vector2(1f, 0.75f); fill_area_obj_transform.offsetMax = new Vector2(-15f, 0f); fill_area_obj_transform.offsetMin = new Vector2(5f, 0f); GameObject fill_obj = new GameObject("Fill", typeof(RectTransform)); RectTransform fill_obj_transform = (RectTransform)fill_obj.transform; fill_obj_transform.SetParent(fill_area_obj.transform); slider_component.fillRect = fill_obj_transform; fill_obj_transform.offsetMax = new Vector2(5f, 0f); fill_obj_transform.offsetMin = new Vector2(-5f, 0f); Image fill_image = fill_obj.AddComponent(); Sprite fill_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/UISprite.psd"); fill_image.color = Color.cyan; fill_image.sprite = fill_sprite; fill_image.type = Image.Type.Sliced; fill_image.fillCenter = true; GameObject handle_slide_obj = new GameObject("Handle Slide Area", typeof(RectTransform)); RectTransform handle_slide_transform = (RectTransform)handle_slide_obj.transform; handle_slide_transform.SetParent(slider_obj.transform); handle_slide_transform.anchorMin = new Vector2(0f, 0f); handle_slide_transform.anchorMax = new Vector2(1f, 1f); handle_slide_transform.offsetMax = new Vector2(-10f, 0f); handle_slide_transform.offsetMin = new Vector2(10f, 0f); GameObject handle_obj = new GameObject("Handle", typeof(RectTransform)); RectTransform handle_obj_transform = (RectTransform)handle_obj.transform; handle_obj_transform.SetParent(handle_slide_obj.transform); slider_component.handleRect = handle_obj_transform; Image knob = handle_obj.AddComponent(); Sprite knob_sprite = AssetDatabase.GetBuiltinExtraResource("UI/Skin/Knob.psd"); knob.sprite = knob_sprite; slider_component.targetGraphic = knob; handle_obj_transform.offsetMax = new Vector2(0f, 0f); handle_obj_transform.offsetMin = new Vector2(0f, 0f); handle_obj_transform.sizeDelta = new Vector2(20f, handle_obj_transform.sizeDelta.y); return slider_component; } }