見出し画像

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

更新日 2024 / 05 / 15 

はじめに

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

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

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

2日目では、Input SystemとC#プログラミングに焦点を当てて学習を進めます!

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


【インプット講義】

C#スクリプトの基礎を理解する

スクリプト とは。

「いつ(トリガー)」
「どうしたら(条件)」
「何をするのか ?(アクション)」

いつ(トリガー)

トリガーは、スクリプトが実行されるきっかけとなるイベントです。Unityのライフサイクルイベント(例えば、オブジェクトが最初にアクティブになるときの Start や毎フレーム呼ばれる Update)、Input Systemからの入力、GUIのボタンクリックなどがトリガーとして機能します。

どうしたら(条件)

条件は、特定のアクションが実行されるかどうかを制御するためのロジックです。条件文(if文やswitch文など)を使用して、特定の条件下でのみアクションを実行するようにスクリプトを設計します。

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

アクションは、トリガーと条件に基づいて実際に行われる操作です。これには、Unityのコンポーネントをプログラム的に操作することで、オブジェクトの移動、アニメーションの再生、サウンドの再生、状態の更新などが含まれます。

スクリプトの構造

UnityでC#スクリプトを新規作成した場合、次のような基本的なテンプレートが提供されます。これはプログラムを記述するためのスケルトンコードです。

名前空間

using "インポートしたい名前空間" 

名前空間を使用するためのusingディレクティブは、エディタに特定の名前空間(例えばUnityEngine)のクラスやメソッドをプログラムで利用する予定であることを通知します。

人間で言えば、「これから英語を使います!   」だから、「英語を聞き取る準備をしてください」っといった具合です。

クラス

public class Test : MonoBehaviour
{
   //ここに、プログラムを書く。
}

Testという名前のクラスがMonoBehaviourを継承しており、Unityのゲームオブジェクトにアタッチして使用することを表しています。


Startメソッド

ゲーム開始時に一度だけ呼び出されるメソッドで、ゲームオブジェクトの初期化などに用います。

Updateメソッド

ゲームが動作している間、毎フレームごとに呼び出されるメソッドです。プレイヤーの入力のチェックやゲームオブジェクトの移動など、連続的な更新が必要な処理をここに記述します。

メソッドは、クラスの{}中に記述され、具体的な処理は、メソッドの{}中に記述します。また、具体的な処理は、行末に ; をつけます。

基本ルール


変数と定数

変数

変数はデータを格納するための容器です。値はプログラムの実行中に変更することができます。Unityでは、変数を使ってゲームオブジェクトの位置、速度、状態などを格納します。

// 変数: プレイヤーの速度
public float speed = 5.0f;

定数

定数は、その値が一度設定されると変更されない変数です。定数は`const`キーワードを使用して定義され、例えば重力加速度のような変更されない値に使用されます。

// 定数: 重力加速度 
public const float GRAVITY = 9.81f;


データ型

int型

整数値を格納するためのデータ型で、スコアやカウントなどの整数データの管理に使用されます。

int score = 100;

float型

浮動小数点数を格納するためのデータ型です。より精密な数値が必要な場合に使用されます。

float speed = 5.5f;

string型

テキストデータを格納するためのデータ型で、プレイヤーの名前やゲーム内のテキスト表示に使用されます。

string playerName = "John";

Vector3型

3次元空間でのポイントを表すために使用されるデータ型です。位置、速度、方向などを格納するのに用います。

Vector3 position = new Vector3(10, 0, 5);

GameObject型

UnityのすべてのエンティティはGameObjectです。この型を使用してゲームオブジェクトを参照し操作します。

GameObject player = GameObject.Find("Player");

Transform型

UnityのすべてのGameObjectはTransformコンポーネントを持っています。この型を使用して、ゲームオブジェクトの位置、回転、スケールなどを参照し、操作します。

Transform playerTransform = GameObject.Find("Player").transform;


グローバル変数とローカル変数

グローバル変数

スクリプト全体からアクセス可能な変数です。クラスレベルで宣言され、どの関数からもアクセスできます。

ローカル変数

関数内でのみ有効で、関数の外部からはアクセスできない変数です。関数が終了するとそのスコープから消えます。

using UnityEngine;

public class Test
{
    public int hp = 999;  // グローバル変数

    void Start() 
    {
        // ゲームの開始時にhpをログに出力
        Debug.Log(hp);
    }

    void Update() 
    {
        // ローカル変数でスコアを定義し、毎フレームスコアを増加させてログに出力
        int localScore = 100;  // ローカル変数
        localScore = localScore + 1;
        Debug.Log(localScore);
    }
}

int localScore = 100; // ローカル変数
上記は、ローカル変数のため、Update関数の{}の中のみで、利用できる。

メソッド

オブジェクト指向型のプログラムは、お仕事と同様にして捉えるとわかりやすいです。

例えば、レストランの経営を例に挙げると…
クラス
はレストランの自体、メソッドはそこで働くスタッフのアクションやタスク、そして変数はスタッフがアクセスできる情報やツールに例えられます。


引数なし、返り値なし

書き方

private void メソッド名 ()
{
    // ここに具体的な処理を書く。
}

具体例

// メソッド (呼び出し側)
void Start()
{
   PrintMessage();
}

// メソッド (実装側)
void PrintMessage() 
{
    Debug.Log("本日の特別メニューはシーフードパエリアです");
}

このメソッドは、レストランでのメニューの日替わり特別告知を行うスタッフに例えることができます。

「本日の特別メニューはシーフードパエリアです」と毎度アナウンスする担当者のように、特定の情報を提供するだけで、外部からの追加情報を必要とせず、また何かを返すわけでもありません。


引数あり、返り値なし

書き方

private void メソッド名 (引き数の型 引数名)
{
    // ここに具体的な処理を書く。
}

具体例 (引数が1つ)

// メソッド (呼び出し側)
void Start()
{
    RequestDishSpeed(10); // テーブル10に料理を配達してください
}

// メソッド (実装側)
void RequestDishSpeed(int tableNumber) 
{
    Debug.Log("テーブル" + tableNumber + "に料理をお願いします");
}

このタイプのメソッドは、レストランでの注文受付担当者に例えることができます。

客からの注文情報(この場合は場所、例えば「テーブル10に料理をお願いします」)を受け取り、その情報に基づいてキッチン(コンソール)への配達指示(ログ出力)を行いますが、客(呼び出し側)に直接的な返答をするわけではありません。

具体例 (引数が2つ以上)

void Start()
{
    RequestDishDelivery(10, "パスタ", 2); // テーブル10にパスタを2皿お願いします
}

void RequestDishDelivery(int tableNumber, string dishName, int quantity)
{
    // 注文情報をログに出力
    Debug.Log("テーブル" + tableNumber + "に" + dishName + "を" + quantity + "皿お願いします");
}

レストランのウェイターが客(呼び出し側)からの具体的な注文情報(引数)を受け取り、その情報に基づいてキッチン(コンソール)への配達指示(ログ出力)を行いますが、客(呼び出し側)に直接的な返答をするわけではありません。


引数あり、返り値あり

書き方

private 返り値の型 メソッド名 (引き数の型 引数名)
{
    // ここに具体的な処理を書く。
    return 返り値
}

具体例

void Start()
{
    int quantity = 2;  // 注文された料理の数量
    float pricePerItem = 9.99f;  // 単品あたりの価格

    // CalculateTotalBillメソッドを呼び出し、注文の合計金額を計算
    float totalBill = CalculateTotalBill(quantity, pricePerItem);

    // 計算された合計金額をUnityのコンソールに出力
    Debug.Log("合計金額は" + totalBill + "円です");
}

float CalculateTotalBill(int quantityOrdered, float pricePerDish)
{
    return quantityOrdered * pricePerDish;
}

このタイプのメソッドは、レストランでのお会計を行うウェイターに例えることができます。

お客様から受け取った注文の内容(この場合は数量と価格)を元に、合計金額(計算結果)を計算し、それを客(呼び出し側)に提示する役割を持っています。

ウェイターは注文された料理の価格を計算し、客(呼び出し側)を返します。

3種類の引数の書き方の違い

クラスとインスタンス化

クラスはオブジェクトの設計図で、インスタンスはその設計図に基づいて作成された具体的なオブジェクトです。


【インプットテスト】

1.ゲームオブジェクトとは。

  • Unityで作成される3Dモデルのこと

  • ゲームのプログラミングコードを記述するファイル

  • Unityのシーン内に配置できるすべてのエンティティ

2.定数と変数の説明として正しい正しい文章を選んでください。

  • 定数は実行時にその値を変更できるが、変数は初期化時のみ設定可能である。

  • 変数はプログラム実行中にその値を変更可能で、定数は初期化後にその値を変更できない。

  • 定数も変数もプログラム実行中に何度でも値を変更できる。

  • 変数はデータ型を持たないが、定数はデータ型を必要とする。

3.グローバル変数の説明として正しい文章を選んでください。

  • ある関数内でのみアクセス可能な変数

  • プログラムのどこからでもアクセスできる変数

  • 一時的なデータを保存するために使用される変数

4.int型とは。

  • 小数点数を扱うデータ型

  • テキストや文字列を扱うデータ型

  • 整数を扱うデータ型

  • 3次元の座標を表すデータ型

  • ゲームオブジェクトの位置、回転、スケールを管理するデータ型

5.float型とは。

  • 小数点数を扱うデータ型

  • テキストや文字列を扱うデータ型

  • 整数を扱うデータ型

  • 3次元の座標を表すデータ型

  • ゲームオブジェクトの位置、回転、スケールを管理するデータ型

6.string型とは。

  • 小数点数を扱うデータ型

  • テキストや文字列を扱うデータ型

  • 整数を扱うデータ型

  • 3次元の座標を表すデータ型

  • ゲームオブジェクトの位置、回転、スケールを管理するデータ型

7.Vector3型とは。

  • 小数点数を扱うデータ型

  • テキストや文字列を扱うデータ型

  • 整数を扱うデータ型

  • 3次元の座標を表すデータ型

  • ゲームオブジェクトの位置、回転、スケールを管理するデータ型

8.Transform型とは。

  • 小数点数を扱うデータ型

  • テキストや文字列を扱うデータ型

  • 整数を扱うデータ型

  • 3次元の座標を表すデータ型

  • ゲームオブジェクトの位置、回転、スケールを管理するデータ型

9.メソッドとは。

  • クラスの外部に定義される関数。

  • クラス内で定義され、特定の動作を実行する関数。

  • データを保存するためのコンテナ。

10.引数なし、返り値なしのメソッドとして正しいものを選んでください。

  • void DisplayMessage(string message) { Debug.Log(message); }

  • void DisplayMessage() { Debug.Log("Hello World"); }

  • int GetNumber() { return 5; }

  • bool IsTrue() { return true; }


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

  1. Unityのシーン内に配置できるすべてのエンティティ

  2. 変数はプログラム実行中にその値を変更可能で、定数は初期化後にその値を変更できない。

  3. プログラムのどこからでもアクセスできる変数

  4. 整数を扱うデータ型

  5. 小数点数を扱うデータ型

  6. テキストや文字列を扱うデータ型

  7. 3次元の座標を表すデータ型

  8. ゲームオブジェクトの位置、回転、スケールを管理するデータ型

  9. クラス内で定義され、特定の動作を実行する関数。

  10. void DisplayMessage() { Debug.Log("Hello World"); }


【アウトプット講義】

C#スクリプトを書いてみよう

スクリプトの作成をする

① プロジェクトビューの「+」をクリック

Projectビュー

② プロジェクトビューの「+」をクリック

Projectビュー

③ 任意のプログラム名「Test」を命名

Projectビュー

注意点 :
同じ名前のプログラムが存在する場合、エラーが発生します。既存のプログラムを削除し、新たに作成し直すことをお勧めします。

④ プログラムを「ダブルクリック」または、右クリックから「Open」を選択して、エディタで開くことができます。

注意点 :
エディタとは、コードを編集するためのアプリケーションです。

Unityをインストールする際にエディタが同梱されていない場合、別途インストールが必要になります。下記の参考リンクから適切なものを選択し、インストールしてください。

(
本講座では、Cursorを利用します)

定番エディタ「VsCode」

最新AIエディタ 「Cursor」


プログラムを記述する

Debug.Log(…);を記述

スクリプト「Test」を任意のゲームオブジェクトへドラッグ&ドロップアタッチをする

コンソールビューでログを確認する

再生ボタンをクリック
Collapseをクリックで、同じログを整理
ログが流れることを確認

「レストラン」 クラスを書いてみよう!!

お手本

解説

  • 定数: PASTA_PRICEDRINK_PRICE は、それぞれパスタとドリンクの価格を保持しています。これにより、価格がプログラム内で一貫性を保ち、変更が容易になります。

  • グローバル変数: totalBill はプログラム全体で注文の合計金額を追跡します。各注文が加算されるたびに更新されます。

  • 注文処理: PlaceOrder メソッドは、注文されたアイテムの数量と単価を受け取り、その注文の合計を計算し、全体の請求額に加算します。

  • クーポン適用: ApplyCoupon メソッドは、特定の割引額を合計金額から引きます。このシナリオでは、初めての注文後に一度だけクーポンが適用されます。

手順

① スクリプトを記述

コピペではなく、手を動かすのが覚えるコツ!!

using UnityEngine;

public class Restaurant : MonoBehaviour
{
    // 定数で料理とドリンクの価格を定義
    private const int PASTA_PRICE = 1200;
    private const int DRINK_PRICE = 500;

    // グローバル変数で合計金額を定義
    private int totalBill = 0;

    // UnityのStartメソッドで注文処理のシミュレーションを開始
    void Start()
    {
        // 最初の注文: パスタを2皿注文
        PlaceOrder(2, PASTA_PRICE);
        
        // 二番目の注文: ドリンクを2杯注文
        PlaceOrder(2, DRINK_PRICE);

     // クーポンを使用して合計金額から割引を適用
        ApplyCoupon(5);  // 5ドルのクーポンを適用

        // 最終的な合計金額をコンソールに出力
        Debug.Log("最終的な合計金額は: ¥" + totalBill);
    }

    // 注文を処理して合計金額を更新するメソッド
    void PlaceOrder(int quantity, int pricePerItem)
    {
        // 注文の合計金額を計算
        int orderTotal = quantity * pricePerItem;
        // 合計金額に注文の合計を追加
        totalBill = totalBill + orderTotal;
        // 注文の詳細をコンソールに出力
        Debug.Log(quantity + "個のアイテムを¥" + pricePerItem + "で注文しました。この注文の合計は: ¥" + orderTotal);
    }

    // クーポンを適用して合計金額から割引を行うメソッド
    void ApplyCoupon(int discountAmount)
    {
        // 合計金額から割引を適用
        totalBill = totalBill - discountAmount;
        // 割引後の合計金額をコンソールに出力
        Debug.Log("クーポンで¥" + discountAmount + "割引されました。現在の合計は: ¥" + totalBill);
    }
}

② スクリプトを保存して、任意のゲームオブジェクトへアタッチ

③ 下記のログがコンソールビューに表示されたら成功!!


【アウトプット課題】

課題1: コンソール出力

  • 目標: Unityのコンソールに「おはよう」など任意のメッセージを表示する。

  • 課題: Debug.Log() メソッドを使用して、好きな文字をコンソールに出力するプログラムを書いてください。

課題2: 変数と定数の使用

  • 目標: プログラムに変数と定数を加え、それらを使用する。

  • 課題: 任意の変数と定数を定義し、それらをDebug.Log()で出力するプログラムを作成してください。

課題3: メソッドの作成と呼び出し

  • 目標: 自作のメソッドを書き、Start() 関数から呼び出す。

  • 課題: 任意の処理を行うメソッドを作成し、Start() 関数内でそのメソッドを呼び出してみてください。

課題4: スクリプトのアレンジと拡張

  • 目標: 学んだプログラム知識を活かして、自由にスクリプトをアレンジする。

  • 課題: これまでの課題で作成したスクリプトを基に、新しい機能を追加したり、改良を加えたりしてみてください。


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

課題1: コンソール出力

using UnityEngine;

public class Hoge : MonoBehaviour
{
    // Startメソッドは、スクリプトのインスタンスがロードされた時に一度だけ呼び出されます
    void Start()
    {
        // コンソールに"おはよう"と出力する
        Debug.Log("おはよう");
    }
}

課題2: 変数と定数の使用

using UnityEngine;

public class Hoge : MonoBehaviour
{
    // 定数の定義
    const string GREETING_MESSAGE = "こんにちは、Unity!";

    // 変数の定義
    string userName = "プレイヤー";

    // Startメソッドは、スクリプトのインスタンスがロードされた時に一度だけ呼び出されます
    void Start()
    {
        // 定数と変数をコンソールに出力する
        Debug.Log(GREETING_MESSAGE);
        Debug.Log("ユーザー名: " + userName);
    }
}

課題3: メソッドの作成と呼び出し

using UnityEngine;

public class Hoge : MonoBehaviour
{
    // 定数の定義
    const string GREETING_MESSAGE = "こんにちは、Unity!";

    // クラスレベルの変数(フィールド)
    string userName = "プレイヤー";

    void Start()
    {
        // 定数と変数を使用してメッセージを出力
        DisplayGreeting();

        // ユーザー名を変更して再度挨拶
        UpdateUserName("新入開発者");
        DisplayGreeting();
    }

    // 定数とユーザー名を使って挨拶を表示するメソッド
    void DisplayGreeting()
    {
        Debug.Log(GREETING_MESSAGE + " ユーザー名: " + userName);
    }

    // ユーザー名を更新するメソッド
    void UpdateUserName(string newName)
    {
        userName = newName;
    }
}

課題4: スクリプトのアレンジと拡張

using UnityEngine;

public class Hoge : MonoBehaviour
{
    // 定数の定義
    const string GREETING_MESSAGE = "こんにちは、Unity!";

    // クラスレベルの変数(フィールド)
    string userName = "プレイヤー";

    void Start()
    {
        // コンソールに初期メッセージを出力
        Debug.Log("おはよう");

        // 定数と変数を使用してメッセージを出力
        DisplayGreeting();

        // ローカル変数を使用してカスタムメッセージを表示
        string customMessage = "Unityでの開発を楽しんでください!";
        DisplayCustomMessage(customMessage);

        // ユーザー名を変更して再度挨拶
        UpdateUserName("新入開発者");
        DisplayGreeting();
    }

    // 定数とユーザー名を使って挨拶を表示するメソッド
    void DisplayGreeting()
    {
        Debug.Log(GREETING_MESSAGE + " ユーザー名: " + userName);
    }

    // カスタムメッセージを表示するメソッド
    void DisplayCustomMessage(string message)
    {
        Debug.Log(message);
    }

    // ユーザー名を更新するメソッド
    void UpdateUserName(string newName)
    {
        userName = newName;
    }
}

スクリプト全体の構造

  • クラス定義: Hoge という名前のクラスが MonoBehaviour を継承しており、Unityのゲームオブジェクトにアタッチできるコンポーネントとして機能します。

  • 定数の定義: GREETING_MESSAGEconst キーワードを使用して定義されており、この文字列はスクリプト内で変更されることはありません。

  • 変数の定義: userName はグローバル変数で、初期値 "プレイヤー" が設定されていますが、スクリプトの実行中に変更可能です。

主要なメソッド

  • Start メソッド:

    • MonoBehaviour に由来するメソッドで、オブジェクトが最初にアクティブになった時に一度だけ呼ばれます。

    • ゲーム開始時にコンソールに「おはよう」と出力し、その後いくつかのメソッドを呼び出して様々なメッセージを表示します。

  • DisplayGreeting メソッド:

    • 定数 GREETING_MESSAGE と変数 userName を使用して、挨拶メッセージをコンソールに出力します。

    • ユーザー名が変更された場合でも、このメソッドを呼び出すことで最新のユーザー名を含む挨拶が表示されます。

  • DisplayCustomMessage メソッド:

    • 引数として受け取った任意の文字列(カスタムメッセージ)をコンソールに出力します。

    • このメソッドは汎用性が高く、異なる状況やコンテキストでのメッセージ出力に再利用可能です。

  • UpdateUserName メソッド:

    • 新しいユーザー名を引数として受け取り、クラスレベル変数 userName の値を更新します。

    • このメソッドにより、ユーザー名の動的な更新が可能となり、それに伴って表示されるメッセージも変更されます。


おわりに

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

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


TOP記事


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