🐈

Unity×C#で現在時刻を取得!デイリーイベント実装方法まで

2025/01/13に公開

Unity C#で日付を扱うメリットと始め方

Unityでゲームを作成するうえで、日付や時刻の情報をうまく活用できると、日替わりイベントやリアルタイム要素を簡単に実装できるようになります。たとえば、ログインボーナスや特定の時間帯のみ発生するイベントなど、ゲームの継続率やユーザー体験を大きく向上させる要素を手軽に盛り込める点は大きなメリットです。また、時間管理がしやすくなることで、プロジェクト全体の可読性や保守性も向上します。

https://zenn.dev/ryuryu_game/books/fd28de9d8e963a

ここでは、UnityのC#を使った日付の取得方法から、ゲーム内での具体的な活用アイデアまで順を追って解説します。基本を押さえておけば、イベント管理やデバッグもしやすくなるので、ぜひ一度はマスターしておきたいポイントです。

ゲーム開発での日付の具体的な使い方

DateTimeでの基本的な日時取得方法

C#で現在の日時を取得する際は、主に**System.DateTime**構造体を利用します。もっともシンプルな書き方としては下記のようになります。

DateTimeSample.cs
using UnityEngine;
using System;

public class DateTimeSample : MonoBehaviour
{
    void Start()
    {
        DateTime now = DateTime.Now;
        Debug.Log("現在の日時: " + now.ToString("yyyy/MM/dd HH:mm:ss"));
    }
}
  • DateTime.Now:PCのシステム時刻を参照
  • DateTime.UtcNow:協定世界時(UTC)を参照

リアルタイムで時刻を表示したい場合は、Update()メソッド内で定期的にDateTime.Nowを取得してUIに反映させる方法を取ります。

詳しいサンプルコードは下記リンクも参考になります。

https://qiita.com/uroshinse/items/6bfb144350e92da87f07

また、各要素を個別に取得するには以下のようなプロパティを利用します。

用途 備考
年の取得 DateTime.Now.Year 4桁の西暦
月の取得 DateTime.Now.Month 1~12の整数
日数の取得 DateTime.Now.Day 1~31の整数

より詳しい機能やサンプルについては、以下のリンクもあわせて確認してみてください。

https://sunagitsune.com/unitydatetimenow/

Unity環境での日付利用で気をつけること

  • PCや端末依存のリスク
    端末によってタイムゾーンや時刻の設定が異なると、意図しないタイミングでイベントが発生してしまう場合があります。たとえば、ユーザーが端末の時刻設定を変更してしまうと、日替わりイベントの判定が崩れるケースも。
  • サーバーとの連携が必要なケース
    不正防止や正確な時間計測が求められるゲームでは、サーバー時刻と同期する仕組みが必要になります。基本的にはゲーム側で端末の時刻を仮利用し、最終的にサーバーから取得した時刻で整合性を保つ流れです。

デイリーイベント・ミッションへの応用

日付情報を使うときの典型的な事例として、ログインボーナスや日替わりミッションなどがあります。1日の区切りを特定の時刻に設定し、そこを境に以下のようなイベントを自動リセットします。

  • 日替わりの報酬
  • デイリーミッションの進捗状況
  • ショップの在庫リセット

サンプルプログラム : デイリーイベント

PlayerPrefs に前回ログイン日を保存し、日付が切り替わったタイミングでデイリーリセット処理を行うサンプルとしてご覧ください。また、曜日ごとのイベント(例:週末ボーナスなど)を実装するための条件分岐も入れています。実際のプロジェクト環境やサーバー連携の有無によって、必要な処理を追加・変更してください。

using UnityEngine;
using System;

public class DailyLoginBonus : MonoBehaviour
{
    private const string KEY_LAST_LOGIN_DATE = "LAST_LOGIN_DATE";
    private TimeSpan resetTime = new TimeSpan(5, 0, 0); // 朝5時リセット

    void Start()
    {
        string savedDate = PlayerPrefs.GetString(KEY_LAST_LOGIN_DATE, "");

        if (string.IsNullOrEmpty(savedDate))
        {
            // 初回ログイン処理
            GrantBonus();
            SaveLastLoginDate(DateTime.Now);
        }
        else
        {
            DateTime lastLogin;
            if (DateTime.TryParse(savedDate, out lastLogin))
            {
                if (IsDailyReset(lastLogin, DateTime.Now))
                {
                    GrantBonus();
                    SaveLastLoginDate(DateTime.Now);
                }
            }
            else
            {
                // データ破損時のリカバリ
                GrantBonus();
                SaveLastLoginDate(DateTime.Now);
            }
        }
    }

    private bool IsDailyReset(DateTime lastLogin, DateTime now)
    {
        return lastLogin.Date < now.Date;
    }

    private void GrantBonus()
    {
        Debug.Log("デイリーログインボーナスを付与しました!");
        // ボーナス処理を実装
    }

    private void SaveLastLoginDate(DateTime dateTime)
    {
        PlayerPrefs.SetString(KEY_LAST_LOGIN_DATE, dateTime.ToString("yyyy-MM-dd HH:mm:ss"));
        PlayerPrefs.Save();
    }
}
デイリーイベントのサンプルプログラム(詳細)
DailyEventManager
using UnityEngine;
using System;  // DateTime, DayOfWeek を使用するため
using UnityEngine.UI;  // UI表示が必要な場合

public class DailyEventManager : MonoBehaviour
{
    // PlayerPrefsで管理するキー
    private const string KEY_LAST_LOGIN_DATE = "LAST_LOGIN_DATE";
    
    // 例:日替わりのリセット時刻を「朝5時」にする場合
    // (ユーザーのローカル時間で処理する簡易例)
    private TimeSpan resetTime = new TimeSpan(5, 0, 0);  // 05:00:00
    
    void Start()
    {
        // 前回のログイン日を取得(キーがなければ空文字が返る)
        string savedDate = PlayerPrefs.GetString(KEY_LAST_LOGIN_DATE, "");

        // キーが存在しない → 初回起動または日付情報なし
        if (string.IsNullOrEmpty(savedDate))
        {
            // 初回ログイン報酬を付与するなどの処理
            GiveDailyLoginBonus();

            // 今日を保存
            SaveLastLoginDate(DateTime.Now);
        }
        else
        {
            // 前回のログイン日時をパース
            DateTime lastLoginDateTime;
            if (DateTime.TryParse(savedDate, out lastLoginDateTime))
            {
                // 日付切り替えチェック
                CheckDailyReset(lastLoginDateTime, DateTime.Now);
            }
            else
            {
                // パース失敗した場合、初期状態とみなす
                GiveDailyLoginBonus();
                SaveLastLoginDate(DateTime.Now);
            }
        }
        
        // 曜日イベントの例示:週末は経験値2倍など
        CheckWeekendBonus();
    }
    
    /// <summary>
    /// 日付切り替えチェックを行い、必要ならデイリーリセット処理を実行
    /// </summary>
    private void CheckDailyReset(DateTime lastLogin, DateTime now)
    {
        // 同じ日にログインしていても、指定した時刻(朝5時)を境に日付リセットを行う場合
        // 「lastLogin.Date と now.Date が異なる」だけではなく、
        // 「lastLogin.Date == now.Date でも、時刻が5時をまたいでいるか」などをチェックできる
        
        // まずはシンプルに「日付(Date部分)が違う」場合はデイリーをリセットする例
        if (lastLogin.Date < now.Date)
        {
            // ここで「昨日ログインした時間」と「今日の5時」を比較して、
            // 実際に5時以降になっているかを判定してもOK
            
            // リセット処理
            ResetDailyMissions();
            
            // デイリーログインボーナス付与など
            GiveDailyLoginBonus();
            
            // 最終ログイン日時を更新
            SaveLastLoginDate(now);
        }
        else
        {
            // 同じ日付内なら特にリセット処理はしない
            // 必要に応じて同日ログインボーナスの制限などを行う
        }
    }
    
    /// <summary>
    /// デイリーミッションをリセットする例
    /// </summary>
    private void ResetDailyMissions()
    {
        Debug.Log("デイリーミッションをリセットしました。");
        // ここで日替わりのミッション進捗やショップ在庫などを初期化
    }
    
    /// <summary>
    /// デイリーボーナスを付与する例
    /// </summary>
    private void GiveDailyLoginBonus()
    {
        Debug.Log("デイリーのログインボーナスを付与しました!");
        // ゲーム内通貨やアイテムを付与する処理を記述
    }
    
    /// <summary>
    /// PlayerPrefsに最終ログイン日時を文字列で保存
    /// </summary>
    private void SaveLastLoginDate(DateTime dateTime)
    {
        PlayerPrefs.SetString(KEY_LAST_LOGIN_DATE, dateTime.ToString("yyyy-MM-dd HH:mm:ss"));
        PlayerPrefs.Save();
    }
    
    /// <summary>
    /// 曜日ごとのイベント判定例
    /// </summary>
    private void CheckWeekendBonus()
    {
        // 現在の曜日を取得
        DayOfWeek currentDay = DateTime.Now.DayOfWeek;
        
        // 土日なら経験値2倍等、平日なら通常などの処理
        if (currentDay == DayOfWeek.Saturday || currentDay == DayOfWeek.Sunday)
        {
            Debug.Log("週末ボーナス:経験値2倍イベント中!");
            // 実際のゲームロジックに合わせて処理を実装
        }
        else
        {
            Debug.Log("平日です。通常イベントを実行中。");
        }
    }
}

コード解説

  1. 最終ログイン日を保存

    • PlayerPrefs.GetString(KEY_LAST_LOGIN_DATE, "") で取得し、初回やキー未登録時は空文字が返ってきます。
    • 取得できない場合(初回ログインなど)はそのままボーナスを付与し、現在時刻を保存します。
  2. 日付切り替えチェック

    • CheckDailyReset メソッドでは、前回ログイン日の Date と現在日時の Date を比較し、日付が変わったタイミングでリセット処理を行います。
    • さらに「同じ日付でも指定時刻(たとえば5:00)を過ぎたかどうか」等の細かい条件を加えることで、厳密なデイリーリセットを実現できます。
  3. 曜日の判定

    • DateTime.Now.DayOfWeek で曜日を取得し、週末はボーナスを追加するなど、簡単な条件分岐で曜日別イベントを実装できます。

このサンプルをベースに、ログインボーナス日替わりミッション曜日イベントなど、ゲーム内の日付管理に必要な機能を拡張してみてください。サーバーサイド連携を行う場合には、クライアント側のローカル時間ではなくサーバー時刻を基準に日付を管理すると、プレイヤーごとの時差や端末時刻の改ざんリスクを回避しやすくなります。

トラブルを回避するテクニック

日付関連の処理は、一見シンプルに思えても想定外のエラーが発生しやすい部分です。以下のポイントを意識してみましょう。

  • 日時の頻繁な取得を避ける
    毎フレームDateTime.Nowを呼び出すと、パフォーマンスに無視できない影響が出るケースがあります。必要最低限のタイミングに絞り込みましょう。

  • テスト環境でのデバッグ
    日替わりイベントなど日付の切り替えが絡むテストは、時間を進めるツールやシミュレート機能を使うと効果的です。
    参考までに、C#のDateTime操作をまとめた情報はこちらにも掲載されています。
    https://www.sejuku.net/blog/52396

  • PlayerPrefsに保存する場合
    ユーザーの端末に時刻を保存することも多いですが、厳密な日付判定を行うには、やはりサーバー側との突合が望ましいです。シングルプレイのオフラインゲームなど、端末依存で問題ないケースのみ保存を利用しましょう。
    下記リンクもチェックして、実装の幅を広げるのがおすすめです。
    https://kyoro-s.com/unity/

まとめ

日付を活用した仕組みは、一度実装してしまえば後からの拡張がとてもラクになります。リアルタイムイベントや日替わり要素の面白さは、プレイヤーが次のログインを待ち遠しく思う要素のひとつ。実装の段階では、端末依存やタイムゾーン、サーバーとの整合性などに注意しておけば、トラブルも最小限に抑えられます。デバッグ時には時間を自由に進める環境を用意するなど、工夫次第で動作確認もスムーズになります。

この記事を読んでもっと実践したいと感じたあなたへ

Unity開発を効率よく進めるためには、実践的なスキルと仲間との交流が欠かせません。
そんな方におすすめのステップが、下記の3つです。

1. 有料教材「どこでもUnity教室」でゲーム制作を短期マスター

  • 5日でシンプルなFPS完成
  • C#や最新のInputSystem、FPS実装まで網羅
  • Discord招待+サンプルプロジェクトDLもセット

Unity初心者でも最短5日で3D FPSが完成!今すぐ始める入門チュートリアルはこちら

https://zenn.dev/ryuryu_game/books/fd28de9d8e963a

2. 無料コミュニティで、疑問をすぐに解消&モチベーションUP

  • 初心者~中級者までOK
  • 質問サポートが充実
  • 学習仲間と切磋琢磨

Discordサーバー参加はこちら

https://discord.gg/5FwuKCacNy

3. “ゲーム開発所RYURYU”がトータルサポート

  • コナラ総販売200件超
  • VR/AR/AIなど最新技術にも精通
  • 多数の出展実績

ご相談・お問い合わせはこちら

https://coconala.com/users/1772507

日付を使った機能を実装すれば、日替わりやリアルタイム要素といった“毎日遊びたくなるゲーム”づくりに大きく近づきます。ぜひ新たなアイデアを形にしながら、ユーザーを飽きさせない仕組みを構築していきましょう。

Discussion