digitalcontent.jp マンガ×図解解説メディア

Gemini×Unityで作るカフェ経営ゲーム第5回:FPS手元操作と修理ミニゲーム

編集

まなびコミック編集部 監修


Unity×AI開発講座【第5回】

『Gemini & ChatGPT × Unity』で本格カフェ経営シミュレーションを作る!

第一人称視点での手元アクション、圧力ゲージ修理ミニゲーム、ドーナツ陳列判定を実装しよう!


第5回の実装を開始

「経営シミュレーションに臨場感を足したい!でも、第一人称視点への切り替えや、手元で行うインタラクティブなミニゲームはどう作れば良い?」

カフェ経営ゲームのゲーム性をグッと高めるのが、プレイヤー自らが手元で行う「アクティビティ」です。機器故障時の圧力ゲージ修理ミニゲームや、トングを使ったドーナツ陳列精度判定を盛り込むことで、単なる数値管理にとどまらない没入感抜群の体験をプレイヤーに提供できます。

第5回となる本記事では、三人称視点(経営)と第一人称視点(手元アクション)の視点切り替え、タイミング判定修理ミニゲーム、トング陳列判定、そして故障時の煙・蒸気エフェクト(Particle System)制御までを完全解説します!

1. はじめに(第5回で実装するプレイヤーアクション&ミニゲーム)

シミュレーションゲームにおいて、店舗の全体を見渡すマクロ視点と、プレイヤーが直接手元で作業するミクロ視点を使い分けることで、ゲームの緩急とメリハリが生まれます。

マクロ視点のみ(作業的になりやすい構造)

ボタンを押すだけで故障が自動治癒、陳列が自動完了。見守るだけになり、プレイヤーの直接的な「介入感」が薄れてしまう。

FPS手元アクション(本講座の方式)

故障中のマシンに近寄り[E]キーで第一人称視点へダイブ。タイミング合わせで修理し、トングでドーナツを配置する直感アクション。

本章では、視点遷移のカメラ制御から、ゲージタイミング判定ロジック、トングでの位置精度判定、視覚効果(煙・湯気)の連動までを一気に構築します。

2. Step 1: 三人称(クォータービュー)と第一人称(FPS手元操作)のカメラ切り替え設計

経営画面(Overview Camera)と、マシン修理・陳列時の手元画面(First Person Camera)をスムーズに切り替えるカメラマネージャーを設計します。

視点切り替えとカーソル制御の手順

モード カメラ位置 / 視点 カーソル状態・操作方法
1. 店舗経営モード(Overview) 店舗俯瞰(クォータービュー:Y:8, Z:-8) `Cursor.lockState = CursorLockMode.None`(UIや家具を選択・配置)
2. 手元操作モード(FPS/Action) ★重要 故障機器の直前(手元クローズアップ) [E]キーで突入。ミニゲームUIのタイミング判定またはドラッグ操作を実行

初心者補足:カメラの優先度(Priority)切り替えとは?

Cinemachineなどのカメラアセットを使用する場合、各カメラの Priority(優先度)の値を変更するだけで、Unityが自動的に滑らかな補間(ブレンド移動)で視点を移動してくれます。

\ タイミング判定ミニゲームコードをAIに自動生成させよう! /


Step 2: MachineRepairMinigameスクリプト生成へ

3. Step 2: AIプロンプトによる「MachineRepairMinigame.cs」スクリプトの自動生成

圧力ゲージの針が振り子のように往復運動し、緑色の適正領域(Target Zone)に重なった瞬間に[E]キーを押すタイミグ判定ミニゲームを構築します。

コピペで使える!修理ミニゲーム生成プロンプト

Unity 2022.3 (C#) で動作する「MachineRepairMinigame.cs」を作成してください。

【要件】
1. 圧力ゲージ(0〜100%)の針の値 `currentValue` が Sine波(Mathf.PingPong)で毎フレーム往復運動させてください。
2. 緑色の成功領域(targetMin: 60%, targetMax: 80%)を定義してください。
3. プレイヤーが [E] キーを押した際の判定:
   - `currentValue` が targetMin 〜 targetMax の間にある場合 ➔ 成功イベント(OnRepairSuccess)を発火、煙パーティクルを停止し、蒸気エフェクトを一瞬再生。
   - 範囲外の場合 ➔ 失敗イベント(OnRepairFailed)を発火、揺れ(Camera Shake)演出を起こし再度挑戦。
4. UI表示用に Slider(針の位置)と Image(ターゲット領域の色)の参照を設定してください。

生成された C# スクリプト:MachineRepairMinigame.cs

using UnityEngine;
using UnityEngine.UI;

public class MachineRepairMinigame : MonoBehaviour
{
    [SerializeField] private Slider needleSlider;
    [SerializeField] private ParticleSystem smokeParticle;  // 故障中の煙
    [SerializeField] private ParticleSystem steamParticle;  // 修理成功時の蒸気
    [SerializeField] private GameObject minigameUI;

    public float needleSpeed = 2.0f;
    public float targetMin = 0.6f; // 60%
    public float targetMax = 0.8f; // 80%

    private bool isPlaying = false;
    private float currentVal = 0f;

    public System.Action OnSuccess;

    public void StartMinigame()
    {
        isPlaying = true;
        minigameUI.SetActive(true);
        if (smokeParticle != null) smokeParticle.Play();
    }

    private void Update()
    {
        if (!isPlaying) return;

        // 針の往復運動(0.0 〜 1.0)
        currentVal = Mathf.PingPong(Time.time * needleSpeed, 1.0f);
        if (needleSlider != null) needleSlider.value = currentVal;

        // タイミング判定ボタン入力
        if (Input.GetKeyDown(KeyCode.E) || Input.GetKeyDown(KeyCode.Space))
        {
            CheckTiming();
        }
    }

    private void CheckTiming()
    {
        if (currentVal >= targetMin && currentVal <= targetMax)
        {
            // 成功
            isPlaying = false;
            minigameUI.SetActive(false);
            if (smokeParticle != null) smokeParticle.Stop();
            if (steamParticle != null) steamParticle.Play();

            Debug.Log("修理成功!機器が正常復旧しました。");
            OnSuccess?.Invoke();
        }
        else
        {
            // 失敗
            Debug.LogWarning("修理失敗!タイミングがズレています。");
        }
    }
}

4. Step 3: トング操作とドーナツケース陳列判定(DonutPlacementController.cs)の実装

プレイヤーがトングでドーナツを掴み、ショーケース内のトレイへ配置する手元アクションを実装します。位置が中央に近いほど高得点(Placement Accuracy)になります。

ドラッグ&レイキャスト移動

マウスカーソルの位置に3Dモデル(ドーナツ+トング)を追従移動させ、クリックで落下配置させます。

陳列精度(Placement Accuracy)計算

トレイの中心座標との距離(Vector3.Distance)を測定し、100%に近いほど店舗映えスコアがアップします。

DonutPlacementController.cs スクリプト

using UnityEngine;

public class DonutPlacementController : MonoBehaviour
{
    [SerializeField] private Transform trayCenterTarget; // 理想の陳列中心
    [SerializeField] private GameObject donutHoldingObject;
    [SerializeField] private LayerMask showcaseLayer;

    private bool isHolding = true;

    private void Update()
    {
        if (!isHolding) return;

        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out RaycastHit hit, 10f, showcaseLayer))
        {
            donutHoldingObject.transform.position = hit.point + new Vector3(0, 0.05f, 0);

            // クリックで配置決定
            if (Input.GetMouseButtonDown(0))
            {
                PlaceDonut(hit.point);
            }
        }
    }

    private void PlaceDonut(Vector3 placePosition)
    {
        isHolding = false;
        float distance = Vector3.Distance(placePosition, trayCenterTarget.position);

        // 精度(Placement Accuracy)の算出(0.2m以内で100%)
        float accuracy = Mathf.Clamp01(1.0f - (distance / 0.2f)) * 100f;
        Debug.Log($"ドーナツ陳列完了!精度 (Placement Accuracy): {accuracy:F1}%");

        // 店舗評価へ還元
        if (accuracy > 80f)
        {
            GameManager.Instance?.SetRating(GameManager.Instance.currentRating + 0.1f);
        }
    }
}

\ パーティクルとSEで臨場感を極めよう! /


Step 4: エフェクト&SE演出へ

5. Step 4: パーティクルエフェクト(Particle System)と音響(SE)の演出制御

機器の故障時・修理完了時・コーヒー抽出時に、Unityの **Particle System** を起動・停止させる制御スクリプトを追加し、視覚的な臨場感を最大化します。

パーティクル制御スクリプトの組み込み

1

Particle System の準備

エスプレッソマシンのプレハブ配下に【Effects】➔【Particle System】を追加。名前を「SmokeParticle」にし、黒っぽい煙がモクモク昇るよう設定します。

2

C# からの再生・停止コード

`particle.Play();` でエフェクト開始、`particle.Stop();` で停止制御を行います。同時に `AudioSource.PlayOneShot(repairSE);` でカチャンという修理音を鳴らすとカンペキです。

6. まとめ & よくある質問 (FAQ)

第5回では、単なる経営数値の管理にとどまらない「FPS手元アクション」「タイミング判定修理ミニゲーム」「ドーナツ陳列精度判定」「パーティクル演出」を完成させました!

次回:第6回「Gemini / ChatGPT API連携!リアルタイム口コミ&InstaCafé」へ!

UnityからLLM API(WebAPI)を呼び出し、店内の評価・内装に応じたリアルな口コミや擬似SNS投稿(InstaCafé)を動的生成させます!


第6回記事を読む(準備中)

よくある質問 (FAQ)

Q. 手元操作モードに入った際、プレイヤーが歩き回ってカメラから外れてしまいます。

手元モード突入時にプレイヤー移動スクリプト(`CharacterController` や `NavMeshAgent`)の `.enabled = false;` に設定して移動物理をロックしてください。

Q. ミニゲームの針の動きを途中で速くしたり難易度を変えたい場合は?

`needleSpeed` の数値を変数化し、ゲームの進行度(店舗レベル等)に応じて `needleSpeed += 0.5f;` と加算することで難易度調整が可能です。

サクッと読めて超わかりやすい!

【無料】マンガで全部わかる!

図解&ストーリー形式だから活字が苦手でもスルスル理解!全話を一覧からチェックしよう

マンガ全話一覧を見る(無料)
マンガ全話一覧へ 次話を読む