会話シーンにキャラクターの立ち絵を表示します。Unity の UI Image コンポーネントを Canvas 上に配置し、スクリプトからアルファ値を制御してフェードイン・フェードアウトを実装します。

このページを読み終えると、以下のことができるようになります。
Image.color を操作してアルファ値を変更できるUpdate() と Time.deltaTime を使ってなめらかなフェードを実装できるTime.deltaTime を使った時間制御を理解していること)まず、キャラクター画像を表示するための Image ゲームオブジェクトを Canvas の下に追加します。上部 GameObject メニューをクリックし、「UI(Canvas)」→「Image」を選択してください。

💡 ポイント: Canvas がまだシーンにない場合は、「GameObject」メニューから「UI」→「Image」を選択すると Canvas ごと自動的に作成されます。
Hierarchy ビューに Image ゲームオブジェクトが追加され、Canvas の子オブジェクトとして配置されます。

Inspector ビューで Image ゲームオブジェクトを選択すると、Image コンポーネントが表示されます。「Source Image」フィールドに、表示したいキャラクター画像のスプライトアセットを設定します。
まず、元となる PNG や JPG 形式の画像ファイルを Unity プロジェクトの Assets フォルダーにドラッグ&ドロップしてインポートします。

Project ビューでインポートした画像アセットを選択し、Inspector ビューで「Texture Type」を「Sprite (2D and UI)」に、「Sprite Mode」を「Single」に変更してください。

これで Image コンポーネントの Source Image としてキャラクター画像が設定できます。Project ビューの画像アセットをドラッグ&ドロップしてください。

追加した Image ゲームオブジェクトのサイズも画像に合わせて整えましょう。Rect Transform コンポーネントで画像の位置とサイズを設定します。キャラクター立ち絵は画面左や右に配置することが多いため、Anchor を画面の左下や右下に合わせて調整してください。「Pos X」「Pos Y」「Width」「Height」に適切な値を入力します。
この場ではサンプルなので1画像のみ画面全体を使って表示してみましょう。Anchor Presets を水平・垂直方向ともに stretch に変更し、Left, Top, Right, Bottom を 0 に設定してください。これで Image ゲームオブジェクトの範囲が親 Canvas のサイズ全体に合わせられます。
キャラクター画像のアスペクト比(縦横比)を維持したい場合は、Image コンポーネントの「Preserve Aspect」チェックボックスをオンにします。これにより、Rect Transform の矩形にあわせて画像が引き伸ばされることなく、元の縦横比を保ったまま表示されます。
Image を表示・非表示にする一番シンプルな方法は、Image.color のアルファ値を直接 0 か 1 に切り替えることです。まず、この最もシンプルな版を作りましょう。
Image ゲームオブジェクトに CharacterView という名前の C# スクリプトを新規作成して追加してください。
Image.color — Image が描画に使用する色(Color 型)を取得または設定するプロパティです。Color 型は赤(r)・緑(g)・青(b)・アルファ(a)の 4 成分を持ちます。アルファ値 a は 0 で完全に透明、1 で完全に不透明です。
書式:Image.color プロパティ
1
Color Image.color { get; set; }
| 戻り値 / 代入値 | 型 | 説明 |
|---|---|---|
color |
Color |
RGBA の 4 成分を持つ色の値 |
Image.color にアルファ値だけ変更した新しい Color を代入するには、次の 3 ステップを踏みます。
Image.color を一時変数に取り出すa 成分(アルファ)だけ書き換えるImage.color に代入し直す💡 なぜこの手順が必要?:
Colorは値型(struct)であるため、_image.color.a = 1f;と直接書くことができません。一度変数にコピーして変更し、代入し直す必要があります。
以下は、マウスボタンを押すことで画像の表示・非表示を行うスクリプトです。左ボタンで表示・右ボタンで非表示になります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CharacterView : MonoBehaviour, IPointerClickHandler
{
[SerializeField]
private Image _image = default; // Inspector ビューから設定する
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left) // 左クリック
{
Show();
}
else if (eventData.button == PointerEventData.InputButton.Right) // 右クリック
{
Hide();
}
}
public void Show()
{
var color = _image.color; // 現在の色を取り出す
color.a = 1f; // アルファだけ変更する
_image.color = color; // 代入し直す
}
public void Hide()
{
var color = _image.color;
color.a = 0f;
_image.color = color;
}
}
Inspector ビューで _image フィールドに Image コンポーネントを設定してください。この時点では Show() / Hide() を呼ぶとアルファ値が瞬時に切り替わります。
瞬時の切り替えでは演出として味気ないため、時間をかけてなめらかにアルファ値が変化するフェードを実装します。
フェードを実現するには 3 つの値を組み合わせます。
| 値 | 役割 |
|---|---|
現在のアルファ(Image.color.a) |
今フレームの実際の透明度 |
目標のアルファ(_targetAlpha) |
フェードイン後に到達したい値(1f or 0f) |
1 秒あたりの変化量(_fadeSpeed) |
毎フレームどれだけ目標に近づくかを決める係数 |
Update() が毎フレーム呼ばれるたびに、現在のアルファを目標アルファに向けて少しずつ動かすことでなめらかなフェードになります。
フレームごとに「現在値を目標値に向けて一定量動かす」という処理には Mathf.MoveTowards が便利です。
Mathf.MoveTowards — 現在値を目標値に向けて、最大 maxDelta だけ近づけた値を返すメソッドです。目標値を超えることはありません。
書式:Mathf.MoveTowards メソッド
1
float Mathf.MoveTowards(float current, float target, float maxDelta);
| パラメータ | 型 | 説明 |
|---|---|---|
current |
float |
現在の値 |
target |
float |
近づきたい目標の値 |
maxDelta |
float |
1 ステップで近づける最大量 |
maxDelta に _fadeSpeed * Time.deltaTime を渡すことで、フレームレートによらず「1 秒あたり _fadeSpeed だけ変化する」という動きを実現できます。
完成版では if (_image == null) { return; } という null チェックを追加しています。これは、Inspector ビューで _image フィールドの設定を忘れた場合でも、すぐに実行時エラーにならないようにするためです。学習用のシンプル版では説明を分かりやすくするため省いていましたが、実際に使うコードでは安全確認を入れておくと原因を切り分けやすくなります。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CharacterView : MonoBehaviour, IPointerClickHandler
{
[SerializeField]
private Image _image = default;
[SerializeField]
private float _fadeSpeed = 1f; // 1 秒あたりのアルファ変化量
private float _targetAlpha = 0f; // 目標のアルファ値
private void Start()
{
SetAlpha(0f); // 最初は完全に透明にしておく
}
public void OnPointerClick(PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Left) // 左クリック
{
FadeIn();
}
else if (eventData.button == PointerEventData.InputButton.Right) // 右クリック
{
FadeOut();
}
}
private void Update()
{
if (_image == null) { return; }
// 現在のアルファを目標のアルファに向けて近づける
var a = Mathf.MoveTowards(_image.color.a, _targetAlpha, _fadeSpeed * Time.deltaTime);
SetAlpha(a);
}
/// <summary>
/// キャラクターをフェードインさせます。
/// </summary>
public void FadeIn()
{
_targetAlpha = 1f;
}
/// <summary>
/// キャラクターをフェードアウトさせます。
/// </summary>
public void FadeOut()
{
_targetAlpha = 0f;
}
private void SetAlpha(float alpha)
{
if (_image == null) { return; }
var color = _image.color;
color.a = alpha;
_image.color = color;
}
}
FadeIn() / FadeOut() は _targetAlpha を変更するだけです。実際のアルファ値の更新は Update() に任せているので、どのタイミングで呼び出してもなめらかにフェードします。
SetAlpha() メソッドに切り出しているのは、「Color を取り出す → a だけ変える → Image.color に戻す」 という同じ処理を何度も重複して書かないようにするためです。処理を 1 か所にまとめておくと、あとで修正するときも変更箇所が少なくなります。
1
2
3
4
5
6
7
// ❌ NG: Color は値型なので直接プロパティを書き換えられない(コンパイルエラー)
_image.color.a = 1f;
// ✅ OK: 一時変数にコピーしてから代入し直す
var color = _image.color;
color.a = 1f;
_image.color = color;
1
2
3
4
5
6
7
// ❌ NG: using UnityEngine.UI; がないと Image 型を認識できない
private Image _image = default;
// ✅ OK: ファイル先頭に using ディレクティブを追加する
using UnityEngine.UI;
// …
private Image _image = default;
Image.color は Color 値型なので、一時変数に取り出して a だけ書き換え、代入し直す必要がある_targetAlpha フィールドで目標アルファを持ち、Update() 内で Mathf.MoveTowards を使って現在のアルファを毎フレーム近づけることでなめらかなフェードを実現できるFadeIn() / FadeOut() は目標値を変えるだけ、実際の描画更新は Update() が担うシンプルな設計以下の問いに答えられるか確認しましょう。
_image.color.a = 1f; と書くとコンパイルエラーになります。なぜですか?また、正しい書き方はどうなりますか?_fadeSpeed を 2f に設定した場合、フェードが完了するまでに何秒かかりますか?FadeIn() を呼んだ直後に FadeOut() を呼ぶとどうなりますか?Color は値型(struct)のため、プロパティ経由で返された値を直接書き換えることができません。正しくは次のように書きます。
1
2
3
var color = _image.color;
color.a = 1f;
_image.color = color;
_fadeSpeed = 2f は「1 秒あたり 2f 分アルファを変化させる」という意味なので、アルファが 0 から 1 に変わるまで約 0.5 秒かかります。
_targetAlpha がすぐに 0f に上書きされるため、フェードインは始まらずそのままフェードアウトします。FadeIn() → FadeOut() の順に呼ぶと、目標値が 0f のままフェードアウトが進みます。立ち絵の表示とフェードができるようになりました。次の発展アイデアとして、以下のような機能に挑戦してみましょう。