投稿記事

2022年 02月の記事 (4)

ものららい 2022/02/26 11:03

Unityでキャラクターを動かしてみた


こんにちは🍎

前回、前々回セリフ周りを作ったので、今回は実際にRPGみたいにキャラクターを動かすことをやってみました。
(※今回はどっちかと言えば作った機能のレビューみたいな感じなのでおててやわらかに)


今回使用してるScript一覧です。(※一部省略)
Player.cs (プレイヤー操作オブジェクトの管理)
StageCharacter.cs (キャラクター移動管理)
BaseSystem/MeshUvControl_Add_Animation.cs (MeshUvControlにアニメーション機能をつける機能)
BaseSystem/CameraControl.cs (追尾カメラ)


まず、ステージ上を歩き回れるキャラクターとは。

アクションさせたりとか考えると色々設定しなきゃいけない所が多いですが、今回はとりあえず歩かせるだけなのでシンプルにしました。

キャラクターのオブジェクトの構成的には、GameObjectに接触用のコライダーとRigidbodyついたものを歩き回れるキャラクターに必要な最低限の物として、その中に入れ子で「MeshUVs」というGameObjectを用意しています。

「MeshUVs」というのはMeshUvControlでUVの絵柄を設定したQuadを格納しておく場所でフルに使う場合は待機、歩行などの専用の絵柄の設定したQuadを入れておきますが、今回はそこまでは行わないのでプレイヤーキャラクターは歩行、NPCキャラクターは待機のみ入れています。

ちなみに「MeshUVs」に入ってるQuadにはMeshUvControlのほかにMeshUvControl_Add_Animationという指定の時間間隔でUVのコマを変更できる機能が付いていてあらかじめ設定してあるので2コマでアニメします。(※MeshUvControl_Add_AnimationはあくまでMeshUvControlが無いと機能しないので注意)

ちょっと説明が後になってしまいましたがキャラクターの移動には移動に関しての処理を集約させたStageCharacterを使用して移動しています。(今回はPlayer.csがセットする形なのでGameObjectに直接セッティングされていませんが)
減速したり面倒な反転とか壁を突き抜けないで移動したりする移動処理が入っているので、今後プレイヤー問わずキャラクターの移動処理のベースとして使用していきます。


実際動かしてみたのがこちら。


動いた!やったー!って感じですが、奥行の移動になんか若干移動に違和感感じますよね?(ね??)
画角とカメラの角度の影響が大いにあるので、別に何も間違ってはいないのですが、もう少し動きがなじむようにカメラをプレイヤーに追尾させる機能をONにして動作させてみます。


もうすでに追尾する機能は用意してプレイヤーをセットしているので、赤丸の部分のチェックを入れると追尾する機能がONになります。



カメラの追尾ONで動かしたのがこちら。


最低限しかありませんが、とりあえずフィールドを歩くことはできるようになったのでゲームっぽくなってきたと思います。


実際動作するアセットフォルダも置いておきますので、アセットフォルダを空プロジェクトに入れれば確認できます。(Script/Player.csに使用例があります)

2022_02_26_Assets.zip (436.22kB)

ダウンロード

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

ものららい 2022/02/20 15:25

Unityでふきだしセリフ的なのを実装してみた

こんにちは🍎

まず初めに…🐄
エディタ上で編集できる用ようにpublicでAnimationCurveを設定した際に未設定時がnullにならないらしく、nullじゃない未設定時の時にMotion_Move等のMotion系の処理が不具合起こしてたっぽいので修正しました。

設定されていない状態を確認するには

if(_curve != null && _curve.length >= 2)

みたいに設定した要素数まで見ないとダメっぽいのでうっかりしてました。
これしないと致命的に動かないわけじゃないので、今回のファイルから上記の修正してますがこういうのはちゃんと気を付けないとですね🐡


--以下から本題--

前回セリフウィンドウを作ってみたので、勉強がてらついでに似たような感じのキャラの頭にふきだしが出るセリフ表示の機能を作ってみました。(以降「ふきだし」と記述します。

ふきだしのウィンドウ表示とテキストの表示は前回とほぼ同じことやってますが、今回はそれにプラスして常にキャラの頭上に表示しないといけないので自動でキャラの座標に追尾するようにしています。


今回使用してるScript一覧です。(※一部省略)
BaseSystem/UI_SerifBalloon.cs (ふきだし管理用)
BaseSystem/UI/UI_TargetTracking (3DオブジェクトにUIを追尾させる処理)


普通に考えたらCanvas内のUI.Imageなどの2D的な表示が3D空間上のオブジェクトの座標にくっついて移動するなんてことはありませんが、CameraのWorldToScreenPointを使用すると3D側のワールド空間の座標を2D側のスクリーン空間の座標に変換出来るので、ふきだしがオブジェクトにくっついて移動してるように見せることができます。

RectTransform _rectTransform = GetComponent<RectTransform>();
_rectTransform.position = Camera.main.WorldToScreenPoint(ターゲットのVector3座標);

スクリプトリファレンス Camera.WorldToScreenPoint


上記の処理で一応ふきだしが追尾しますが、喜ぶのもつかの間、当然2Dの表示なので奥行に合わせて拡縮したりしないので若干違和感ありますよね…🐄

そこで座標の処理と一緒にふきだしのUIのスケールもカメラとの距離に応じて変化させてやると自然な感じになります。

//カメラからターゲットまでの距離
float _distance = Vector3.Distance(カメラのVector3座標, ターゲットのVector3座標);

//ふきだしのスケール
float _scale = カメラが0地点から離れてる距離 / _distance;

ただ…、現状なんか「カメラが0地点から離れてる距離」の部分に正確な値を入れると大きすぎたり小さすぎたりしてたので個々の部分だけ結構あいまいでやってます…🐄(吸いません)
自分の環境でカメラが0地点から約Z-5くらい離れてるけど、3くらいに設定したらしっくり来たのでなんかいい塩梅でお願いします…🐄

あとこれだけだと結構大きくなりすぎたり小さくなりすぎたりするので、求めたスケールの数値は下記のような感じでリミットを設けてあげるとより良くなります。

if(_scale > 1)
{
	_scale = 1;
}
else if(_scale < 0.1f)
{
	_scale = 0.1f;
}

今回のような機能は「ふきだし」に限らず、ゲーム的な2DのUIとか(毒状態アイコンとか)を3D空間のオブジェクトにあわせて表示するのにも使えるので覚えておいても損はないかなと思います。


実際に動かした際にはこんな感じになります。


実際動作するアセットフォルダも置いておきますので、アセットフォルダを空プロジェクトに入れれば確認できます。(Script/Main.csに使用例があります)

2022_02_20_Assets.zip (430.31kB)

ダウンロード

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

ものららい 2022/02/19 14:47

Unityで会話ウィンドウ的なのを実装してみた

こんにちは🍎

今回はセリフウィンドウを作ってみました。

今回は前2回の機能(一定時間で処理のタイマーとモーショントゥイーン)を使って作ったものなのでおさらい的な感じですね。

ちなみに今回はこのAPI使うとできるよ!みたいなのは無いので機能的に説明するところは少ないのでささっと説明でいきます。


今回使用してるScript一覧です。(※TimerFunc.csとかも使ってるけど省略してます。)
UI_SerifWindow.cs (セリフウィンドウ管理用)
UI/UI_ImageAlpha.cs (UI.Imageの透過処理用)
UI/UI_ImageAnimation.cs (UI.ImageのSprite切替用)
UI/UI_TextAnimation.cs (UI.Textのtext表示処理用)


【大まかにこんな感じの動きします。】
フェードインしてウィンドウが表示する

名前の表示と会話文が一文字ずつ表示されてく

一定時間後にウィンドウがフェードアウト

上記はウィンドウのみの説明ですが、ほとんどの場合は会話ウィンドウが表示される際にはしゃべってるキャラの存在が欠かせないので、今回はノベルゲーム風なキャラの立ち絵も含めて演出させています。
キャラ立ち絵自体は特にセリフウィンドウに組み込まれた機能ではないですので、セリフウィンドウの処理の合間の演出完了通知時に処理させて立ち絵を表示しています。


実際に動かした際にはこんな感じになります。


実際動作するアセットフォルダも置いておきますので、アセットフォルダを空プロジェクトに入れれば確認できます。(Script/Main.csに使用例があります)

2022_02_19_Assets.zip (426.05kB)

ダウンロード

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

ものららい 2022/02/10 17:00

Unityでモーショントゥイーン的なの実装してみた


(またまた前回と変わり映えしないスク)

こんにちは🍎
今回はモーショントゥイーン的なのを。

ここら辺はアセット頼みでもいいところではありますが、自分で作れば細かい所の調整しやすいよなってなったのでとりあえず作ってみました。

※あくまで自身の学習用なので粗があってもおおめにみてね🦝


とりあえずソース。(※他もあるけど今回は平行移動用の)
Motion_Move.cs

using System;
using UnityEngine;

//モーショントゥイーン 平行移動
public class Motion_Move : MonoBehaviour
{
	float _motionTime;
	float _startTime;
	Vector3 _startPosition;
	Vector3 _endPosition;
	bool _localFlag;
	Action _updateFunc;
	Action _compFunc;
	AnimationCurve _curve;
	
	
	void Awake ()
	{
		//非動作状態にする
		Stop();
	}
	
	
	//移動のセット
	public void SetMove (Vector3 position, float time, bool localFlag = false, AnimationCurve curve = null, Action updateFunc = null, Action compFunc = null)
	{
		//時間設定が0の時は即終了させる
		if(time <= 0)
		{
			if(localFlag == true)
			{
				this.transform.localPosition = position;
			}
			else
			{
				this.transform.position = position;
			}
			
			Stop();
		}
		else
		{
			if(localFlag == true)
			{
				_startPosition = this.transform.localPosition;
			}
			else
			{
				_startPosition = this.transform.position;
			}
			
			_motionTime = time;
			_startTime = Time.timeSinceLevelLoad;
			_localFlag = localFlag;
			_endPosition = position;
			_updateFunc = updateFunc;
			_compFunc = compFunc;
			_curve = curve;
			
			enabled = true;
		}
	}
	
	
	//動作停止
	public void Stop ()
	{
		enabled = false;
	}
	
	
	void Update ()
	{
		//停止時は処理しない
		if(Time.timeScale == 0){ return; }
		
		//経過時間
		float _elapsedTime = Time.timeSinceLevelLoad - _startTime;
		
		//経過割合
		float _ratio = _elapsedTime / _motionTime;
		if(_curve != null)
		{
			_ratio = _curve.Evaluate(_ratio);
		}
		
		//ローカル移動
		if(_localFlag == true)
		{
			this.transform.localPosition = Vector3.Lerp(_startPosition, _endPosition, _ratio);
		}
		//グローバル移動
		else
		{
			this.transform.position = Vector3.Lerp(_startPosition, _endPosition, _ratio);
		}
		
		//更新時処理
		if(_updateFunc != null){ _updateFunc(); }
		
		//終了
		if(_elapsedTime > _motionTime)
		{
			Stop();
			
			//終了時処理
			if(_compFunc != null){ _compFunc(); }
		}
	}
}

実際どうやって作るの?的な感じで難しい処理とか想像しちゃいましたが、Vector3.Lerpを使うと案外簡単に2点の間の補完された移動処理が作れました。
Unity スクリプトリファレンス Vector3.Lerp


肝の部分は大体下記のような感じなので、シンプルです。

現在位置 = Vector3.Lerp(開始位置, 終了位置, 進行割合);


進行割合の部分に関してはスタートからの経過時間に対して移動にかかる時間を割ってやればいいだけなので一回処理の流れを自作してみればおおよそ理解できると思います。


進行割合は大体こんな感じ(%出すときの計算ですね🍎)
経過時間 = 現在の時間 - 開始時の時間;
進行割合 = 経過時間 / 移動時間;


AnimationCurveを設定して動かすとこんな感じの心地いい動きもできます。


実際動作するアセットフォルダも置いておきますので、アセットフォルダを空プロジェクトに入れれば確認できます。(Script/Main.csに使用例があります)

2022_02_10_Assets.zip (82.05kB)

ダウンロード

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

月別アーカイブ

記事のタグから探す

記事を検索