Skip to content

Instantly share code, notes, and snippets.

@Masterexa
Created March 26, 2022 13:09
Show Gist options
  • Save Masterexa/013577b66a94ae00dbe6b678e8760e66 to your computer and use it in GitHub Desktop.
Save Masterexa/013577b66a94ae00dbe6b678e8760e66 to your computer and use it in GitHub Desktop.
TextMeshProのルビ振りコード
using System.Text;
using TMPro;
using UnityEngine;
namespace Kimiguna.Unity
{
public class RubyExample : MonoBehaviour
{
[SerializeField] TMP_Text m_text;
// Use this for initialization
void Start()
{
var builder = new StringBuilder();
float widthMul = 1.0f;
// グループルビ
builder.Append("<indent=0>グループルビ:<indent=20%>");
builder.AppendRubyLine("叛逆", "リベリオン");
builder.AppendRubyLine("百舌鳥", "もず");
builder.AppendRubyLine("田町", "たまち");
builder.AppendRubyLine("花鳥風月", "かちょうふうげつ");
builder.Append("\n");
// モノルビ
builder.Append("<indent=0>モノルビ:<indent=20%>");
builder.AppendRuby("田", "た", widthMultiply:widthMul);
builder.AppendRubyLine("町", "まち", widthMultiply: widthMul);
builder.AppendRuby("花", "か", widthMultiply: widthMul);
builder.AppendRuby("鳥", "ちょう", widthMultiply: widthMul);
builder.AppendRuby("風", "ふう", widthMultiply: widthMul);
builder.AppendRubyLine("月", "げつ", widthMultiply: widthMul);
builder.Append("\n");
// 例文
builder.Append("<indent=0>例文:<indent=1em>\n");
builder.Append("そのころわたくしは、モリーオ市の博物局に勤めて");
builder.AppendRuby("居", "お");
builder.Append("りました。\n十八等官でしたから役所のなかでも、ずうっと下の方でしたし");
builder.AppendRuby("俸給", "ほうきゅう");
builder.Append("もほんのわずかでしたが、受持ちが標本の採集や整理で生れ付き好きなことでしたから、わたくしは毎日ずいぶん愉快にはたらきました。");
m_text.text = builder.ToString();
}
}
}
using System.Text;
using UnityEngine;
namespace Kimiguna.Unity
{
public static class TextMeshProRuby
{
/// <summary>
/// ルビを生成
/// </summary>
/// <param name="baseText">ベーステキスト</param>
/// <param name="rubyText">ルビテキスト</param>
/// <param name="voffset">ルビの垂直オフセット</param>
/// <param name="removeRubyHeight">ルビの行の高さを0に指定するか?</param>
/// <param name="baseLineHeight">元の行の高さ(<paramref name="removeRubyHeight"/>がtrueのときのみ使用)</param>
/// <param name="widthMultiply">テキスト幅倍数</param>
/// <param name="rubyFontScale">ルビのフォントサイズ(倍数)</param>
public static void AppendRuby(this StringBuilder builder, string baseText, string rubyText, float voffset = 1f, bool removeRubyHeight = false, string baseLineHeight = "100%", float widthMultiply = 1f, float rubyFontScale = 0.5f)
{
Generate(builder, baseText, rubyText, voffset, removeRubyHeight, baseLineHeight, widthMultiply, rubyFontScale);
}
/// <summary>
/// ルビを生成
/// </summary>
/// <param name="baseText">ベーステキスト</param>
/// <param name="rubyText">ルビテキスト</param>
/// <param name="voffset">ルビの垂直オフセット</param>
/// <param name="removeRubyHeight">ルビの行の高さを0に指定するか?</param>
/// <param name="baseLineHeight">元の行の高さ(<paramref name="removeRubyHeight"/>がtrueのときのみ使用)</param>
/// <param name="widthMultiply">テキスト幅倍数</param>
/// <param name="rubyFontScale">ルビのフォントサイズ(倍数)</param>
public static void AppendRubyLine(this StringBuilder builder, string baseText, string rubyText, float voffset = 1f, bool removeRubyHeight = false, string baseLineHeight = "100%", float widthMultiply = 1f, float rubyFontScale = 0.5f)
{
builder.AppendRuby(baseText, rubyText, voffset, removeRubyHeight, baseLineHeight, widthMultiply, rubyFontScale);
builder.AppendLine();
}
/// <summary>
/// ルビを生成
/// </summary>
/// <param name="baseText">ベーステキスト</param>
/// <param name="rubyText">ルビテキスト</param>
/// <param name="voffset">ルビの垂直オフセット</param>
/// <param name="removeRubyHeight">ルビの行の高さを0に指定するか?</param>
/// <param name="baseLineHeight">元の行の高さ(<paramref name="removeRubyHeight"/>がtrueのときのみ使用)</param>
/// <param name="widthMultiply">テキスト幅倍数</param>
/// <param name="rubyFontScale">ルビのフォントサイズ(倍数)</param>
/// <returns></returns>
public static string Generate(string baseText, string rubyText, float voffset = 1f, bool removeRubyHeight = false, string baseLineHeight = "100%", float widthMultiply=1f, float rubyFontScale = 0.5f)
{
var builder = new StringBuilder();
Generate(builder, baseText, rubyText, voffset, removeRubyHeight, baseLineHeight, rubyFontScale);
return builder.ToString();
}
/// <summary>
/// ルビを生成
/// </summary>
/// <param name="builder">出力用<see cref="StringBuilder"/></param>
/// <param name="baseText">ベーステキスト</param>
/// <param name="rubyText">ルビテキスト</param>
/// <param name="voffset">ルビの垂直オフセット</param>
/// <param name="removeRubyHeight">ルビの行の高さを0に指定するか?</param>
/// <param name="baseLineHeight">元の行の高さ(<paramref name="removeRubyHeight"/>がtrueのときのみ使用)</param>
/// <param name="widthMultiply">テキスト幅倍数</param>
/// <param name="rubyFontScale">ルビのフォントサイズ(倍数)</param>
public static void Generate(StringBuilder builder, string baseText, string rubyText, float voffset = 1f, bool removeRubyHeight = false, string baseLineHeight="100%", float widthMultiply = 1f, float rubyFontScale = 0.5f)
{
// ルビが空のとき以外に処理
if (!string.IsNullOrWhiteSpace(rubyText))
{
// 事前計算
float baseLength = baseText.Length;
float rubyLength = rubyText.Length;
bool displayBase = baseText.Length > 0;
// テキストの幅を計算(em単位)
//
// ベースとルビに必要な幅のうち、値が大きいものを設定
float baseMinWidth = baseLength*widthMultiply;
float rubyMinWidth = rubyLength * rubyFontScale;
float width = Mathf.Max(baseMinWidth, rubyMinWidth);
// 等幅を計算
float baseMs = width / baseLength;
float rubyMs = width / rubyLength * (1 / rubyFontScale);
// ↓↓↓文字列生成
// 改行防止
builder.Append("<nobr>");
// ベースの出力と垂直オフセット
if (displayBase)
{
// ベース
builder.Append($"<mspace={baseMs:F2}em>");
builder.Append(baseText);
builder.Append($"<space={-width:F2}em></mspace>");
// 垂直オフセット
builder.Append($"<voffset={voffset:F2}em>");
// ルビの行の高さを0に設定
if( removeRubyHeight )
{
builder.Append("<line-height=0%>");
}
}
// ルビの出力
builder.Append($"<size={rubyFontScale * 100f:F0}%><mspace={rubyMs:F2}em>");
builder.Append(rubyText);
builder.Append("</mspace></size>");
if (displayBase)
{
// 行の高さを元に戻す
if( removeRubyHeight )
{
builder.Append($"<line-height={baseLineHeight}>");
}
// 垂直オフセット
builder.Append("</voffset>");
}
builder.Append("<nobr>");
}
else{
builder.Append(baseText);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment