大学生が母の誕生日に思い出を振り返るアプリを作ってプレゼントした話【技術編】

## 3. ゲーム制作の詳細

前回は「Omoide」というゲームの概要とコンセプトについて紹介しました。今回は、このゲームの技術的な側面や制作過程について詳しく解説していきます。

### 3.1 技術的な詳細

#### 使用したゲームエンジン

Unity を選んだ理由は主に以下の点です：

* クロスプラットフォーム対応（Android/iOSの両方に対応可能）
* 3D空間の構築と操作が直感的
* アセットストアの充実（First Personコントローラーなど必要な機能が揃っている）
* C#というプログラミング言語の学習しやすさ

特に役立った機能は：

* シーン管理システム - メディア選択画面と美術館探索画面の切り替え
* UI Canvas - 直感的なユーザーインターフェースの構築
* Timeline - お祝いメッセージシーンでの演出

#### 使用したアセット

* **Starter Assets - FirstPerson**

    * このアセットは、First Person視点でのキャラクター移動とカメラ制御を提供してくれます。
```csharp
    // FirstPersonControllerの活用例
    public class PlayerInteraction : MonoBehaviour
    {
    [SerializeField] private StarterAssetsInputs starterAssetsInputs;
    [SerializeField] private FirstPersonController firstPersonController;
    // ...
    }
```

<iframe width="560" height="315" src="https://www.youtube.com/embed/4QuPlKzdq14?si=ux-tFJObpFo9wT-2" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

* 利点：
    * モバイル向けの入力制御が最初から実装されている
    * 視点移動やジャンプなどの基本機能が揃っている
    * カスタマイズしやすい構造
<br/>
        
* **Native Gallery**

    * スマートフォンのギャラリーから写真や動画を選択するために利用しました。
```csharp
    // Native Galleryを使った写真選択の例
    NativeGallery.Permission permission = NativeGallery.GetImageFromGallery((path) =>
    {
    if (path != null)
    {
    // 選択された画像を処理
    StartCoroutine(ProcessSelectedImage(path));
    }
    });
```

https://assetstore.unity.com/packages/tools/integration/native-gallery-for-android-ios-112630?locale=ja-JP&srsltid=AfmBOoojYDMXTl9f7CYH50CCSLeLyGx7nSaaiATnWcUKVVP2sfqPQQmj

* 使用した理由：
    * iOS/Android両方に対応している
    * 写真だけでなく動画も取得できる
    * ファイルパスを直接取得できるため扱いやすい
* 使い心地：
    * 基本的な機能は簡単に実装できる
    * ただし、一部の高解像度画像や特殊な形式の動画で問題が発生することも
* **その他使用したアセット**
    * ProBuilder - 美術館の内装モデリング
    * Post Processing Stack - 美しい照明効果
    * DOTween - スムーズなアニメーション

#### プログラミング言語

ゲームのプログラミングには C# を使用しました。
最も重要な核となるコードは「ExhibitFrame.cs」です。これは美術館内の展示フレームの挙動を制御するクラスで、写真・動画の表示とインタラクションを担当しています：

```csharp
// 簡略化したExhibitFrameクラス
public class ExhibitFrame : MonoBehaviour, IInteractable
{
[SerializeField] private RawImage mediaDisplay;
[SerializeField] private VideoPlayer videoPlayer;
[SerializeField] private TextMeshProUGUI messageText;

private MediaItem currentMedia;

// メディアアイテムをフレームに設定
public void SetMediaItem(MediaItem mediaItem)
{
currentMedia = mediaItem;

if (currentMedia.type == MediaItem.MediaType.Photo)
{
LoadPhotoMedia();
}
else if (currentMedia.type == MediaItem.MediaType.Video)
{
SetupVideoMedia();
}

if (messageText != null && !string.IsNullOrEmpty(currentMedia.message))
{
messageText.text = currentMedia.message;
}
}

// インタラクション（拡大表示切替）
public void Interact()
{
ToggleExpand();
}

// その他のメソッド...
}
```
このクラスはインタラクション、メディア表示、メッセージ表示など、ゲームの中核機能を担っています。

開発期間
企画から完成まで、約1週間かかりました

ChatGPT/Claudeによるアシストのおかげで、プログラミング初心者ながら短期間での開発が可能になりました。特に、基本システムの設計やコードの書き方についてのアドバイスが役立ちました。

工夫した点

* **没入感を高めるための工夫**
    * 適切なフィールドオブビュー（FOV）設定
        * モバイル画面での視野角を調整し、没入感と操作性のバランスを取りました
        * 標準60°から75°に拡大し、空間の広がりを感じられるように
    * 展示物との距離感の調整
        ```csharp
        // プレイヤーとの距離に応じた挙動
        public void UpdatePlayerProximity(Transform playerTransform)
        {
        float distance = Vector3.Distance(playerTransform.position, transform.position);
        bool isClose = distance <= interactionDistance;

        if (interactionPrompt != null)
        interactionPrompt.SetActive(isClose);
        }
        ```
    * 美術館の照明設計
        * 展示物に集中するようスポットライトを配置
        * グローバルイルミネーションで自然な光の反射を実現
* **ユーザーフレンドリーなUI/UX**
    * メディア選択画面のグリッドレイアウト
        * サムネイル表示で直感的に選択できるデザイン
        * カテゴリ分けによる整理機能
    * インタラクションヒント表示
        * 展示物に近づくとヒントが表示される仕組み
        * タップ可能な要素が視覚的にわかるデザイン


### おわりに

「Omoide」の開発は、技術的な成長と母へのプレゼントを同時に行うものでした。

この記事によってあなたがIT技術を誰かに使ってプレゼントをするようなきっかけになれば幸いです。
技術的な質問やアドバイスがありましたら、コメント欄にてお気軽にお寄せください。