見出し画像

【Unity】「魔理沙の本返し」のScript公開

unityroomで不定期に開催されているunity1week(Unity1週間ゲームジャム)に参加しました。今回で9回連続9回目になります。今回の期間は2024年8月12日から8月18日までで、テーマは「かえす」でした。


この記事では、このゲームの根幹をなすスクリプト4つを紹介します。途中から有償といたします。

1.GameManager

少し失敗したかもしれません。
StageMangerに機能をつけすぎて、GameManagerがスッカラカンになってしまいました。

using System;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameManager : MonoBehaviour
{
    // GameManagerのシングルトンインスタンス。どのシーンからでもアクセス可能。
    public static GameManager instance;

    // プレイヤーのスタミナを表示するUIのスライダー
    private Slider staminaSlider;

    // ゲーム内で使用するオーディオクリップ
    public AudioClip booksetSound; // 本をセットする音
    public AudioClip goalSound; // ゴールしたときの音
    public AudioClip bgm; // ゲーム中に再生するBGM

    // シングルトンパターンを実装するためのAwakeメソッド
    private void Awake() {
        if (instance == null) {
            // インスタンスが存在しない場合、このオブジェクトをインスタンスとして設定
            instance = this;
            // DontDestroyOnLoad(gameObject); // シーンを切り替えてもGameManagerを破棄しない(コメントアウトされている)
        } else {
            // すでにインスタンスが存在する場合、このオブジェクトを破棄
            Destroy(gameObject);
        }
    }

    // ゲーム開始時に呼び出されるStartメソッド
    public void Start()
    {
        // ゲームの時間を通常速度にリセット
        Time.timeScale = 1;

        // 現在再生中のBGMを停止
        SoundManager.i.StopBgm();

        // "Stamina"タグが付いているオブジェクトからSliderコンポーネントを取得
        // スタミナバーが存在する場合、そのコンポーネントを取得
        if (GameObject.FindGameObjectWithTag("Stamina") != null)
        {
            staminaSlider = GameObject.FindGameObjectWithTag("Stamina").GetComponent<Slider>();
        }
        else
        {
            // スタミナバーがない場合、通常はタイトル画面やステージセレクト画面のため、BGMを再生
            SoundManager.i.PlayBgm(bgm);
        }
    }

    // プレイヤーのスタミナUIを更新するメソッド
    // currentStamina: 現在のスタミナ値
    // totalStamina: スタミナの最大値
    public void UpdateStaminaUI(float currentStamina, float totalStamina)
    {
        if (staminaSlider != null)
        {
            // スライダーの最大値を設定
            staminaSlider.maxValue = totalStamina;
            // スライダーの現在の値を設定
            staminaSlider.value = currentStamina;
        }
    }
    
    // 指定されたステージをロードするメソッド
    // stageName: ロードするステージのシーン名
    public void LoadStage(string stageName) {
        SceneManager.LoadScene(stageName); // 指定されたシーンをロード
    }

    // タイマーを停止するメソッド
    public void StopTimer()
    {
        // 現在のシーン内でStageManagerコンポーネントを持つオブジェクトを検索
        StageManager stageManager = FindObjectOfType<StageManager>();
        if (stageManager != null)
        {
            // タイマーを停止
            stageManager.isTimerRunning = false;
        }
    }

    // ゲームオーバー時の処理を行うメソッド
    public void GameOver()
    {
        // ここにゲームオーバー時の具体的な処理を追加
        Debug.Log("Game Over"); // デバッグ用にログを出力
    }
}

2.StageManger

ステージ毎に配置します。
ステージ毎のチェックポイント(本返却ポイント)などを管理します。

using System;
using UnityEngine;
using TMPro;
using System.Collections.Generic;
using UnityEngine.Playables;
using unityroom.Api; // UnityRoomのAPIを使用するための名前空間

public class StageManager : MonoBehaviour
{
    [SerializeField]
    private MarisaController player; // プレイヤーキャラクターのスクリプト参照

    // UI要素の参照
    [SerializeField]
    private TextMeshProUGUI stageNameText; // ステージ名を表示するテキスト
    [SerializeField]
    private TextMeshProUGUI checkpointText; // チェックポイント数を表示するテキスト
    [SerializeField]
    private TextMeshProUGUI timeText; // 経過時間を表示するテキスト
    [SerializeField]
    private TextMeshProUGUI bestTimeText; // ベストタイムを表示するテキスト
    
    [SerializeField]
    public int stageNumber; // ステージ番号を保持するフィールド
    [SerializeField]
    private List<Transform> checkpoints; // チェックポイントのリスト
    [SerializeField]
    private AudioClip stageBgm; // ステージBGM

    // ステージクリアに関連する設定
    [Header("Stage Clear Settings")]
    [SerializeField] private PlayableDirector stageClearTimeline; // ステージクリアのタイムライン

    private bool allCheckpointsPassed = false; // 全てのチェックポイントに接触したかのフラグ

    private int totalCheckpoints; // チェックポイントの総数
    private int passedCheckpoints; // 通過したチェックポイント数
    [NonSerialized] public float elapsedTime; // 経過時間を保持するフィールド
    [NonSerialized] public bool isTimerRunning; // タイマーが動作しているかどうかを管理するフラグ
    [SerializeField] private PlayableDirector CountDownTimeline; // カウントダウン用のタイムライン

    // ベストタイムに関連する設定
    [NonSerialized] public float bestTime; // ステージのベストタイム
    public GameObject bestTimeUpdateText; // ベストタイム更新時に表示するテキスト
    public TextMeshProUGUI clearTimeText; // ステージクリア後のタイムを表示するテキスト
    
    // サウンド関連の設定
    [SerializeField] AudioClip ClearSound; // ステージクリア時のSE
    [SerializeField] AudioClip GameOverSound; // ゲームオーバー時のSE
    [SerializeField] AudioClip CountDownSound; // カウントダウン時のSE

    private void Start() {
        
        // EasySaveを使用してステージのベストタイムを取得
        bestTime = ES3.Load<float>("BestTime" + stageNumber, 9999.99f);
        bestTimeText.text = string.Format("{0:0000.00}", bestTime); // ベストタイムをテキストに表示
        
        // チェックポイントの総数と経過時間を初期化
        totalCheckpoints = checkpoints.Count;
        passedCheckpoints = 0;
        elapsedTime = 0f;

        // 各種UIの初期表示を更新
        UpdateStageNameText(); // ステージ名を表示
        UpdateCheckpointText(); // チェックポイント情報を表示
        UpdateTimerText(); // 経過時間を表示
    }
    
    // ステージ開始時に呼び出されるメソッド
    public void StageStart() {
        isTimerRunning = true; // タイマーを開始
        player.isGameStarted = true; // プレイヤーにゲーム開始を通知
        SoundManager.i.PlayBgm(stageBgm); // ステージBGMを再生
    }

    // カウントダウン開始時に呼び出されるメソッド
    public void CountdownStart() {
        // カウントダウン用のタイムラインが設定されている場合、それを再生
        if (CountDownTimeline != null)
        {
            CountDownTimeline.Play();
        }
    }
    
    private void Update() {
        // タイマーが動作中の場合のみ経過時間を更新
        if (isTimerRunning)
        {
            elapsedTime += Time.deltaTime;
            UpdateTimerText(); // 経過時間のUIを更新
        }
    }

    // チェックポイントを通過した際に呼び出されるメソッド
    public void CheckpointPassed(Transform checkpoint) {
        if (checkpoints.Contains(checkpoint)) {
            passedCheckpoints++; // 通過チェックポイント数を増加
            checkpoints.Remove(checkpoint); // チェックポイントリストから削除
            UpdateCheckpointText(); // チェックポイント数をUIに更新
        }
    }

    // ステージ名のテキストを更新するメソッド
    private void UpdateStageNameText() {
        stageNameText.text = "Stage " + stageNumber; // ステージ名を表示
    }

    // チェックポイント数のテキストを更新するメソッド
    private void UpdateCheckpointText() {
        checkpointText.text = string.Format("{0}/{1}", passedCheckpoints, totalCheckpoints);
    }

    // 経過時間のテキストを更新するメソッド
    private void UpdateTimerText() {
        // 経過時間を4桁の少数点2桁で表示
        timeText.text = string.Format("{0:0000.00}", elapsedTime);
    }

    // ステージクリア時に呼び出されるメソッド
    private void StageClear() {
        Debug.Log("Stage Cleared!");

        // プレイヤーのアニメーションをidleDownに変更
        player.animancer.Play(player.idleDown);
        
        // ゴールのSEを再生
        SoundManager.i.PlaySe(GameManager.instance.goalSound);
        
        // 経過時間がベストタイムより短い場合、ベストタイムを更新
        if (elapsedTime < bestTime) {
            bestTime = elapsedTime; // ベストタイムを更新
            ES3.Save<float>("BestTime" + stageNumber, bestTime); // ベストタイムを保存
            bestTimeUpdateText.SetActive(true); // ベストタイム更新メッセージを表示
        }
        
        // クリアタイムをUIに表示
        clearTimeText.text = string.Format("今回のタイム:"+"{0:F2}"+"秒", elapsedTime);
        
        player.stageClear = true; // プレイヤーのstageClearフラグをtrueに設定
        
        // スコアをUnityroomのAPIに送信
        UnityroomApiClient.Instance.SendScore(stageNumber, elapsedTime, ScoreboardWriteMode.Always);
        
        // すべての敵キャラクターにゲームオーバー処理を実行
        EnemyController[] enemies = FindObjectsOfType<EnemyController>();
        foreach (EnemyController enemy in enemies)
        {
            enemy.HandleGameOver(); // ゲームオーバー時の処理を実行
        }

        // タイマーを停止
        isTimerRunning = false;
        SoundManager.i.StopBgm(); // BGMを停止

        // ステージクリア用のタイムラインを再生
        if (stageClearTimeline != null)
        {
            stageClearTimeline.Play();
        }
    }

    // チェックポイント通過時の処理
    public void CheckpointPassed()
    {
        passedCheckpoints++; // 通過チェックポイント数を増加
        SoundManager.i.PlaySe(GameManager.instance.booksetSound); // チェックポイント通過音を再生
        UpdateCheckpointText(); // チェックポイント数をUIに更新

        // すべてのチェックポイントを通過した場合、クリアの準備を行う
        if (passedCheckpoints >= totalCheckpoints)
        {
            allCheckpointsPassed = true;
            Debug.Log("All checkpoints passed. Return to the start to finish the stage.");
        }
    }

    // ゴールに到達した際の処理
    public void GoalReached()
    {
        // すべてのチェックポイントを通過している場合、ステージクリア処理を行う
        if (allCheckpointsPassed)
        {
            StageClear(); // ステージクリア処理を呼び出す
        }
        else
        {
            Debug.Log("You must pass all checkpoints before returning to the start!"); // チェックポイントを通過していない場合、メッセージを表示
        }
    }
    
    // ステージクリア時のサウンド再生
    public void ClearSoundPlay()
    {
        SoundManager.i.PlaySe(ClearSound);
    }
    
    // ゲームオーバー時のサウンド再生
    public void GameOverSoundPlay()
    {
        SoundManager.i.PlaySe(GameOverSound);
    }
    
    // カウントダウン時のサウンド再生
    public void CountDownSoundPlay()
    {
        SoundManager.i.PlaySe(CountDownSound);
    }
}

3.MarisaController

プレイヤーである魔理沙を動かすスクリプトです。
AnimancerProが必須です。
Playerタグをつける必要があります。

ここから先は

21,320字 / 2画像

¥ 100

この記事が気に入ったらサポートをしてみませんか?