見出し画像

【UNITY3Dをゼロから学ぶ超入門書: DAY3】C#プログラムの基礎を徹底解説!!【FPS開発】

更新日 2024 / 04 / 20

はじめに

\ ココナラ実績140件達成 /
こんにちは!ゲーム開発所RYURYUのりゅうやと申します。
【Unityエンジニア / 男性 / 22歳 / 新潟出身】

このマガジンシリーズは、ゲーム開発の世界に足を踏み入れたいと考えているあなたに向けたものです。

全7日間で構成され、Unityという強力なツールを用いて、基本的な操作からプロフェッショナルなゲーム開発までのステップを詳細に解説します

Day3 : 300円!!(約字を収録) | 次回は4/26日にリリース予定

         ↓↓↓↓↓↓ 有料マガジン ↓↓↓↓↓↓

3日目では、….

自宅にいながら、自分のペースで学べるnoteで、ゲーム制作の第一歩を踏み出しましょう。

有料エリアを購入して頂くと、
頻出エラー5選の徹底解説
②  小テスト (選択式 11問) /  小テストの解説
③  アクティブ編

④ 実践課題 (3つの課題)  /  実践課題の例  
【スペシャルな特典】Unityエンジニアによる開発サポートも付いてきます


【インプット講義】

「いつ(トリガー)」

InputSystemとは。

アクションマップ (Action Map)

アクションマップは、関連するアクションの集まりを管理するコンテナのようなものです。

一つのアクションマップは特定のゲームプレイのコンテキスト(例えば、「メニュー選択中」や「バトル中」)に特化することができ、レイヤーが異なる状況下で異なる入力方法を持つことが可能です。

アクションマップを切り替えることで、ゲームの状態に応じて入力の挙動を動的に変更することができます。


アクション (Action)

アクションはプレイヤーの入力に対する具体的な反応を定義します。例えば、「ジャンプ」や「射撃」といった行動がアクションに該当します。

各アクションは一つ以上のバインディングを持ち、特定のキーやボタンに対応します。アクションを使用することで、コード内で直接キーコードを扱うことなく、入力を管理することができます。

バインディング

バインディングは、特定のアクションを具体的なデバイスのボタンやキー、あるいはマウスの動きなどに結び付けます。

これにより、どのボタンがどのアクションをトリガーするかを定義でき、多様な入力デバイスに対応可能です。

また、バインディングはユーザによるカスタマイズが容易であるため、プレイヤーが自分の好みに合わせてキー配置を変更することができます。

具体例

アクションマップ「Player」には、「Move」というアクションが含まれており、このアクションにはキーボードの「WASD」キーがバインドされています。

つまり、プレイヤーがWASDキーを使用して入力を行うと、その情報が「Move」アクションに送られます。

この設定を基にプログラムを作成することにより、入力に応じて適切な反応を返すインタラクティブなゲームを開発することが可能です。

// このメソッドはプレイヤーの移動入力を処理します
public void OnMove(InputAction.CallbackContext context)
{
    // 入力が実行されたとき(例えばWASDキーが押されたとき)、以下のコードブロックが実行されます
    if (context.performed)
    {
        // コンソールにログを出力し、移動が開始されたことを表示します
        Debug.Log("移動が開始されました!");
    }
}


Unityのライフサイクル

Unityのライフサイクルは、特定のメソッドが特定の順序で自動的に呼ばれることによってゲームの動作が制御されます。

1. Awake

  • Awake メソッドは、スクリプトインスタンスがロードされたときに一度だけ呼ばれます。このメソッドは、ゲームオブジェクトが有効になる前、他のオブジェクトとの関連付けや初期設定に適しています。

2. Start

  • Start メソッドは、Awake メソッドの直後に、スクリプトがアクティブになったときに一度だけ呼ばれます。主に、初期化処理に使用され、Awake で設定されたパラメータに基づいてのセットアップを行います。

3. Update

  • Update メソッドは、毎フレーム呼ばれます。このメソッドはゲームの主要なロジック、例えばユーザー入力の処理やオブジェクトの動き、時間に依存したチェックなどを行うのに使われます。

4. FixedUpdate

  • FixedUpdate メソッドは、物理計算のアップデートごとに定期的に呼ばれます。このメソッドは一定の間隔で実行されるため、物理演算やその他の間隔を要する処理に適しています。

5. LateUpdate

  • LateUpdate メソッドは、すべてのUpdate メソッドが呼び出された後に毎フレーム呼ばれます。カメラの追従など、他のオブジェクトに依存する動作を実装するのに適しています。

6. OnDestroy

  • OnDestroy メソッドは、ゲームオブジェクトが破棄される直前や、スクリプトが非アクティブ/破棄されるときに呼ばれます。リソースのクリーンアップや、他のオブジェクトへの最後の通知を行うのに役立ちます。

using UnityEngine;

public class LifecycleExample : MonoBehaviour
{
    // Awakeメソッド: オブジェクトがロードされた時に一度だけ呼ばれる
    void Awake()
    {
        Debug.Log("Awake called: オブジェクトのロード時に初期設定を行います");
    }

    // Startメソッド: オブジェクトが初めてアクティブになるときに一度だけ呼ばれる
    void Start()
    {
        Debug.Log("Start called: オブジェクトの初期化処理をここで行います");
    }

    // Updateメソッド: 毎フレーム呼ばれる
    void Update()
    {
        Debug.Log("Update called: フレームごとの更新処理をここで行います");
    }

    // FixedUpdateメソッド: 一定間隔で呼ばれる(物理演算用)
    void FixedUpdate()
    {
        Debug.Log("FixedUpdate called: 物理演算の更新処理をここで行います");
    }

    // LateUpdateメソッド: すべてのUpdateメソッドが呼ばれた後に毎フレーム呼ばれる
    void LateUpdate()
    {
        Debug.Log("LateUpdate called: 他のアップデート処理の後に行う処理をここで行います、例えばカメラの追従など");
    }

    // OnDestroyメソッド: オブジェクトが破壊される直前に呼ばれる
    void OnDestroy()
    {
        Debug.Log("OnDestroy called: オブジェクトが破壊される前にクリーンアップを行います");
    }
}


UGUI(Unity GUI)

エディタから設定可能なGUIシステムで、主にゲーム内UIに使用されます。

シーン内にCanvasオブジェクトを設置し、その上にButtonTextImageなどのUIコンポーネントを配置して構築します。

Buttonコンポーネント

  • インタラクション: ユーザーがクリックすることで特定のアクションをトリガーするUI要素です。

  • カスタマイズ可能: 背景色、テキスト、画像などをカスタマイズして視覚的に調整できます。

  • イベントハンドラー: `OnClick()`イベントを使用して、クリック時に呼び出されるメソッドを指定できます。

Textコンポーネント

  • 表示用途: ゲーム内で文字情報を表示するために使用されます。

  • スタイリング: フォント、サイズ、カラー、アラインメントなどのスタイリングオプションが豊富です。

  • ダイナミックテキスト: スクリプトからテキスト内容を動的に更新することが可能です。

Imageコンポーネント

  • 画像表示: スプライトやテクスチャをUI要素として表示するために用います。

  • 変形可能: 画像のサイズやアスペクト比を自由に調整できます。

  • マスキング: 他のUIコンポーネントと組み合わせて、特定の形状で画像をマスクすることが可能です。

「どうしたら(条件)」

制御文

制御文は、プログラムのフローを制御し、特定の条件に基づいて異なるアクションを実行するために使用されます。

演算子

Unityでゲームロジックを記述する際、様々な種類の演算子を利用して条件式を評価します。

比較演算子

比較演算子は、二つの値を比較し、その比較結果に基づいて真 (true) または偽 (false) を返します。これらは条件分岐(if文など)の決定に頻繁に使用されます。

`==` (等しい): 左右のオペランドが等しい場合に true を返します。

`!=` (等しくない): 左右のオペランドが等しくない場合に true を返します。

`>` (より大きい): 左のオペランドが右のオペランドより大きい場合に true を返します。

`<` (より小さい): 左のオペランドが右のオペランドより小さい場合に true を返します。

`>=` (以上): 左のオペランドが右のオペランド以上である場合に true を返します。

`<=` (以下): 左のオペランドが右のオペランド以下である場合に true を返します。

int score = 85;
if (score >= 50)
{
    Debug.Log("Passed");
}

論理演算子

論理演算子は、一つまたは複数のブール条件式を組み合わせて評価し、最終的な真偽値を導き出します。これにより、より複雑な条件を表現することが可能になります。

`&&` (AND): すべての条件が真である場合に true を返します。

`||` (OR): 条件のいずれか一つが真である場合に true を返します。

`!` (NOT): 条件の真偽値を反転します(真が偽に、偽が真に変わります)。

bool hasKey = true;
bool isDoorLocked = true;

if (hasKey && isDoorLocked)
{
    Debug.Log("You can open the door");
}


if文

`if` 文は、指定された条件が真(true)である場合にのみ、ブロック内のコードを実行します。例えば、プレイヤーの体力が0以下になったかどうかをチェックする場合に使用されます。

if (playerHealth <= 0)
{
    Debug.Log("Player is dead.");
}

if文-else文

`if-else` 文は、条件が真の場合と偽の場合で異なるアクションを実行します。これにより、より複雑な決定をスクリプトに組み込むことができます。

if (playerHealth > 0)
{
    Debug.Log("Player is alive.");
}
else
{
    Debug.Log("Player is dead.");
}


Ray判定

Ray判定は、3D空間での視線や射撃の軌道をシミュレートする強力なツールです。`RaycastHit` オブジェクトを使用して、レイが何かと交差したかどうかを検出します。

RaycastHit hit;
if (Physics.Raycast(transform.position, transform.forward, out hit, 100))
{
    Debug.Log("Hit: " + hit.collider.name);
}

Ray判定は、視線がクリックされたオブジェクトに到達するかどうかを確認したり、射撃ゲームでターゲットを狙ったりする際に特に有用です。

「何をするのか?(アクション)」

1. オブジェクトの生成・破壊

オブジェクトの生成

Unityでオブジェクトを生成するには、Instantiateメソッドを使用します。

using UnityEngine;

public class ObjectSpawner : MonoBehaviour
{
    public GameObject objectToSpawn; // 生成するオブジェクトのプレハブ

    void Start()
    {
        // 指定された位置と回転でオブジェクトを生成
        Instantiate(objectToSpawn, new Vector3(0, 0, 0), Quaternion.identity);
    }
}

オブジェクトの破壊

オブジェクトを破壊するには、Destroyメソッドを使用します。

using UnityEngine;

public class ObjectDestroyer : MonoBehaviour
{
    public GameObject objectToDestroy; // 破壊するオブジェクト

    void Start()
    {
        // オブジェクトを破壊
        Destroy(objectToDestroy, 2.0f); // 2秒後にオブジェクトを破壊
    }
}

2. コンポーネントの取得

Unityでコンポーネントを取得するには、GetComponentメソッドを使用します。

using UnityEngine;

public class ComponentGetter : MonoBehaviour
{
    private Rigidbody rb;

    void Start()
    {
        // このゲームオブジェクトのRigidbodyコンポーネントを取得
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (rb != null)
        {
            // Rigidbodyコンポーネントを使用して操作を行う
            rb.AddForce(Vector3.up * 10);
        }
    }
}

3. オブジェクト・コンポーネントの表示・非表示

オブジェクトやコンポーネントを表示・非表示にするには、SetActiveメソッドやenabledプロパティを使用します。

using UnityEngine;

public class VisibilityToggler : MonoBehaviour
{
    public GameObject targetObject;

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            // オブジェクトの表示・非表示を切り替え
            targetObject.SetActive(!targetObject.activeSelf);
        }
    }
}

4. オブジェクトの移動・回転・拡大

オブジェクトの移動、回転、拡大は、Transformコンポーネントを通じて行います。

移動

using UnityEngine;

public class ObjectMover : MonoBehaviour
{
    public float speed = 5.0f;

    void Update()
    {
        float move = speed * Time.deltaTime;
        transform.Translate(Vector3.forward * move);
    }
}

回転

using UnityEngine;

public class ObjectRotator : MonoBehaviour
{
    public float rotationSpeed = 100.0f;

    void Update()
    {
        float rotation = rotationSpeed * Time.deltaTime;
        transform.Rotate(Vector3.up, rotation);
    }
}

拡大

using UnityEngine;

public class ObjectScaler : MonoBehaviour
{
    public float scaleSpeed = 2.0f;

    void Update()
    {
        float scale = 1 + scaleSpeed * Time.deltaTime;
        transform.localScale *= scale;
    }
}

結論

これらの基本的な操作を組み合わせることで、Unityでゲームオブジェクトの管理や操作を行うことができます。各スクリプトは独立して動作しますが、実際のゲーム開発ではこれらを組み合わせて複雑な挙動を実現します。


【インプットテスト】

1.InputSystemとは。

  • ゲーム内でのキャラクターの動きを制御するシステム

  • プレイヤーの入力を処理するためのUnityの新しいシステム

  • ゲームのグラフィックを向上させるためのツール

2.UnityのUpdateメソッドについての説明として正しいものはどれですか。

  • Updateメソッドは物理演算の更新ごとに一定間隔で呼ばれます。

  • Updateメソッドは毎フレーム呼ばれ、ゲームの主要なロジックを処理します。

  • Updateメソッドはゲームオブジェクトが破壊される直前に呼ばれます。

3.A && B の結果は何ですか?

const bool A = true; 
const bool B = false;
Debgu.Log(A&&B);
  • true

  • false

  • null

4. if 文についての説明として正しいものはどれですか。

  • if 文は条件が偽(false)の場合にのみコードを実行します。

  • if 文は条件が真(true)の場合にのみコードを実行します。

  • if 文は条件に関係なく常にコードを実行します。

5.以下のコードが実行された際に出力されるデバッグログを特定してください。

const bool A = true; 
const bool B = false;

if (A || B)
{
   Debug.Log("パターン1");
}
else if (A && B)
{
  Debug.Log("パターン2");
}
else
{
  Debug.Log("パターン3");
}
  • パターン1

  • パターン2

  • パターン3

6..Rayを使った当たり判定で正しい記述はどれですか。

  • Rayはゲームオブジェクトに直接影響を与える物理オブジェクトです。

  • Ray判定はレイが何も交差しない場合にのみ使用されます。

  • Ray判定は3D空間でレイがオブジェクトと交差するかを検出する方法です。


【インプットテストの回答】

  1. プレイヤーの入力を処理するためのUnityの新しいシステム

  2. Updateメソッドは毎フレーム呼ばれ、ゲームの主要なロジックを処理します。

  3. false

  4. if 文は条件が真(true)の場合にのみコードを実行します。

  5. パターン1

  6. Ray判定は3D空間でレイがオブジェクトと交差するかを検出する方法です。


【アウトプット講義】

「いつ(トリガー)」

InputSystemのダウンロード方法

① Window > Package Manager

② ドロップダウンで、Unity Registryを選択

③ 検索バーからInputSystemを検索


InputActionMapの作成

①Unityエディタの`Assets`メニューから`Create > Input Actions`を選択して新しいInput Actionsファイルを作成します。

②このファイルを開き、`Action Maps`セクションに新しいAction Mapを追加し、名前を付けます(例:PlayerActions)。

③アクションマップへアクションを追加する

  • 移動: `PlayerActions`に`Move`アクションを追加し、対応する入力タイプ(例:StickやWASDキー)を設定します。

  • クリック: `Click`アクションを追加し、マウスの左クリックにバインドします。

  • Eキー: `Interact`アクションを追加し、キーボードの`E`キーにバインドします。


「どうしたら(条件)」 「何をするのか?(アクション)」

Input Systemとプログラムの紐付け

Input Action Assetをスクリプトで利用するには、まずスクリプト内でInputActionMapのインスタンスを作成し、各アクションの`performed`イベントにメソッドを登録します。

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    public InputActionAsset inputActions;

    private void OnEnable()
    {
        var gameplayActions = inputActions.FindActionMap("PlayerActions");
        gameplayActions.FindAction("Move").performed += OnMovePerformed;
        gameplayActions.Enable();
    }

    private void OnMovePerformed(InputAction.CallbackContext context)
    {
        Vector2 inputVector = context.ReadValue<Vector2>();
        // 移動処理
    }
}

4. キー入力によるオブジェクトの生成

`E`キーを押すと特定のオブジェクトを生成する機能を追加します。

private void OnInteractPerformed(InputAction.CallbackContext context)
{
    Instantiate(prefab, transform.position, Quaternion.identity);
}

5. 右クリックでオブジェクトを生成

マウスの右クリックでRayを飛ばし、ヒットした場所にオブジェクトを生成します。

private void OnRightClickPerformed(InputAction.CallbackContext context)
{
    Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
    if (Physics.Raycast(ray, out RaycastHit hit))
    {
        Instantiate(prefab, hit.point, Quaternion.identity);
    }
}

6. 左クリックでオブジェクトを破壊

マウスの左クリックでRayを飛ばし、ヒットしたオブジェクトを破壊します。

private void OnLeftClickPerformed(InputAction.CallbackContext context)
{
    Ray ray = Camera.main.ScreenPointToRay(Mouse.current.position.ReadValue());
    if (Physics.Raycast(ray, out RaycastHit hit))
    {
        Destroy(hit.collider.gameObject);
    }
}

これらの基本をマスターすることで、Unityでのインタラクティブなゲーム環境の構築が可能になります。各ステップを詳細に理解し、実際のプロジェクトへ応用してみてください。


【アウトプット課題】



【アウトプット課題の回答】



おわりに


ご不明点や疑問点がある方は、ぜひ、ゲーム開発所RYURYUの公式LINEの無料サポートをご活用ください。

Unityの基本操作からゲーム・VR開発のノウハウまで幅広くサポート致します!


TOP記事


ボタンを実装してみよう。

1. UI要素の追加

Unityエディタの階層ビュー(Hierarchy)で右クリックし、「UI」から「Button」を選択します。これにより、CanvasとButtonオブジェクトがシーンに追加されます。CanvasはUI要素を表示するための領域を提供し、Buttonはクリック可能なUI要素です。

2. ボタンの設定

追加されたボタンを選択し、インスペクター(Inspector)ビューでボタンのプロパティを確認し、必要に応じてボタンのテキストやデザインを変更します。

3. スクリプトの作成

次に、ボタンのクリックイベントを処理するためのスクリプトを作成します。プロジェクトビュー(Project)で右クリックし、「Create」->「C# Script」を選択して新しいスクリプトを作成します。スクリプトには適当な名前を付けましょう(例えばButtonHandler)。

using UnityEngine;
using UnityEngine.UI; // UI要素を扱うために必要

public class ButtonHandler : MonoBehaviour
{
    public Button yourButton; // パブリック変数としてボタンを宣言

    void Start()
    {
        yourButton.onClick.AddListener(TaskOnClick); // ボタンのクリックイベントにリスナーを追加
    }

    void TaskOnClick()
    {
        Debug.Log("You have clicked the button!"); // ボタンをクリックするとログが出力される
    }
}

4. スクリプトのアタッチと設定

作成したスクリプトをCanvasにドラッグ&ドロップしてアタッチします。スクリプトのyourButton変数に、ボタンをドラッグして関連付けます。

5. 実行してテスト

Unityエディタの再生ボタンをクリックしてゲームを実行します。UIに表示されているボタンをクリックし、コンソールウィンドウにログが出力されることを確認します。

よろしければサポートお願いします! いただいたサポートはクリエイターとしての活動費に使わせていただきます!by ゲーム開発所RYURYU