おはよう。
現在Unity2Dでアクションゲームを作っている。
私は独学でUnityことゲーム制作を始めた。
Youtubeや本、ブログなどたくさんの人に助けてもらった。
だからこそ私も記事という形で、
今のあなたに何らかの参考材料となればいいなと思い、記事を書いた。
結構長くなるので、いくつか分けて書きたい。
簡単な部分は省略したり、参考となる本や動画を載せたりする。
私が書くべき部分は参考あるいはイチから作ったものばかりだ。
くわえてスクリプトなど「なるべく減らす」形で書いていきたい。
書く内容が多すぎるので、いくつかに分散化した。
まずは基本スクリプト編からだ。
スクリプトの基本とリファレンスの観方

基本と言っても膨大にありすぎるので、私にとっての基本を書く。
またスクリプトリファレンスの見方を改めて記述していき、
「どうやって関数やスクリプトを記載していけばいいか」についても述べる。
はじめにスクリプトの基本だ。
スクリプトは作成しただけでは意味がない。
何かしらのゲームオブジェクト(ヒエラルキーに登録されているもの)に接続し、始めて効果を発揮する。
スクリプトを開くと、Start関数とUpdate関数に分かれている。
Start関数の前にまずは箱と箱名を決めてしまう。
private,publicの二つに分かれており、
privateは「そこでのみ、別のスクリプトからも使えない」状態。
publicはインスペクター上で設定できるうえ、別のスクリプトからでも呼び出せるモノだ。
[SerializeField] を使えば、private/publicどちらからでも直接インスペクター上で代入できる。あなたに覚えてほしい項目が public staticだ。
public staticはシーン(scene)を変更しても継続される項目であり、
例えば主人公のHPや残り人数など、ステージを変えても維持する場合に使う。
public staticはGameManager.csにでも創っておくと、
ここから別のスクリプトにHPとか入れられる。
スクリプトを書くと、リファレンスの観方が大切になる。
リファレンスの観方についてはこちらでも語っているが、改めて一つ例をあげたい。
sharedMaterial;について他の部分では
var material = GetComponent<Rigidbody2D>().sharedMaterial;
書いてある。var(便利な箱)と書いてあるが、正確に知るなら検索しかない。
公式サイトには次のように書いてあった。
public PhysicsMaterial2D sharedMaterial ;
![]()
スクリプトにはvarでもいいが正確さなら、
PhysicsMaterial2D material = GetComponent<Rigidbody2D>().sharedMaterial;
置いた方が、スクリプト及びあなたにとってもわかりやすい。
ついでにStart関数の前にRigidbody2Dの箱と名前を決めてしまい、
Start関数でGetComponentを行ったうえでmaterialの定義をしたほうが、
スクリプトも軽くで済むうえ、ほかの関数を使う際にも役立つ。
※キャッシュ化という。
例えばUpdate関数内でmaterialの定義を行ってしまうと、
Update関数以外では使えないというエラーが返ってくる。
いちいちほかの関数にmaterialの定義をしなければならず、面倒くさい。
「特定の関数でしか使わない」ものを除き、最初に定義してしまったほうが楽だ。
//最初(//はコメントを示す)
private Rigidbody2D rb2d;
PhysicsMaterial2D material ;
// private Rigidbody2D rb2d = null; が初期状態
void Start(){
rb2d = GetComponent<Rigidbody2D>();
material = rb2d.sharedMaterial;
}
void Update(){
//省略
}
最後にスクリプトを入れた際、インスペクター上にRigidbody2Dの確認を行う。
でないとNullReferenceExceptionというエラーを起こす。
なお、別のスクリプトから参照する方法はこちらを見てほしい。
かなり大切なnull(空)判定

Unityはnullにかき回される。例えば最初に置いた箱と箱の名前
private Rigidbody2D rb2d;は
private Rigidbody2D rb2d = null; を示している。
基本、最初のうちに等号(=)を入れていないものはすべて空(0)だ。
Start関数で入れるなどしないと、空のままだ。
空のままなのに、関数が入っているがごとく定義を書き込むと、
NullReferenceExceptionを起こしてしまう。
私たちの脳みそは「そこにオブジェクトが入ってるやん」捉えるが、
ゲームプログラミングは違う。入っていないもんはない。
NullReferenceExceptionは私たちの脳が素晴らしいがゆえに起きるエラーだ。
NullReferenceExceptionエラーのうち
UnityEditor.Graphs.Graph.WakeUp()~が出てきたら、
いったんUnityを閉じて開けばいい(再起動すればいい)。
null対策として、Start関数にきちんと定義をするか、
if(何らかのオブジェクト ==null)何かしらの対策
if(何らかのオブジェクト !=null)何かしらの対策
!=は「~でない」を示す。「箱は空ではありませんよ」という意味だ。
null判定をどこで最も使うかと言ったらアイテムを出すときだ。
といっても空はなくしておきたいため、
ヒエラルキーに「空のオブジェクト」を作り、プレハブ化し、
インスペクター上に空オブジェクトを入れておけばいい。
プレハブ化とゲームオブジェクト
プレハブは便利な道具だ。
一つ作っておけばコピペするだけでいちいち設定せずとも使えるから。
プレハブの作り方はヒエラルキー似て作ったゲームオブジェクトを、
直接コンソール欄にもっていけばいいだけ。
敵キャラやアイテムを作成した時、まず一つをプレハブ化する。
コンソール欄で一つプレハブができたら、Ctrl+CとCtrl+Vでコピペし、
その場で新しいプレハブを創る(コピペ)。
後はspriterendererのイメージ画像と、
アニメーションを作っているならAnimatorのコントローラーを更新すればいい。
※コントローラー更新の手順は上記動画を参照。
プレハブ化において、一つ問題がある。
スクリプトにて「public GameObject ~」を入れたとき、
コンソール上では基本空(null)であり、コンソールから直接代入しようとしても、
目的のゲームオブジェクトがなく、入れられない。
なんとオブジェクトを入れるとき「アセット」から参照すると、
簡単に入れられると分かった。

「シーン」だとオブジェクトはないが、アセットだとある。
アセットから目的のゲームオブジェクトを入れると、
使いまわすとき、いちいちインスペクター上から目的のオブジェクトを代入せずにすむ。
加えてスクリプトで「重い」と言われるFind関数を使わずにすむ。
なおアイテムなどで「どうしてもオブジェクトを入れたくないが、空白は……」
思った場合、空のオブジェクトを一つ作成してプレハブにすればいい。
メソッド(関数)を使うコツ

関数(メソッド)とは何だろう。
基本 void Start(){ほにゃらら}やUpdate()はもちろん、
void OnCollisionEnter(Collision collision)など当たり判定、
自作したvoid Jisaku(){ほにゃらら}、void Keisan(int damage){ほにゃらら}、
int Kakaku(){ほにゃらら returnうんたら}などを示す。
物理や数学ではいつの間にか「当たり前」に存在する関数について、改めて掘り下げてみよう。
関数とは「計算機あるいは電卓」にあたる。
関数でいろいろ計算をして、結果を出し、ゲームに反映させる。
何かを計算するための電卓と抑えておかないと、
何のためにメソッドを使うのか、わからなくなって混乱の元につながる。
メソッドは基本計算であり、計算次第で簡略にも複雑にもつながる。
関数を最小限に抑えるならUpdate()内にごちゃごちゃ書き込めばいいが、途中で混乱をきたす。
だからこそ目的にあった関数をどんどん作り、
UpdateやOnCollision関数などへの書き込みを減らし、
翌日あるいは数か月後の自分でもわかるように整えていく。
使い方として、
void Update(){
//ここに計算式うんたらかんたら
//例えばキャラを動かすなど
Kikaku(); //自作した関数
Life(2);
int answer;
answer = Plus(1 ,4):
}
void Kikaku(){
//うんたらかんたら計算式を入れる
}
void Life(int damage){ //上記よりdamageには2が入っている
int hpNokori -= damage;
}
int Plus(int a,int b){//上記よりa=1、b=4が入っている
int c += a + b;
return c;
}
int関数、bool関数などでは必ずreturnを入れる。
返り値returnの意味

returnは返り値と呼ばれており、最初私も意味わからなかった。
要は計算結果であり、この関数は「ここでおしまい」を示す。
returnの使い道例として、イベントや死亡などでキャラを動かしたくない場合を上げる。
一つbool(真偽値) sousaなどを入れるなどし、
sousaが偽(false)の時、ボタン操作を不能にさせるなら、
void Update(){
if(!sousa) return
//sousaがfalse(偽)の時、強引に作業を止めて切り上げる
//(!sousa)は(sousa == false)の略
//ここから下はsousa=true(真)なので歩くやジャンプなどのボタン設定ができる
} //Update()終わり
returnは計算結果かつ「この関数はここでおしまい、これ以降使わない」を示す。
先ほど載せたPlus(1 ,4):はint Plus(int a,int b)にて
c = 1+4 = 5となり、answerの中身は5として結果が返ってくる。
関数に放り込んでら、計算結果が返ってくる値=返り値と考えればいいのだろう。
目的の関数やスクリプトを組み立てる方法

例えば私が「キャラと地面が降れているか」を知りたい場合、
Youtubeやグーグルさんなどを使い
- Unity2d 地面 当たり判定
- Unity2d 地面 キャラ
こういった言葉を使って、まずは調べる。
すでに他人がやり方を知っているのだから、まずは他人に頼る。
ここまではあなたもやっているだろう。
他人に頼っても(=検索しても)出てこない「細かい悩み」が出てきた場合、
紙とペンを使って「自分が何をしたいのか」分解していく。
例えば角の部分では大地とキャラが接しているのに動かない。
まずやるべきことは紙とペンに書いて問題点を認識する。
頭は基本混乱をきたし、何をするかわけわからなくなるからだ。
次にDebug.LogやDebug.Drawlineなどを使い、ギズモをオンにする。
ギズモをオンにしておかないと、Debug.Drawlineが働かないためだ。
//私がよく使うDebug
Debug.Log("Hello");
//""の中に文字を入れて、関数が働いているかどうかを確認するときに使う
Debug.Log(Sore);
//bool(ここではSore)が働いているかどうかで使う
Debug.DrawLine(Vector3.zero, new Vector3(5, 0, 0), Color.red);
//当たり判定、大地との接触判定などでよく使う
他のデバッグについてはこちらに乗っているので、参照してほしい。
パソコンから離れて、紙とペンにて色々書き込んでいく。
例えば私の場合「大地と床の設置判定を線でなく長方形にすればいいのでは?」
メモを取って気づいたら、すぐさまパソコンに戻って調べたり、数値を入れたりする。
Debug及び紙とペンを使うと、だんだん自分が何をしたいのか。
そのためにどんなプログラムや材料が必要なのかが見えてくる。
またスクリプトを組んで困ったうえで解決した出来事があれば、載せていく。
