Skip to content

Instantly share code, notes, and snippets.

@anzfactory
Last active November 23, 2019 12:35
Show Gist options
  • Save anzfactory/f9a7ef0591e2cb19ea1de7b76e9ecc1b to your computer and use it in GitHub Desktop.
Save anzfactory/f9a7ef0591e2cb19ea1de7b76e9ecc1b to your computer and use it in GitHub Desktop.
会話イベントをタイムライン風に表示するやーつ http://anz-note.tumblr.com/post/145359548501
/*********************************
* 会話イベントをタイムライン風に表示するやーつ
* 参考:http://tsubakit1.hateblo.jp/entry/2015/10/19/022720
*********************************/
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Talk : MonoBehaviour
{
[SerializeField] private RectOffset elementPadding;
[SerializeField] private float elementSpace = 5f;
[SerializeField] private Sprite iconFrame;
[SerializeField] private Vector2 iconSize = new Vector2(40, 40);
[SerializeField] private Vector2 iconPadding = new Vector2(2, 2);
[SerializeField] private Sprite messageFrame;
[SerializeField] private Font messageFont;
[SerializeField] private Color messageColor = Color.white;
[SerializeField] private int messageFontSize = 14;
[SerializeField] private RectOffset messagePadding;
private RectTransform rectTransform;
private TalkItem talkItemTemplate;
private List<TalkItem> talkItems;
private void Awake()
{
this.rectTransform = this.gameObject.GetComponent<RectTransform>();
this.talkItems = new List<TalkItem>();
}
private void Start()
{
// 自動サイズ調整に必要なコンポーネントをセットしていく
var verticalLayout = this.gameObject.AddComponent<VerticalLayoutGroup>();
verticalLayout.childForceExpandHeight = false;
verticalLayout.padding = this.elementPadding;
verticalLayout.spacing = this.elementSpace;
var contentSizeFitter = this.gameObject.AddComponent<ContentSizeFitter>();
contentSizeFitter.verticalFit = ContentSizeFitter.FitMode.PreferredSize;
// テンプレートアイテム作成
this.talkItemTemplate = CreateTemplate();
}
/// <summary>
/// メッセージ追加(アイコン無し。地の文とか用)
/// </summary>
/// <returns>The message.</returns>
/// <param name="message">Message.</param>
public GameObject AddMessage(string message)
{
return AddMessage(message, null, TalkItem.ItemTypes.IconNone, false);
}
/// <summary>
/// メッセージ追加(アイコンは左指定)
/// </summary>
/// <returns>The message.</returns>
/// <param name="message">Message.</param>
/// <param name="icon">Icon.</param>
public GameObject AddMessage(string message, Sprite icon)
{
return AddMessage(message, icon, TalkItem.ItemTypes.IconLeft, false);
}
/// <summary>
/// メッセージ追加
/// </summary>
/// <returns>The message.</returns>
/// <param name="message">Message.</param>
/// <param name="icon">Icon.</param>
/// <param name="itemType">Item type.</param>
public GameObject AddMessage(string message, Sprite icon, TalkItem.ItemTypes itemType)
{
return AddMessage(message, icon, itemType, false);
}
public GameObject AddMessage(string message, Sprite icon, TalkItem.ItemTypes itemType, bool isIconFlip)
{
GameObject newTalkItemObject = Instantiate(this.talkItemTemplate.gameObject) as GameObject;
newTalkItemObject.transform.SetParent(this.gameObject.transform);
newTalkItemObject.SetActive(true);
TalkItem newTalkItem = newTalkItemObject.GetComponent<TalkItem>();
newTalkItem.ItemType = itemType;
if (itemType != TalkItem.ItemTypes.IconNone) {
if (isIconFlip) {
newTalkItem.Icon.rectTransform.Rotate(new Vector3(0f, 180f, 0f));
}
newTalkItem.Icon.sprite = icon;
}
newTalkItem.Message.text = message;
this.talkItems.Add(newTalkItem);
return newTalkItemObject;
}
/// <summary>
/// 全メッセージクリア
/// </summary>
public void Clear()
{
foreach (var item in this.talkItems) {
Destroy(item.gameObject);
}
this.talkItems.Clear();
}
/// <summary>
/// テンプレート作成
/// </summary>
/// <returns>The template.</returns>
private TalkItem CreateTemplate()
{
var gameObject = new GameObject("Template");
gameObject.transform.SetParent(this.gameObject.transform);
var rectTransform = gameObject.AddComponent<RectTransform>();
rectTransform.sizeDelta = new Vector2(
this.rectTransform.rect.width, // 横幅いっぱい
this.iconSize.y // 高さはとりあえずアイコンで
);
rectTransform.localPosition = new Vector2(0f, 0f);
// 必要なデータを渡して作成
TalkItem.Param param = new TalkItem.Param();
param.FullRect = this.rectTransform.rect;
param.IconSize = this.iconSize;
param.IconFrame = this.iconFrame;
param.IconPadding = this.iconPadding;
param.MessagePadding = this.messagePadding;
param.MessageFont = this.messageFont;
param.MessageFontSize = this.messageFontSize;
param.MessageColor = this.messageColor;
param.MessageFrame = this.messageFrame;
TalkItem item = gameObject.AddComponent<TalkItem>();
item.Build(param);
gameObject.SetActive(false); // テンプレートなので非活性
return item;
}
}
/*********************************
* 会話イベントをタイムライン風に表示するやーつ(要素)
* http://tsubakit1.hateblo.jp/entry/2015/10/19/022720
*********************************/
using UnityEngine;
using UnityEngine.UI;
public class TalkItem : MonoBehaviour
{
public enum ItemTypes
{
IconLeft,
IconRight,
IconNone
}
[SerializeField] private Image iconFrame;
[SerializeField] private Image icon;
[SerializeField] private Text message;
[SerializeField] private Image messageFrame;
public Image IconFrame {
get { return this.iconFrame; }
}
public Image Icon {
get { return this.icon; }
}
public Text Message {
get { return this.message; }
}
public Image MessageFrame {
get { return this.messageFrame; }
}
private ItemTypes itemType;
public ItemTypes ItemType {
get { return this.itemType; }
set {
this.itemType = value;
SwitchType(this.itemType);
}
}
/// <summary>
/// まっさらなGameObjectにTalkItemとしてアイコン/メッセージなど作成
/// </summary>
/// <param name="param">Parameter.</param>
public void Build(Param param) {
var horizontalLayout = this.gameObject.AddComponent<HorizontalLayoutGroup>();
horizontalLayout.spacing = 3f;
horizontalLayout.childForceExpandWidth = false;
horizontalLayout.childForceExpandHeight = false;
// icon frame
var iconFrameObject = CreateGameObject("IconFrame", gameObject);
var iconFrameRect = iconFrameObject.AddComponent<RectTransform>();
iconFrameRect.sizeDelta = new Vector2(param.IconSize.x, param.IconSize.y);
iconFrameRect.localPosition = new Vector2(
(param.FullRect.width * -0.5f) + (param.IconSize.x * 0.5f),
0f
);
this.iconFrame = iconFrameObject.AddComponent<Image>();
this.iconFrame.type = Image.Type.Sliced;
this.iconFrame.sprite = param.IconFrame;
var iconLayoutElement = iconFrameObject.AddComponent<LayoutElement>();
iconLayoutElement.minWidth = param.IconSize.x;
iconLayoutElement.minHeight = param.IconSize.y;
// icon
var iconObject = CreateGameObject("Icon", iconFrameObject);
var iconRect = iconObject.AddComponent<RectTransform>();
iconRect.anchorMin = Vector2.zero;
iconRect.anchorMax = new Vector2(1f, 1f);
iconRect.sizeDelta = new Vector2(
param.IconPadding.x * -2f,
param.IconPadding.y * -2f
);
iconRect.localPosition = Vector2.zero;
this.icon = iconObject.AddComponent<Image>();
// message frame
var messageFrameObject = CreateGameObject("MessageFrame", gameObject);
var messageFrameRect = messageFrameObject.AddComponent<RectTransform>();
messageFrameRect.sizeDelta = new Vector2(
param.FullRect.width - param.IconSize.x,
param.IconSize.y // 高さはとりあえずアイコンに合わせておく
);
messageFrameRect.localPosition = new Vector2(
(param.FullRect.width * 0.5f) - (messageFrameRect.rect.width * 0.5f),
0f
);
var verticalLayout = messageFrameObject.AddComponent<VerticalLayoutGroup>();
verticalLayout.padding = param.MessagePadding;
this.messageFrame = messageFrameObject.AddComponent<Image>();
this.messageFrame.type = Image.Type.Sliced;
if (param.MessageFrame != null) {
this.messageFrame.sprite = param.MessageFrame;
} else {
this.messageFrame.enabled = false;
}
// message
var messageObject = CreateGameObject("Message", messageFrameObject);
var messageRect = messageObject.AddComponent<RectTransform>();
messageRect.localPosition = Vector2.zero;
this.message = messageObject.AddComponent<Text>();
this.message.font = param.MessageFont;
this.message.fontSize = param.MessageFontSize;
this.message.color = param.MessageColor;
}
/// <summary>
/// GameObject作成&親設定
/// </summary>
/// <returns>The game object.</returns>
/// <param name="name">Name.</param>
/// <param name="parent">Parent.</param>
private GameObject CreateGameObject(string name, GameObject parent)
{
var gameObject = new GameObject(name);
gameObject.transform.SetParent(parent.transform);
return gameObject;
}
/// <summary>
/// ItemTypeが切り替わった時の要素変更
/// </summary>
/// <param name="newType">New type.</param>
private void SwitchType(ItemTypes newType)
{
switch (newType) {
case ItemTypes.IconLeft:
var newMessageFrame = Instantiate(this.messageFrame) as Image;
Destroy(this.messageFrame.gameObject);
newMessageFrame.gameObject.transform.SetParent(this.gameObject.transform);
this.messageFrame = newMessageFrame;
this.message = newMessageFrame.transform.GetChild(0).GetComponent<Text>();
break;
case ItemTypes.IconRight:
var newIconFrame = Instantiate(this.iconFrame) as Image;
Destroy(this.iconFrame.gameObject);
newIconFrame.gameObject.transform.SetParent(this.gameObject.transform);
this.iconFrame = newIconFrame;
this.icon = newIconFrame.transform.GetChild(0).GetComponent<Image>();
break;
case ItemTypes.IconNone:
Destroy(this.iconFrame.gameObject);
this.messageFrame.enabled = false;
break;
}
}
/// <summary>
/// データやり取り用
/// </summary>
public struct Param {
public Rect FullRect;
public Vector2 IconSize;
public Sprite IconFrame;
public Vector2 IconPadding;
public Sprite MessageFrame;
public RectOffset MessagePadding;
public Font MessageFont;
public int MessageFontSize;
public Color MessageColor;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment