ゲームを作る上で、最低限プログラムの知っておくべき知識を教えて!
本記事の内容
・AIの作るコードの意味を理解するスピードがあがるプログラムの知識
・プログラムに使う変数には型や修飾子がある。それぞれの意味・使い方を理解しよう!
キャラクターを思いのままを動かせるプログラムを作るにはこれだけ知っておこう
小難しい内容は覚える必要なし!"型"と"修飾子"を理解しよう!
「ゲームを作ろう!」と思ったけども、プログラミングの本やサイトを見てみたけど、なんかよくわからない・・・。
という方もいると思う。
このサイトでは、ゲームに必要なプログラミングをすべてAI(ChatGPT)に任せ、人間はAIが書いてきたコードの内容を実行して不備の内容を指摘するという、新時代のゲームの作り方を提唱しています。
これからの時代、コードを書けるようになる能力よりも、組み立てる能力・読める能力・修正する能力があれば大丈夫!そこで、コードを読む時にこれだけは知っておきたい、「型」と「修飾子」について解説します。
型ってなんだ?
プログラムに必要な変数の形式を決めるもの
以前、こちらの記事で、基本的にプログラムは、変数と関数を押さえれば実行することができる、と解説しました。
忘れてしまった人はこちらを参照ください。
今回は、変数についてもう少し見ていきます。
それぞれの変数は、どんな変数かを表す、1つの型を持っています。型が決まっていない変数はありません。
型を決めることで、変数に対して不適当な値が入ることを防ぐことが出来ます。
たとえば、プレイヤーが死んでいるかを判定するフラグが、1~100の値をいずれも取れるとしたら、バグがとっても起きそうですよね?
そのため、真 or 偽 いずれかの値しか取らない型(bool)をセットする必要があります。
逆に、真 or 偽 いずれかの値しか取らない型(bool)がセットされているのであれば、その変数はフラグや何かしらの判定に使うものなんだ、ということが分かるわけですね。
というように、変数には型をセットするというのがプログラムの基本になるので、今回はゲーム制作で絶対使う型に絞って解説します。ただ、覚える必要はありません。AIの作ったコードを見ながらなんとなーく意味を理解してみましょう。
int : 整数ならこいつ
使い所
実行回数や、起動回数、ループ回数、クリック回数など、回数のカウントによく使う。
ポイント
・少数の値は入らない。細かなパラメータ調整は、floatを使うのがよい。
・HPの値は整数になるが、計算の過程で小数が発生することがある(耐性のある攻撃は、二分の一してHP減らすなど)。その場合は、キャストという処理が必要になります。といっても、頭に(int)とつけるだけの話。
サンプルコードは以下のとおり。
// float 型の変数を定義
float myFloat = 9.75f;
// float から int へキャスト
int myInt = (int)myFloat;
・-2,147,483,648 から 2,147,483,647の範囲を超える場合、intは使えない。
クリッカーゲームなどでインフレが想定される場合は、BigIntegerをという型にする必要がある。
float: 小数点のいる数字ならこいつ
使い所
・整数も少数も入れられる万能タイプ。
・小数点が発生するタイプ(移動速度、秒数など)なら、ほぼこれになる。
・オブジェクトや画像の拡大率、移動距離などの調整など小数点を使うパラメータの場合基本はfloatを使う。
ポイント
・コードの中に「0.05f」のように記載しているものがあるが、このfは「float」のf。型がfloatなら、最後にfを付けないといけない。
・時間を管理するときは、loatの数字を使って管理する。例えば、制限時間が2分秒なら、float型の変数に120.0という値をセットして、画面に表示するときは120を、時間に変換して出力するという方法を取るのが一般的。サンプルコードは以下のとおり。
using UnityEngine;
using UnityEngine.UI;
public class CountdownTimer : MonoBehaviour
{
public Text timerText;
private float remainingTime = 120f;
void Update()
{
// 時間を減少させる
if (remainingTime > 0)
{
// Time.deltaTimeは前回の処理から経過した時間
remainingTime -= Time.deltaTime;
UpdateTimerDisplay(remainingTime);
}
}
void UpdateTimerDisplay(float timeToDisplay)
{
// 時間を分と秒に変換
int minutes = Mathf.FloorToInt(timeToDisplay / 60);
int seconds = Mathf.FloorToInt(timeToDisplay % 60);
// テキストを更新
timerText.text = string.Format("{0:00}:{1:00}", minutes, seconds);
}
}
ほぼ同じ役割を持つ変数にdoubleがあるが、より厳密な計算をする時にしか使わない。ゲームでdoubleを使うことはあまりないと思う。
bool: フラグといえばこいつ
使い所
・やったか or やってないか、生きているか or 死んでいるか、動けるか or 動けないか、など、2択の選択肢に使う。
・ゲームの「フラグが立った」というのは、bool型の変数の値が更新された、ということ。
「プレイヤーが生きているならば、画面にXXXを表示する」などの処理の分岐条件に使う。
ポイント
・bool型の変数名は、「isClear」、「shouldMove」みたいに、isとかshouldを頭につけるのが一般的。
string: テキストといえばこいつ
使い所
・画面に表示する文字や説明文など、文字を扱う場合に使う。
・変わり種かもしれないが、SEやBGMを再生するときに、曲名を指定して再生するときにも使ったり。
ポイント
・string型の変数を使って計算は出来ない。たとえば、string型の変数の値が、「10.0」だったとしても、パソコンの中ではその10.0はただの記号でしかないので、10.0という数字として認識してくれない。計算をしたいなら、intやfloatを使おう。
・文字列の中身の値(表示したい文字の中身)をコードの中に入れるときには、ダブルクオーテーションをつける必要がある。たとえば、コンソール(開発者だけが見れる画面)に「Game Started」という文字を書きたい場合、ダブルクオーテーションで囲って、”Game Started"と書く必要がある。
using UnityEngine;
public class DebugExample : MonoBehaviour
{
void Start()
{
// ゲーム開始時のメッセージ
Debug.Log("Game Started");
}
void Update()
{
// キーボードの特定のキーが押されたときにメッセージを出力
if (Input.GetKeyDown(KeyCode.Space))
{
Debug.Log("Space Key Pressed");
}
}
}
・文字列を結合したい場合は、文字列の変数の間に「+」を入れる。
「こんにちは」という文字列と「Aさん」という文字列を結合した場合の例。これを実行すると、「こんにちはAさん」と出力される。
using System;
class Program
{
static void Main()
{
string greeting = "こんにちは";
string name = "Aさん";
string combinedString = greeting + name;
Debug.Log(combinedString);
}
}
ちょっと番外編
enum(列挙型) : オリジナルの型を作る
使い所
・真 or 偽以外にも、決められた3択や4択にしたいことってありますよね。
例えば、じゃんけんなら、「グー」、「チョキ」、「パー」の3択した取らないですよね。
ゲームで属性を持たせたいと思ったときに、「炎」、「水」、「電気」、「自然」の4種類の属性を作るとしたら4択にしたい、ということってあると思います。
intの整数の変数を作り、値が1ならグーで、2なら「チョキ」で・・・とやっていくのはミスを招く原因になるので、あまり良しとされません。マジックナンバーと言ったりします。
そこで使われるのが、オリジナルの選択範囲を取ることができるenum(列挙型)です。
例えばアドベンチャーゲームを作るとして、いまが何曜日であるかを判定する変数を作りたいとします。
そしたらまずはこのDaysという名前のenum型を以下のように定義します。
enum Days { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday };
すると、今日が何曜日であるか判定する、Days型の変数を作ることができるようになります。ここでは「today」というDays型の変数を作ってみます。
そして、「今日が日曜日であるか?」の判定をしたいのであれば、todayとDays.Sundayを見比べることで判定することができるようになります。
class Program
{
static void Main()
{
Days today = Days.Sunday; // 例として、今日を日曜日とします。
// 日曜日かどうかをチェック
if (today == Days.Sunday)
{
Debug.Log("今日は日曜日です。");
}
else
{
Debug.Log("今日は日曜日ではありません。");
}
}
}
ポイント
・自分で作ったDaysのようなオリジナルのenumの値を使うときは、頭に「Days.」のように修飾語をつけてあげる必要があります。
アクセス修飾子:public と private
アクセス修飾子とはなんだ?
一見難しそうに見えるワードですが、じつはとっても簡単です、怖くないよ!
変数を定義するときに型と合わせて、アクセス修飾子というのを設定することが出来ます。
設定をしない場合はデフォルトでprivateになります。
特にゲーム制作においては重要な概念ですし、コードを読む上でも、非常に重要な要素です。
ゲームを作るにはたくさんのクラスがあり、相互にアクセスしあう
こちらの記事で解説していますが、ゲームを作るには様々なオブジェクトが存在し、相互に影響しあっています。
スーパーマリオを例に考えてみましょう。
マリオのHPが0になったら、ゲームオーバーにする処理があるとします。
一般的には、プレイヤーのHPを管理しているコード(正確にいうとコードの塊であるクラス)と、ゲームオーバーであるかを管理するコード(クラス)は別物です。
なので、マリオのHPが0になったら、ゲームオーバーであるかを管理するコードにアクセスして、例えばゲームオーバーであるというフラグをfalse→trueに変更する必要があります。このように他のコード(クラス)を見に行くことを、アクセスといいます。
この他のコード(クラス)からアクセスしてもOKか、NGかを決めるのがpublicとprivateの違いです。
public と privateは、どう使い分けるの?
なぜこれを説明してきたかというと、AIに生成を任せたコードの場合、このアクセス修飾子によるエラーがよく起きるからです。
publicを使う場合、非常に強力が故に、無闇に使うとなんでも出来てしまう分、いろんなコード(クラス)から同時にアクセスされることで、値が予期せぬタイミングで更新されてしまったりして、バグの原因になりがちです。
なので、必要がなければprivateで設定するのが基本ですし、AIが生成するコードは、プロジェクト全体を俯瞰して考えていないため、privateな変数を前提としたコードを作成することが多いです。
しかし、先程の例にもあげたような、他のコード(クラス)からアクセスすることが必要なのに、privateなため、エラーとなるケースがあります。
たとえば、マリオの体力を「Player」というクラスで管理し、ゲームオーバーか否かのフラグを「GameManager」というクラスで管理するとします。
こちらはプレイヤーのクラス。
using UnityEngine;
public class Player : MonoBehaviour
{
public int health = 100;
public GameManager gameManager;
public void TakeDamage(int damage)
{
health -= damage;
if (health <= 0)
{
gameManager.isGameOver = true;
}
}
}
こちらはGameManagerのクラス。
using UnityEngine;
public class GameManager : MonoBehaviour
{
private bool isGameOver = false;
public void CheckGameOver(Player player)
{
if (player.health <= 0)
{
isGameOver = true;
// ゲームオーバーの処理
// 例えば、ゲームオーバー画面を表示するなど
}
}
}
これで実行しようとすると、以下のようなエラーが出ます。
なぜかというと、GameManagerというクラスに設定しているisGameOverという変数はprivateなため、Playerというクラスからアクセスが出来ないからです。
なので、このようなエラーが出たらGameManagerのisGameOverをprivate→publicに変更してあげましょう。
publicに変更したスクリプトです、こうするとエラーが消えますね。
public class GameManager : MonoBehaviour
{
public bool isGameOver = false;
public void CheckGameOver(Player player)
{
if (player.health <= 0)
{
isGameOver = true;
// ゲームオーバーの処理
// 例えば、ゲームオーバー画面を表示するなど
}
}
}
Unityのインスペクタからの設定可否
最後に、Unityでは先程のpublicにした値の場合、インスペクタ画面から値を更新することが出来ます。
たとえば、ゲームを作ってテストプレイをするとします。
プレイヤーが死亡したときの処理を確かめたいとした場合、プレイヤーのHPだったり死亡フラグに当たる変数を変更したいですよね。
けど、プレイヤーを敵と戦わせてHPが0になるまで待つのは面倒ですよね。
ほかにも、プレイヤーの移動速度を変更するのに、パラメータを調整したい。そんな時に毎回プログラム編集画面を開くのは面倒ですよね。
そういった時に、インスペクタ画面から変数の値を変更できるようにするには、以下の2つの方法を取ることが出来ます。
方法①:修飾子をpublic
にする
先程紹介したpublicな変数にすると、このインスペクタ画面での変更が可能になります。
方法②:[SerializeField]
をつける
privateな変数であっても、頭に[SerializedField]をつけると、インスペクタ画面での変更が可能になります。
ですが、他のコード(クラス)から変更することは出来ません。
[SerializeField]private bool isGameOver = false;
このように頭に[SerializeField]がついていると、インスペクタ画面に「isGameOver」という欄が出現しました。
まとめ
少し長い記事になってしまいました。
一見難しそうなコードでも、もう一段階細かく見てみると、これはそういう意味だったんだ、ということが分かってきますね!
これらの内容は暗記して覚えるようなものではなく、こういう意味なんだ!と理解することが大事です。これらを理解するだけで、AIの作ったコードを読む理解力が数倍速くなるからです。
それでは素敵なゲーム制作ライフを!
コメント