
昼夜変化とイベント時刻の状態を分ける
朝を表示、夕方へ進む、イベント時刻を知らせる を別々の状態として扱い、今どの段階かを画面で確認できるようにします。
今がいつで何が起きるかをUIで伝える
Console だけではプレイヤーには見えません。TextMeshPro や Slider に dayHour / eventHour / timeScale を出して、判断材料を画面へ移します。
最小実装から広げる
まず DayNightTimerDemo を動かし、その後に本物の入力、通信、戦闘、保存処理などへ置き換えると、原因を見失いにくくなります。
導入
昼夜UIで大事なのは、時計を見せることではなく「次に何が起こるか」を分かるようにすることです。夜が近い、店が閉まる、イベントが始まる。この3つがすぐ読めれば、プレイヤーは迷いません。
たとえるなら、学校のチャイムです。今何時何分かを暗記させるためではなく、「次は動く時間だ」と知らせるために鳴ります。ゲームの時間UIも同じです。
これから作るもの
今回は Unity で、ボタンを押すと時間帯と残り時間が変わる小さな確認用UIを作ります。次の順番で用意してください。
- Project ウィンドウで右クリックし、Create > C# Script を選びます。名前を
DayNightEventTimerTutorialにして新規作成します。 - Hierarchy で右クリックし、Create Empty を選びます。名前を
DayNightTimerDemoに変え、作ったDayNightEventTimerTutorialをこの GameObject へドラッグして付けます。 - Canvas がなければ Hierarchy で右クリックし、UI > Canvas を選びます。Canvas を右クリックして UI > Text - TextMeshPro を2つ作り、片方を時間帯、もう片方を残り時間の表示にします。
- Canvas を右クリックして UI > Slider を1つ作り、1日の進み具合を表示するバーにします。
- Canvas を右クリックして UI > Button を新規作成し、名前を
Advance Time Buttonに変えます。これは時間を1時間進めるために押す Button GameObject です。
ステップ1: 変数を作る
まずは数字と表示先を作ります。
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class DayNightEventTimerTutorial : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI phaseText; // 時間帯の名前を画面に表示するTextへの参照
[SerializeField] private TextMeshProUGUI timerText; // 次のイベントまでの残り時間を表示するTextへの参照
[SerializeField] private Slider timeSlider; // 1日の進み具合を表示するSliderへの参照
[SerializeField] private float currentHour = 8f; // 現在のゲーム内時刻
[SerializeField] private float daySpeed = 0.25f; // 1秒あたりに進めるゲーム内時間
[SerializeField] private float eventStartHour = 18f; // イベントが始まるゲーム内時刻
}
currentHour は今のゲーム内時刻です。eventStartHour はイベント開始時刻です。まずはこの2つだけでも十分です。
ステップ2: 時間を進める
次は時間が少しずつ進む処理です。
private void Update()
{
currentHour += Time.deltaTime * daySpeed;
if (currentHour >= 24f) currentHour -= 24f;
RefreshUi();
}
public void AdvanceTime()
{
currentHour += 1f;
if (currentHour >= 24f) currentHour -= 24f;
RefreshUi();
}
Advance Time Button の On Click() から AdvanceTime() を呼ぶと、Buttonを1回押すたびに1時間進みます。待たずに表示を確認できます。
ステップ3: 昼・夕・夜を判定する
次に、今がどの時間帯かを文字で出します。
private string GetPhaseLabel(float hour)
{
if (hour < 6f) return "夜";
if (hour < 12f) return "朝";
if (hour < 17f) return "昼";
if (hour < 20f) return "夕方";
return "夜";
}
最初は細かくしすぎなくて大丈夫です。プレイヤーが「今は危ない時間か」を読めることのほうが大事です。
ステップ4: 次のイベントまでの残りを出す
イベント時刻の見せ方も入れます。
private float GetHoursUntilEvent(float hour)
{
if (hour <= eventStartHour) return eventStartHour - hour;
return (24f - hour) + eventStartHour;
}
この関数で「あと何時間か」を出せます。時計そのものより、残り時間のほうが行動に直結しやすいです。
ステップ5: UIを更新する
ここで文字とスライダーをまとめて更新します。
private void RefreshUi()
{
var phase = GetPhaseLabel(currentHour);
var remain = GetHoursUntilEvent(currentHour);
if (phaseText != null)
{
phaseText.text = $"時間帯: {phase} ({currentHour:00.0}時)";
}
if (timerText != null)
{
timerText.text = $"イベントまで {remain:0.0} 時間";
}
if (timeSlider != null)
{
timeSlider.value = currentHour / 24f;
}
}
この時点で、画面がちゃんと返事をするようになります。まずはここまでで十分です。
完成版
ここまでをまとめるとこうなります。
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class DayNightEventTimerTutorial : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI phaseText; // 時間帯の名前を画面に表示するTextへの参照
[SerializeField] private TextMeshProUGUI timerText; // 次のイベントまでの残り時間を表示するTextへの参照
[SerializeField] private Slider timeSlider; // 1日の進み具合を表示するSliderへの参照
[SerializeField] private float currentHour = 8f; // 現在のゲーム内時刻
[SerializeField] private float daySpeed = 0.25f; // 1秒あたりに進めるゲーム内時間
[SerializeField] private float eventStartHour = 18f; // イベントが始まるゲーム内時刻
private void Update()
{
currentHour += Time.deltaTime * daySpeed;
if (currentHour >= 24f) currentHour -= 24f;
RefreshUi();
}
public void AdvanceTime()
{
currentHour += 1f;
if (currentHour >= 24f) currentHour -= 24f;
RefreshUi();
}
private string GetPhaseLabel(float hour)
{
if (hour < 6f) return "夜";
if (hour < 12f) return "朝";
if (hour < 17f) return "昼";
if (hour < 20f) return "夕方";
return "夜";
}
private float GetHoursUntilEvent(float hour)
{
if (hour <= eventStartHour) return eventStartHour - hour;
return (24f - hour) + eventStartHour;
}
private void RefreshUi()
{
var phase = GetPhaseLabel(currentHour);
var remain = GetHoursUntilEvent(currentHour);
if (phaseText != null) phaseText.text = $"時間帯: {phase} ({currentHour:00.0}時)";
if (timerText != null) timerText.text = $"イベントまで {remain:0.0} 時間";
if (timeSlider != null) timeSlider.value = currentHour / 24f;
}
}
Inspectorでつなぐ
- Hierarchy で
DayNightTimerDemoを選び、Inspector にDayNightEventTimerTutorialコンポーネントが付いていることを確認します。 - Canvas に作った時間帯用 Text (TMP) を
Phase Text欄へ、残り時間用 Text (TMP) をTimer Text欄へドラッグします。 - Canvas に作った Slider を
Time Slider欄へドラッグします。これでスクリプトがそれぞれのUIを更新できます。 Current Hour、Day Speed、Event Start Hourは、このコンポーネントの最初の時刻、時間の進む速さ、イベント開始時刻です。数字を変えるとPlay開始時の動きが変わります。Advance Time Buttonを選び、Inspector の Button コンポーネントにある On Click() で + を押します。DayNightTimerDemoを空欄へドラッグし、メニューからDayNightEventTimerTutorial > AdvanceTime()を選びます。- Play を押して Button をクリックし、時間帯と残り時間が変わるか見ます。
次に足すとよいもの
- 夜の直前だけ文字色を変える
- イベント10秒前に音を鳴らす
- 店が閉まる、敵が強くなる、採取できる、を別アイコンで出す
まとめ
昼夜UIは、細かい時計より「次に動く理由」を出すほうが強いです。まずは時間帯、残り時間、簡単な通知の3つを作ってください。そこまでできれば、プレイヤーはかなり迷いにくくなります。
この記事のまとめ
夜になると敵が強くなる、朝だけ採取できる、一定時刻で店が閉まる。そんな時間変化を、世界観を壊さず判断しやすく見せる方法をまとめます。
大きな違いを生むのは、派手な性能よりも 毎日触れる環境を無理なく整えること です。見やすい画面と使いやすい道具がそろうと、学習や次の一歩を決めやすくなります。