プログラムってなんだかとっても難しそう・・・
そんなことはありません!要素に分解してみればとってもシンプル!
本記事の内容
・ゲーム制作におけるプログラムの役割を理解しよう
・スクリプトの構成要素を理解しよう
・変数と関数の役割を理解しよう
ゲーム制作にはプログラムが必要。けど、AIがいるから難しくないよ
ゲームはプログラムで動いている
ゲームを作ってみたいと思ってみた方も多いと思います。しかし、ゲームにはプログラムが必ず必要です。
キーを入力したらプレイヤーが前に走る、というのは、キーを入力するとプレイヤーを動かすというプログラムがあるおかげなのです。
自分のオリジナルなゲームを作ろうと思う場合、「これをしたら」「こうなる」というプログラムを作る必要があります。
AI時代に知っておくべきプログラミング知識
プログラムを書くのは、現在ではとっても簡単になっています。生成AIのお陰です。やりたいことを書けば、ChatGPTが動くコードを作成してくれるようになりました。
しかし、必ず完全なコードを返してくれるわけではありません。挙動がおかしかったり、指示した内容と違うことを返してしまうことがあります。
また、AIが生成したコードをコピペしたコードを使って微修正したり、ここを直してほしい、という指示を出す必要があります。その際により具体的な指示を出せた方が、修正に掛かる時間は短くなります。
そのため、コード作成をAIに任せる前提だとしても、最低限のプログラム知識は必要です。そこで、AIが生成したコードを読むには最低限どんな内容が必要か、を解説します。
プログラミング知識 超入門
プログラミングは、料理の献立・料理を作ることと同じようなもの
プログラミングができる、というのは料理の献立が作れるようになること、と同じようなものだと思います。例えば、今日の夕飯を作ってみるとしましょう。夕飯を作ってみるにはこんな情報が必要です。
- 献立はどんなメニューで構成するか(例えば、カレーとサラダにする)
- どんなカレーなのか、どんなサラダなのか(タイカレーなのか、日本風のカレーなのか、甘口か辛口か?)
- 材料とその分量を決める(例えば、にんじん、じゃがいも、肉、カレールウ、水などがどれくらい必要?)
- 材料を加工する具体的な手順とその順番
プログラムを作る手順もこれとそれほど変わりません。まずはどんな処理が必要になるかを決めて、一つづつその処理の内容を、適切な変数(料理で言えば分量)を使ってセットします。
・処理の内容
・変数(数値、文字、ステータス状態)
スーパーマリオにはどんなプログラミングで出来ているの?
スーパーマリオを例に見てみましょう。マリオの動きに必要な処理は大方こんなところではないでしょうか?
【マリオというキャラに求められる処理とパラメータ】
- [処理]Aボタンでジャンプ [変数]:ジャンプの高さ
- [処理]十字キーで移動 [変数]:歩きのスピード
- [処理]Bボタン+十字キーでダッシュ [変数]:ダッシュのスピード
- [処理]キノコを取ると巨大化 [変数]:プレイヤーのステータス(キノコで巨大化中 or 通常サイズ)
- [処理]穴に落ちると死亡 [変数]:なし
- [処理]敵を踏むと敵を退治できる [変数]:踏みつけのダメージ量
- [処理]ジャンプ中にZボタンでヒップドロップ [変数]:ヒップドロップのダメージ量
これらの1つづつの処理の内容をプログラミングでは「関数(メソッド)」といいます。そして、この処理の中で使用する変数のことを「変数」といいます。
スーパーマリオには、他にこんな関数と変数が必要ですね。
スクリプトの読み方
スクリプトは要素を分解して読み解こう
上記のことを踏まえて、ゲーム制作におけるスクリプトのサンプルを見てみましょう。Unityでは、使用している言語はC#というプログラミング言語になります。
AIにコードを生成してもらうときは、「Unityで作成しています」とか、「C#で作ってください」とお願いするのがよいです。
今回はAIに生成してもらったサンプルのクリプトを使って、コードの読み方を見ていきます。
これは、ボタンを何も押さないと画面に「何かキーを押してください」と表示され、スペースキーを押すと「スペースキーが押されました!」と表示されるスクリプトです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ConditionalText : MonoBehaviour
{
public Text uiText; // UIのテキスト要素をアサインするための変数
public string messageToShow = "スペースキーが押されました!"; // 表示するメッセージ
public string initialMessage = "何かキーを押してください"; // 初期メッセージ
void Start()
{
uiText.text = initialMessage; // ゲーム開始時に初期メッセージを表示
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) // スペースキーが押されたとき
{
ShowMessage();
}
}
void ShowMessage()
{
uiText.text = messageToShow; // UIテキスト要素にメッセージを設定
}
}
このスクリプトを構成要素に分解してみましょう。
ほとんどのスクリプトはこの構成要素に分解することが出来ます。
- エリア① 名前空間(重要度:中)
- エリア② クラス名・継承クラス(重要度:中)
- エリア③ 変数の定義(重要度:高)
- エリア④ 関数の処理(重要度:高)
それぞれの構成要素ごとに中身を見ていきましょう。
エリア① 名前空間参照
頭に「using」を付けます。新規作成したスクリプトには、デフォルトで以下の名前空間がついています。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
基本的にはこれらは外す必要はありません。基本はこれに追加をするのみです。名前空間を自分追加する必要があるケースは以下の2点の場合です。
1.UI(テキストやボタンなど)関連のオブジェクトを使う時
2.アセットに付随しているスクリプトを使う時(基本的にマニュアルに書いてあるのでそれに従うまでです)
上記のサンプルは、テキストをUIに出力するプログラムなので、以下の一文を追加します。これを付けないとエラーになってしまいます。
using UnityEngine.UI;
また、Unityの新しいスタイルのテキスト、TextMeshProを使う場合、以下のusingをつける必要があります。
using TMPro;
エリア② クラス名・継承クラス
classほにゃららと書いてある部分を見てみましょう。
public class [クラス名]:[継承元クラス]
{
//なにかの処理
}
[クラス]とは、処理たちを束ねたものの単位です。基本的には、1つのスクリプトにクラスは1つにしますが、1スクリプトで複数のクラスを保持することも出来ます。
例えば、プレイヤーの走る動き、歩く動き、待機中の動きをまとめた、「Player」というクラス名で作ってみます。
・C#では、小文字と大文字は別の文字として認識されます。
・クラス名は、1文字目が大文字にしましょう。
次に、継承元クラスについて。
こちらはあまり最初は意識する必要はありません。デフォルトで入っている「MonoBehaviour」を入れておけば問題ありません。
中級編で解説する、「継承」という概念を理解するために必要ですが、初級では”おまじない”という認識で問題ありません。
エリア③ 変数の定義
public Text uiText; // UIのテキスト要素をアサインするための変数
public string messageToShow = "スペースキーが押されました!"; // 表示するメッセージ
public string initialMessage = "何かキーを押してください"; // 初期メッセージ
ここでは、このクラスの中で共通で使用する変数を定義します。詳しくはこちらの記事で解説しています。
概要として理解したい点は、変数として定義するものは2種類ある、ということ。
1.エリア④の関数の処理の中で使う数値や文字
2.エリア④の関数の処理の中で使う他のクラスへの参照
処理の中で使う数値や文字
こちらは、関数の中で使う数値(たとえばプレイヤーの移動速度や、体力など)や文字を定義するのに使います。
上記の例では、関数の処理で表示する文字列を定義しています。
public string messageToShow = "スペースキーが押されました!"; // 表示するメッセージ
public string initialMessage = "何かキーを押してください"; // 初期メッセージ
このように一度変数を定義すると、"何かキーを押してください" というメッセージを複数の処理で使うことができますし、ゲーム中に値を変更する(ユーザーが入力した文字に変更する)といったことが可能になります。
他のクラスへの参照
すこしイメージしずらいと思いますが、こちらは他のクラスの処理や変数にアクセスするのに使います。
例えば、上記のサンプルコードでは、以下の定義をしました。
public Text uiText; // UIのテキスト要素をアサインするための変数
public string messageToShow = "スペースキーが押されました!"; // 表示するメッセージ
public string initialMessage = "何かキーを押してください"; // 初期メッセージ
Unity標準のTextというクラスの中に、text
という変数がいます。(大文字と小文字で意味が違います)
このtext
という変数の値を更新する処理をエリア④関数の処理 で行うために、「TEXTという名前のクラスへの参照」が必要になる、というわけです。
たとえば、ゲーム内の経過時間や制限時間を管理するTimeManagerというクラスがあるとします。
ただ、アイテムを取得すると制限時間が+10秒されるとします。
アイテムを取得する処理を、Itemというクラス名にしていた場合は、TimeManagerというクラスを参照する必要があるんですね。
このように、ゲーム制作では、小さなクラスが多数あり、相互にアクセスするということが多発します。そのために、こうした変数の定義が必要です。
エリア④ 関数(メソッド)の処理
ここが一番のメインです!
このエリアで、このスクリプトが実行する処理の中身を記載します。
まずは、とりあえずこれだけ理解しておこう、という点はたった2点だ記載します。
1.複数のパーツをつなぎ合わせて作る(カプセル化と言ったりします)ようになっているということ
2.StartとUpdate文の使い方
メソッドは入れ子構造(カプセル化)になっている
プログラムというのは、基本的に複数のレゴブロックをつなぎ合わせて大きなレゴのオブジェクトを作るイメージに近いです。
たとえば、机を作るなら以下のパーツが必要ですよね。
- 足×4
- 天板
これを前提に机を作るプログラムを行う場合、以下の3つの関数で作ります。
- 「足を作るメソッド」を4回呼び出し、「天板を作るメソッド」を呼び出す
- 「足を作るメソッド」
- 「天板を作るメソッド」
なんとなくイメージできましたか?
今回のサンプルのスクリプトで見てみましょう。Update()内の処理はいわば「天板を作るメソッドを呼び出す」です。
以下の「ShowMessage()」はいわば、「天板を作るメソッド」です。
このように、細かなメソッドをつなげて、大きな処理を行っているという概念を理解しましょう!
void Update()
{
if (Input.GetKeyDown(KeyCode.Space)) // スペースキーが押されたとき
{
ShowMessage();
}
}
void ShowMessage()
{
uiText.text = messageToShow; // UIテキスト要素にメッセージを設定
}
・VisualStudioでは、「Ctrlボタン」を押しながら、関数の名前(ShowMessage)をクリックすると、対象の処理の内容に飛ぶことが出来ます
StartとUpdate文の使い方
関数には、デフォルトで用意されている関数(メソッド)と、自前で作る関数(メソッド)の2種類があります。
デフォルトで用意されている関数は多数あるのですが、どのゲームでも100%使う2つの関数について説明します。
- Start関数(メソッド):
Start
は、スクリプトが有効になったときに一度だけ呼び出されます。- このメソッドは主に初期化のために使われます。例えば、変数の初期設定(プレイヤーの位置を原点に設定するなど)、ゲームオブジェクトの参照の設定、スタート時に一回だけ実行したいロジックなどです。
- Update関数(メソッド):
Update
メソッドは、オブジェクトがアクティブな間、毎フレーム(1秒間に数十回実行される)ごとに呼び出されます。- このメソッドは、ゲームのメインループの一部として使用されます。たとえば、ユーザーのキー入力チェックプレイヤーの入力のチェック、キャラクターの移動、タイマーの更新、連続的なイベントのチェックなどに使われます。
基本的にゲーム開始時に、初期値を設定する場合はStart
メソッド、ゲーム内で常に更新する処理はUpdate
メソッド、なにか行動を起こしたときに実行したい処理は、自前のメソッドというようなイメージを持っておきましょう。
関数については詳細をこちらの記事で解説していますので、こちらもよかったら読んでみてください。
まとめ
プログラムと聞くと難しいイメージがありますが、こうやって要素を1つ1つ分解していくと、少しずつ理解していけると思います。これらが理解出来たら基礎はバッチリです。
続きはこちらの記事から!
コメント