おはよう、現在ゲーム制作にUnityを使っている。
ウディタからUnityに切り替えて3か月がたち、
だんだん操作がわかってきた。
一方C#スクリプトは基本しかわかっていないが、
3か月もたつとだんだん「すべきこと」が見えてきた。
いかに3か月程度でスクリプト文法を身に着けるか?
発展途上ながらもわかった部分について書いていく。
なぜC#は難しい?
Unityに触れるまで、私はC#を一度も触れていない。
初めて親しむ言語の勉強で、
まずは基本中の基本「スペル」から知らねばならぬ。
C#といってもUnity独自の関数や表現がある。
スクリプトリファレンスを調べたら、数多くあり絶望した。
解説動画を見ても、何をやっているのかよくわからない……
なぜ狙い通りのプログラミングを行うのに、
それをしなければならないのか?
理由がわからず、絶望が多かった。
プログラミングの役割
Unitで行うべきプログラミングはいろいろある。
色々が頭を悩ます要因だが、突き詰めていけば一つ。
「メイン装置の補助道具」
例えば向きによってキャラの立ち絵を変えたいとする。
3Dなら移動によって向きを変えたいとする。
SpriteRendererというコンポーネントにFlipという場所がある。
(日本語表示だと反転と書いてある場所だ)
※SpriteRenderer(スプライト)とは画像の向きや色などを決める道具
アニメ表示する時にも「分割」できる機能がある。
Unityで使う英単語は基本スペルが長いため、
スペルミスによるエラーを起こしやすい。英単語はコピペしよう!
作成時は自分でチェックを入れると左右に反転できるが、
ゲームプレイ時はボタン入力によって変えたい。
※画像を固定したまま左右に動くだけ。
プログラミングを組んで、
ボタンと同時に向きを変えていかねばならぬ。
そこでUnity内から「作成」でC#スクリプトを作る。
一度名前を決めたら削除しない限りエラーを起こすので注意。
作成したら、主人公や敵キャラなど、
「動かす対象」に向けてスクリプトを代入(アタッチ)させる。
代入前後でいいから「コンポーネントを追加」して、
SpriteRendererを入れるといい。
あくまでもスクリプトは「メインでできない細かい設定」を、
サクサク行うためにやる補助手段だ。
一つのスクリプトが一つについた。
「このC#はここでしか機能しませんよ」と意思表示できたわけだ。
簡単に作成していく。
public class PlayerMove : MonoBehaviour
{
private SpriteRenderer spR;
void Start(){ //剛体を呼び出す
this.spR = GetComponent<SpriteRenderer>();
} //start
void Update()
{ //左右入力で動く
float x = Input.GetAxisRaw("Horizontal") ;
//向き反転かどうか
if ( x < 0 ){
spR.flipX =true;
} else if ( x > 0 ){
spR.flipX =false;
} //flip if
} //Update
} //public class playerMove
※//は「コメントアウト」を示す。
プログラミングは「定義→分岐(あれば)→代入」からなる。
初期値にprivate SpriteRenderer spR; と入力し、
「SpriteRenderer用として、spRという箱(変数)を使います」と宣言する。
数学で言うなら、次のようにざっくり捉えてほしい。
「横座標軸の定義(→SpriteRenderer)をX(→spR)と置きます」
最初に定義をしなければ、スクリプト側がエラーを出してくる。
私たちは座標といえば「xy軸」と定めているけど、
場合によってはuv、ReIm軸など色々あるからね。
プログラミングの難しさは私たちの脳内にある。
脳内では「すでにわかってる、定義するまでもない」決め事を、
こちら側で定めていかねばならないんだ。
プログラミングを行えば、いかに脳みそが便利で優れているか!
嫌というほどわかるよ。
最初に定義を行った。次に入ろう。
void Start{spR = GetComponent<SpriteRenderer>();}と書いて、
spRはComponent<SpriteRenderer>から値をとります・変えますよ。
宣言していくわけだ。再び定義するわけだ。
getComponentは「コンポーネントを追加」し、
SpriteRendererをインスペクター内に入れていないと無意味だ。
※void Startはゲームプレイボタンを押したとき、
すぐさま反映するための道具と思ってほしい。
次にvoid Update{
float x = INput.GetAxisRaw(“Horizontal”);
//ボタンを定義する。左右の矢印キーを押したら、キャラが動く
//値は-1か0か1のどれか。
後は条件分岐を行って、向きを決めていく。
if (x < 0 ) { //左向き
spR.flipX =True;
} else if (x > 0 ) { //右向き
spR.flipX =False; }
} //Updateはここまで
キャラが最初から右向きなら、trueとFalseを反対にすべし。
また数学の座標を思い浮かべてほしい。
マイナス座標なら左、プラス座標なら右だ(YやZも同じ)。
始めて手を出した人は一つ疑問が出るだろう。
「flipXってどこから持ってきたんだ?」
上記画像はUnityマニュアルから持ってきた、
英語(正式)verのSpriteRendererだ。
日本語では「反転」と書かれた部分が、
英語では「Flip」と書いてあるね。
上記プログラミングにて、ボタンを左に押すと、
True=チェックボタンを入れた状態となり、向きが変わる。
一方右にボタンを押すと、
False=チェックボタンを外した状態となり、向きはそのままだ。
スクリプトは「コンポーネント設定だけでは無理な細かい役割」を、
支えてくれる素材として考えるといい。
もちろんUIなど例外(監督要素など)もあるけど基本は「補助」だ。
スクリプトリファレンスの観方
Unityは独自のスクリプトがある。
独自だからこそ迷うし、何をしたらいいかわからなくなる。
特に上記画像左のリスト欄を見たら……絶望だ。
リファレンスがあったとしても
「何をすればいいかわからない」から問題だ。
そこで記事を書いている自分も理解するため、
先ほど載せたSpriteRendererを見ていこう。
一つずつ分けてみていくと……
- 変数
- 継承メンバー-変数
- Public 関数
- Static 関数
- Operator
- メッセージ
分かれていて、何がなんだかわけわからないね。
そこで一緒に見ていこう。
基本:どういう状況で使うの?
基本中の基本として、スクリプトリファレンスでは、
「この条件は、この型版でしか使えませんよ」を示している。
例えばlocalScale。上記画像で黄色く囲んだところに注目してほしい。
Vector3と表記している(2DはVector2でも使える)。
Vector3でしか使えないよ、intやstring、floatなどはエラーが出るよ。
次に説明を見てほしい。何を言っているかわかるだろうか?
私はよくわからない。英語に変換してもよくわからない。
なのでグーグルさんを使って「unity localScale」調べよう。
検索したら大抵の意味と役割が出ている。
リファレンスを見るとき、どの型番でしか使えないかを確認してから使ってほしい。
変数とは?
変数は「Unity内で定義しなくても最初から使える道具」だ。
スクリプトでなく普通の編集画面にて
SpriteRendererをコンポーネントに追加し、見てほしい。
変数は上記画像の部分と見事に対応しているんだ。
(自分は日本語で設定しているけど、変換すればわかるよね)
spR.flipX =True;を見てほしい。「flipX」と書いた。
上記変数にも「flipX」の項目があるのを確認してほしい。
Unity内であらかじめ定義してくれているから、
わざわざ冒頭でflipX=適当な変数;とおかなくてもいい。
継承メンバーとは
次に継承メンバー-変数だ。
継承とはメンバー変数やメソッド(関数)など、
あるクラスの引き継いで、新しいクラスを作る行為だ。
……いまいちよくわからない。
数か月たって継承を作り、やっと体で理解できた。
継承は親元を作って「ここだけ変えたい」子を創る。
それぞれ親を創るやり方もありだが、
それぞれ親を創ると、必ず重複する関数が出てくる。
敵のスクリプトを創るにあたり、敵も数種類分けると、
歩いたり、壁との当たり判定などで別の敵スクリプトと重なってしまう。
重なりを一つにまとめる役割こそ継承の働きだ。
記事を書いてから数か月後、継承にて苦労したので記事を書いた。
パブリック(Public)関数とは
続いてパブリック関数を見ていきたい。
対象物を動かす際に必要なRigidbody2D.AddForceがある。
最初に private Rigidbody2D rb2D;を出して箱rb2Dを用意し、
Startでrb2D = gameObject.AddComponent<Rigidbody2D>();を用意。
rb2Dはコンポ―ネットにくっつけたRigidbody2Dにのみ働くよと宣言。
後はアップデート関数(void Update)にて、
Vector2 force = new Vector2 (0.0f,1.0f);
rb.AddForce (force);
newと新しくもうけ、自分で数値を入れていいんだ。
新たに座標を設定するよと表示したのだから。
と入力すれば、.AddForceは上向きに動く。
変数.Public関数という形で書けるのね。
Public関数は初期設定やスタート関数におかず、
いきなり変数.Public関数という形で使用できるのね。
スクリプト:Rigidbody2D
継承メンバーパブリック(Public)関数とは
Public 関数にはもう一つ、継承からのパブリック関数がある。
継承型Public 関数で一番使うのがGetComponentだろう。
パラメーターがあり「type」と書いてある。
先ほどのスタート関数(ゲームプレイ時、すぐ軌道するプログラム)で
{spR = GetComponent<SpriteRenderer>();}書いたね。
現時点で()が空欄であり、typeは何も入れていない。
何も入れていない=すべて入れるよ。と思えばいい。
リファレンスでは
HingeJoint hinge = gameObject.GetComponent(typeof(HingeJoint)) as HingeJoint;
hinge.useSpring = false
※asはas演算子であり、データ型を変換できる装置。
hingeからHingeJointへ強引に変えたとみていいのね。
スタティック(Static)変数・関数とは
Staticはどのスクリプトでも自由に扱える関数・変数だ。
本来あるスクリプトからある関数や値を参照する時、
インスペクターから直接値をアタッチするか、
タグ検索などでゲームオブジェクトをもって来なければならない。
staticはUnityで初めから設定しているので、参照なく自由に扱える。
例えばVectorに原点を代入する時、
vector2 vec = new Vector2(0 , 0);
でもできるが、スクリプトリファレンスから
Vector2 vec = Vector2.zero;
Vector2.zeroはstatic関数であり、このまま代入できる。
別スクリプトにいちいち値を入れなくていい。このまま直接入れられる。
変数はそのまま代入で、関数は中に計算を行う時に使う。
オペレーターやメッセージ
オペレーターを見ていくと、単純に論理演算に関する記述であり、
他の部分でも併用ができる。
スプライトにはもちろん、リジット他にも影響を与えますよと見ていい。
メッセージは現時点で正直わからん(すまぬ)。
重要は変数とpublic,static
リファレンスを調べたおかげで、
Unityスクリプトで重要な部分は三つとわかった。
主に三つの部分–変数、public、static–に注目し、
一つずつ改造をこなしていくといい。
特にstaticは別のシーンファイル(scene)に移動する時、
例えばHPをそのまま引き継ぐ時に使える。
またゲームプレイ中かどうかを識別する時も使える。
さらに別スクリプトから変数や関数を参照する時にも使える。
これらは後で述べる関連記事に書いたから、読んでほしい。
後はエラーについてどう対応すればいいかがわかれば、
スクリプト編集にあまり困らなくなるだろう。