Skip to content

Instantly share code, notes, and snippets.

@hecomi
Created November 29, 2022 17:27
Show Gist options
  • Save hecomi/fd3caf8aa0339455c441d95188d71f8b to your computer and use it in GitHub Desktop.
Save hecomi/fd3caf8aa0339455c441d95188d71f8b to your computer and use it in GitHub Desktop.
PicturesGenerator Example
using UnityEngine;
namespace WeddingMovie
{
public class ColorChanger : MonoBehaviour
{
public Color color = Color.white;
[ContextMenu("ChangeColor")]
public void ChangeColor()
{
Debug.LogFormat("ChangeColor({0})", color.ToString());
ChangeColorRecursively(gameObject);
}
void ChangeColorRecursively(GameObject gameObject)
{
var t = gameObject.transform;
var renderer = t.GetComponent<Renderer>();
if (renderer)
{
// 非実行時のエディタ上での material プロパティアクセスによるインスタンス生成は
// 警告が出るが、エディタ上で作業する分には問題ないので無視
renderer.material.color = color;
}
for (int i = 0; i < t.childCount; ++i)
{
var child = t.GetChild(i);
ChangeColorRecursively(child.gameObject);
}
}
}
}
using UnityEngine;
namespace WeddingMovie
{
public class PictureChanger : MonoBehaviour
{
public Texture2D texture;
public new Renderer renderer;
public void ChangeTexture()
{
if (!renderer || !texture) return;
var material = renderer.material;
material.SetTexture("_BaseMap", texture);
}
}
}
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using System.Collections.Generic;
using System.Linq;
#if UNITY_EDITOR
using UnityEditor;
using UnityEditorInternal;
#endif
namespace WeddingMovie
{
public enum PictureTimelineType
{
BulletLeft,
BulletRight,
BomLeft,
BomRight,
}
public enum PictureRootAnimationType
{
Up,
}
[System.Serializable]
public struct PictureData
{
public PictureTimelineType type;
public Texture2D picture;
[Multiline]
public string text;
[HideInInspector] public Color inkColor;
public bool skip;
public static PictureTimelineType defaultType = PictureTimelineType.BulletRight;
public static string defaultText = "hogehoge";
public static Color defaultInkColor = Color.white;
}
[System.Serializable]
public struct PictureTimelinePrefabData
{
public PictureTimelineType type;
public GameObject prefab;
}
public class PicturesGenerator : MonoBehaviour
{
public PictureData[] pictures;
public PictureTimelinePrefabData[] prefabs;
public Color inkColor;
}
#if UNITY_EDITOR
[CustomEditor(typeof(PicturesGenerator))]
public class PicturesGeneratorEditor : Editor
{
ReorderableList reorderableList;
bool isPrefabsFoldedOut = true;
bool isPicturesFoldedOut = true;
void OnEnable()
{
var prop = serializedObject.FindProperty("pictures");
reorderableList = new ReorderableList(serializedObject, prop);
reorderableList.drawHeaderCallback += rect =>
{
EditorGUI.LabelField(rect, "Pictures");
};
reorderableList.drawElementCallback += (rect, index, isActive, isFocused) =>
{
var elem = prop.GetArrayElementAtIndex(index);
rect.x += 12;
EditorGUI.PropertyField(rect, elem, true);
};
reorderableList.elementHeightCallback += index =>
{
var elem = prop.GetArrayElementAtIndex(index);
float height = EditorGUIUtility.standardVerticalSpacing * 2;
height += EditorGUI.GetPropertyHeight(elem, true);
return height;
};
reorderableList.onAddCallback += list =>
{
prop.arraySize++;
var index = prop.arraySize - 1;
var elem = prop.GetArrayElementAtIndex(index);
elem.FindPropertyRelative("type").enumValueIndex = (int)PictureData.defaultType;
elem.FindPropertyRelative("text").stringValue = PictureData.defaultText;
elem.FindPropertyRelative("inkColor").colorValue = PictureData.defaultInkColor;
elem.FindPropertyRelative("skip").boolValue = false;
};
}
public static bool Foldout(string title, bool display)
{
var style = new GUIStyle("ShurikenModuleTitle");
style.font = new GUIStyle(EditorStyles.label).font;
style.border = new RectOffset(15, 7, 4, 4);
style.fixedHeight = 22;
style.contentOffset = new Vector2(20f, -2f);
var rect = GUILayoutUtility.GetRect(16f, 22f, style);
GUI.Box(rect, title, style);
var e = Event.current;
var toggleRect = new Rect(rect.x + 4f, rect.y + 2f, 13f, 13f);
if (e.type == EventType.Repaint) {
EditorStyles.foldout.Draw(toggleRect, false, false, display, false);
}
if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) {
display = !display;
e.Use();
}
return display;
}
public override void OnInspectorGUI()
{
var style = new GUIStyle("ShurikenModuleTitle");
style.font = new GUIStyle(EditorStyles.label).font;
style.border = new RectOffset(15, 7, 4, 4);
style.fixedHeight = 22;
style.contentOffset = new Vector2(20f, -2f);
serializedObject.Update();
EditorGUI.BeginChangeCheck();
isPrefabsFoldedOut = Foldout("Template", isPrefabsFoldedOut);
if (isPrefabsFoldedOut)
{
EditorGUI.indentLevel++;
DrawInkColor();
EditorGUILayout.Separator();
DrawPrefabs();
EditorGUILayout.Separator();
EditorGUILayout.Separator();
EditorGUI.indentLevel--;
}
isPicturesFoldedOut = Foldout("Pictures", isPicturesFoldedOut);
if (isPicturesFoldedOut)
{
EditorGUI.indentLevel++;
DrawPictures();
EditorGUI.indentLevel--;
}
DrawButton();
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
}
void DrawPrefabs()
{
var prefabsProp = serializedObject.FindProperty("prefabs");
EditorGUILayout.PropertyField(prefabsProp, true);
}
void DrawInkColor()
{
var inkColorProp = serializedObject.FindProperty("inkColor");
EditorGUILayout.PropertyField(inkColorProp, true);
}
void DrawPictures()
{
if (reorderableList != null)
{
reorderableList.DoLayoutList();
}
}
void DrawButton()
{
var txt = new GUIContent(" Rebuild Timeline ");
var style = GUI.skin.button;
style.fixedHeight = 32f;
var rt = GUILayoutUtility.GetRect(txt, style, GUILayout.ExpandWidth(false));
rt.center = new Vector2(EditorGUIUtility.currentViewWidth / 2, rt.center.y);
if (GUI.Button(rt, txt, style))
{
SetupTimeline();
}
}
void SetupTimeline()
{
var generator = target as PicturesGenerator;
var gameObject = generator.gameObject;
var transform = gameObject.transform;
while (transform.childCount > 0)
{
var child = transform.GetChild(0);
if (child) DestroyImmediate(child.gameObject);
}
var director = gameObject.GetComponent<PlayableDirector>();
var asset = director.playableAsset;
var clips = new List<TimelineClip>();
foreach (var output in asset.outputs)
{
if (!output.streamName.Contains("Picture")) continue;
var track = output.sourceObject as ControlTrack;
foreach (var clip in track.GetClips())
{
clips.Add(clip);
}
}
clips = clips.OrderBy(x => x.start).ToList();
var pictures = generator.pictures.Where(x => !x.skip).ToList();
int nc = clips.Count;
int np = pictures.Count;
for (int i = 0; i < nc; ++i)
{
var clip = clips[i];
var playableAsset = clip.asset as ControlPlayableAsset;
if (playableAsset == null) continue;
if (i >= np)
{
director.SetReferenceValue(playableAsset.sourceGameObject.exposedName, null);
continue;
}
var data = pictures[i];
data.inkColor = generator.inkColor;
var prefab = generator.prefabs.FirstOrDefault(x => x.type == data.type).prefab;
if (prefab == null) continue;
var go = Instantiate(prefab, transform);
go.SetActive(false);
var setup = go.GetComponent<PictureTimelineSetup>();
if (setup)
{
setup.Setup(data);
}
director.SetReferenceValue(playableAsset.sourceGameObject.exposedName, go);
}
}
}
#endif
}
using UnityEngine;
namespace WeddingMovie
{
public class PictureTimelineSetup : MonoBehaviour
{
[SerializeField]
TextMesh textMesh = null;
public void Setup(PictureData data)
{
var colorChanger = GetComponent<ColorChanger>();
if (colorChanger)
{
colorChanger.color = data.inkColor;
colorChanger.ChangeColor();
}
var pictureChanger = GetComponent<PictureChanger>();
if (pictureChanger)
{
pictureChanger.texture = data.picture;
pictureChanger.ChangeTexture();
}
if (textMesh)
{
textMesh.text = data.text;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment