自作ゲームでセリフの吹き出し演出の作成の方法

前回、新しく作成したアプリを紹介しました

今回はこの吹き出しについてみていきたいと思います

コンテンツ

概要

今回作成したアプリにはこのように

回答の選択肢にセリフの吹き出し風の演出を用いています

また吹き出しのシッポがキャラクターを追従するようになっているため、キャラクターが実際に考えながら、選択肢を選び走っていく様子を表現しています

次はこの実装方法を見ていきたいと思います

実装方法

この吹き出しについて図解するとこうなります

各項目については以下の通りです

O : 吹き出しの原点座標

A : 吹き出しシッポの元の座標

B:移動するシッポの座標(今回これを求めます)

T:キャラクターの2D座標

ℓ:OからA長さ

既に数値として持てるものはOとAとℓ

動的に移動し逐次取りに行くものはTとなります。

そして、ここで注目する点はAとBのY座標は横移動になるため同じということです

そのため、Bの座標はX座標を求めるだけで決まることがわかりました

よってXbを求めるために皆さんご存じの1次方程式のy= ax + bを使用して

ここからxの値を求めます

xを求めるために式を変形し、x = (y – b) / aにします

なおbとaはこのようになります

a:ベクトルTOの傾き、ソースコード的にはこうなります

var to = T.position - O.position;
float a = 0.0f;
if (bo != Vector3.zero && to.x != 0)
{
	a = bo.y / bo.x;
}

b:そのままOのX座標が入る

ここから計算式は

Xb=(Yb – X0)/{(Yt – Yo)/(Xt – Xo)}

となります

これでBの位置が求めることができ吹き出しのキャラクター追従が可能となりました

ソースコードはこのようになっています

using UnityEngine;

public class BaloonDotPosSetter : MonoBehaviour
{
	[SerializeField] private RectTransform m_parent = null;
	[SerializeField] private RectTransform m_target = null;
	[SerializeField] private RectTransform m_arrowTarget = null;
	[SerializeField] private float         m_lerpSpeed   = 2.0f;

	private void Update()
	{
		if(m_parent == null || m_target == null || m_arrowTarget == null)
		{
			return;
		}

		var rect = transform as RectTransform;
		var bo = m_arrowTarget.position - m_parent.position;
		float a = 0.0f;
		if (bo != Vector3.zero && bo.x != 0)
		{
			a = bo.y / bo.x;
		}

		if (a == 0.0f)
		{
			m_target.position = transform.position;
		}
		else
		{
			var x = (rect.position.y - m_parent.position.y) / a + m_parent.position.x;
			m_target.position = Vector2.Lerp(m_target.position, new Vector2(x, rect.position.y), Time.deltaTime * m_lerpSpeed);
		}
	}
}

なお、Tを求めるために以下のソースコードで3D座標から2D座標に置き換え、保存することで表現しています。

using UnityEngine;

public class PlayerTracer : MonoBehaviour
{
	[SerializeField] private RectTransform m_parentUI = null;
	[SerializeField] private Transform m_target = null;

	private void Update()
	{
		// オブジェクトのワールド座標→スクリーン座標変換
		var targetScreenPos = Camera.main.WorldToScreenPoint(m_target.position);

		// スクリーン座標変換→UIローカル座標変換
		RectTransformUtility.ScreenPointToLocalPointInRectangle(
			m_parentUI,
			targetScreenPos,
			null,
			out var uiLocalPos
		);

		this.transform.localPosition = uiLocalPos;
	}
}

まとめ

今回は数学パズルですが、アドベンチャーゲームなどでも吹き出し演出はよく使うと思います

たかが吹き出し程度ですが、演出を少しでも凝ってみたいという場合にはこのように

処理を追加してもよいかと思います

また求め方も意外とシンプルなため導入もしやすいかと思います

ただし、この前提条件はキャラクターが吹き出しの下にいる前提となりますので、

そうそうないと思いますが横や上の表示の場合はさらなるひと工夫が必要になるかと思います

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT US
vuniformity誰でもない人
トレンドの行く末を見守っている
仮名を名乗るエンジニア

ゲーム開発は仕事であり趣味である
プログラムだけでなく多種多様なスキルを数多く持つ

ゲーム開発は
ソーシャルゲームを開発運用の経験アリ
ゲーム以外にも経験アリ
Webサービス保守開発等に携わる

ゲームプレイの主な戦場は
FGO
FEH
MTGA
マビノギ
ここでは主にunityroomで公開しているゲーム作り直しの軌跡を綴っていきます