1.はじめに
しろうととまなぶ たのしい Unityにようこそ!この記事は新歓ブログリレー2日目(3/9付け)の記事です。皆様、JKになりたいですか?
私はね、JKになりたかったんだ・・・うん、残念ながら、JKは
この記事では、前回の続きとして、Unityで使うプログラミング言語、C#の超微妙な解説をしますどんな感じで書くかを感じて「あれ?実はプログラミングってそこまで怖くなくね?」と思って欲しいというのがこの記事の趣旨です。と言う関係で、前回の記事を読んでからこれを読むのを強くお勧めします。お相手は引き続き私、tyoxuでお送りします。
うん、初めに言っておくとね、私は素人なんだ。ということでお話のレベル自体は超初心者の入門しようかなーどうしようかなーwwぐらいの人向けであることをご理解してください。
1. はじめに
2. ぷろぐらむって なんでかかないといけないの?
3. まずは かいどくからはじめよう
4. かたとへんすうとかんすう
5. あのけいさん このしょり、どうやるの?
6. おわりに
2. ぷろぐらむって なんでかかないといけないの?
Unityは、確かにゲーム開発を強力にサポートするツールです。しかし、プログラミングに関しては、書かないとどうにもならないようになっています。
ゲームを作るためのツールにおいて、プログラミングの自由度はそのまま開発の自由度になります。
Unityのそれは英語で書いていきますが、公式マニュアルの日本語版もありますし、決して、落ち着いてみれば意味不明な文字列ではなく、ちゃんと"解読"をすることができます。
嫌がってても何も始まらないので、覚悟を決めて、見ていきましょう!
3. まずは かいどくからはじめよう
と言うわけで、まずはUnityの比較的簡単なプログラムがどのような構造になっているかを、例文を見て学んでいきましょう。//tutolial1.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class tutorial1 : MonoBehaviour {
float timer=0.0f;
Vector3 firstpos;
bool flag = false;
void Start () {
firstpos = this.transform.position;
}
void Update () {
this.transform.position = firstpos + new Vector3 (Mathf.Sin (timer - 1), Mathf.Sin (timer * 10), Mathf.Sin (timer / 3));
timer += Time.deltaTime;
}
}
うーん、意味不明!w
ですが、ちょっと気合出して読んでいきましょう!
//tutolial1.cs
いっちばん最初のところですね。実はこの一行にはプログラム的意味がありません。
いわゆるコメント文と言って、プログラムの著者が後で自分や他人が見てそこが何を意味しているかを残すためのもので、Unityでは//(スラッシュ二つ)と同じ行のそれ以降の記述と、/* と */ とで囲まれた部分(こちらは行をまたいでもOK)がコメント文になります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
ここはusing (色々);という文が特徴的ですね。
実は、usingを使うことでunity内の使いたいプログラミング機能(の、ようなもの)を予約することができます。しないと使えません。ごく一部の人は、こう言った動作のために必要な記述のことをおまじないと表現することがあります。これがまさにそうと言えます。
public class tutorial1 : MonoBehaviour {
(中略)
}
そして、これもおまじないに近いものです。
もっというならば、これは、このプログラムの本文がこの{}の中にあること、それの名前が"tutarial1"であること、そしてそれがMonoBehaviourというモノを継承していることを表します。
継承、最近のスマホゲーではよく見ますね。
さっきのusing ~のように、MonoBehaviourの機能を使うよ!と言ってるイメージで今はいいと思います(細かく言うとややアレですが気にしない寛大さが大事)。
そして、例文を見るとこの{}の中身は、若干右にずれています。
これをインデントと呼びます。
これはプログラム上必要ではありません(実は言語によって必要だったりします。
個人的にはそんな細かいところで怒られたくないです)インデントを使うと、どこからどこまでがどの{}に入っているかがわかりやすくなります。
{}の中にまた{}が入ってくるような場合でもややこしくならないような工夫です。
4. かたとへんすうとかんすう
float timer=0.0f;
Vector3 firstpos;
bool flag = false;
ここでは、変数を宣言しています。変数の宣言は、
型 変数の名前;
と宣言することで、その後のプログラム内で操作、参照をすることができるようになります。
型の方というのは、その変数の種類です。例えば、整数なのか、実数なのか、みたいな話です。代表的なものは
名前 | 概要 |
---|---|
int | 整数(-8,1,0など) |
float | 実数(1.1,4.5,-1.4など) |
bool | 真義値(true ,false)単純で扱いやすく軽い |
Vector3 | 3次元ベクトル。(厳密に言えば変数の型ではない。) 各成分にアクセスとかできる |
GameObject | オブジェクト。前回のドラム缶とか |
などです。他にも色々ありますが紹介しきれないので必要になった時ぐぐってください。
さらに、
型 変数の名前 = 初期値;
とすれば初期値を設定することもできます。便利。
void Start () {
firstpos = this.transform.position;
}
お次は関数です。関数は、
返り値の型 関数名 (引数の型 引数の関数内での名前){
(内容)
}
とすることで多用する処理をまとめて書いておける機能です。
返り値の型をvoidとすると、帰り値を取らなくなります。
例えば、intにすると、
int kansu1(){
return 10;
}
とすれば、後のプログラムでkansu1( )と書いたところが自動で10になります。
で、これは"関数"なので、( )の中に"引数"を用意して、その引数をある決まった計算をして返す、と言ったこともできます。
int kansu2(int a,int b){
return (a*b);
}
とすれば、(a掛けるb)を計算してくれる関数の出来上がりです。
kansuu2(1,1)と書けばそこが代わりに1になりますし、kansuu2(114,514)とすれば、そこが58596となります。return ~でその関数が最終的に求めたかったものを出力している訳ですね。ではさっきのStart()関数に戻って見ましょう。
void Start () {
firstpos = this.transform.position;
}
"firstpos"は、さっき宣言したVector3型の変数でしたね。
this.transform.positionは、"このオブジェクトの 現在座標"がVector3型で入っている変数のようなものと考えれば大丈夫です。
Unityでは、=を挟んだ左側のものに、右側のものを代入します。
つまり、Start関数は、プログラムで呼び出されたときに、今の座標をfirstposに代入する関数って訳です。
また、Start()という関数はUnityの機能により、オブジェクトの登場に合わせて1回処理されます。これで、初期地点の座標を記録しておくわけです。
void Update () {
this.transform.position = firstpos + new Vector3 (Mathf.Sin (timer - 1), Mathf.Sin (timer * 10), Mathf.Sin (timer / 3));
timer += Time.deltaTime;
}
次のUpdate関数も特殊な関数で、そのオブジェクトが有効な限り1フレームに1回処理される関数です。他にもそういう特殊な関数名は複数あります。例によって多いので必要に応じて調べてください。で、この中身を見てみると、さっきも見た"このオブジェクトの 現在座標"this.transform.positionに、何やら代入しようとしています。この書き方によって、"現在座標"をプログラムから操作しちゃおう!という訳ですね。
何を代入しようとしているかというと、最初に記録しておいたfirstposに、(sin(timer-1),sin(timer*10),sin(timer / 3))を成分としたVector3を足し算したものですね。さらっと流しましたが、四則演算はUnityではなぜか+ , - , * , / です。
new Vector3は、いきなり3次元ベクトルを用意するときにこれが3次元ベクトルですと宣言しないとコンピューターがわからないから、している訳ですね。
またsin関数は、Mathf.sin()とすると呼び出すことができます。Mathf.~には他にも色々な関数がまとめられています。
timer += Time.deltaTime;の部分では、timer変数にTime.deltaTimeというものを足したものを、新しくtimer変数に代入しています。Time.deltaTimeが表すのは、前フレームからこのフレームまでの経過時間です。これによって、timer変数は最初からの経過時間を表すようになっている訳ですね。
さて、それでは、実際にさっきのプログラムを前回の要領で適当な(rigidbodyのついていない)オブジェクト(3D Object>Cubeが良いでしょう)に、Add Componentからtutorial1を新規作成してコピペして再生ボタンを押してみると・・・sin関数を感じる動き方をしたと思います。
5. あのけいさん このしょり、どうやるの?
公式マニュアルの日本語版を見ましょう。そこではここよりも詳しく、色々な状況に対応したことが載っています。またunity (したいこと)でgoogle検索をかければたくさんの情報が出てきます。日本語で。
まぁせっかくなのでさっきのを改造する形でちょっとした例を紹介します。
まず、フラグがあります。それが立っていない間は動かず、 立っている間は動くようにして見ましょう。 改造するのはUpdate関数ですね。
void Update () {
if(flag){
this.transform.position = firstpos + new Vector3 (Mathf.Sin (timer - 1), Mathf.Sin (timer * 10), Mathf.Sin (timer / 3));
timer += Time.deltaTime;
}
}
if(){}文は、()内がtrueのときのみ{}内を処理するというもので、より高度な処理の制御を実現できます。
次にflagをどうやってtrueにするかを考えて見ましょう。
せっかくだし外部から変えられるようにしたいですね。
そのためには、最初の変数宣言に手を加える必要があります。
public bool flag = false;
最初のやつに比べると、"public"がつきました。宣言するときにこれをつけると、"このプログラムの外"からflagを操作できるようになります。
・・・flagを操作するプログラムが別に必要になってしまいました。
ここは、前回のように、buttonを使いますか。
まず、新しいUI>Buttonを用意して・・・tutorial2をAdd Componentから新規作成してみましょう。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class tutorial2 : MonoBehaviour {
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
}
まずは、相手のflagを持っているオブジェクトを認識しないといけませんね。それ用の変数型がありますのでそれを追加してみます。ついでにStartとUpdateはいらないので消しましょう
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class tutorial2 : MonoBehaviour {
[SerializeField]private GameObject aite;
}
[SerializeField]privateを型の前につけることで、Inspectorから初期値を設定できるようになります。さらに、provateなので、他のオブジェクトから参照できないようになっています。こっちの方が気持ち軽いです[要検証]
ボタンを押した時に処理される関数を書いていきます。
public void Onpush(){
aite.GetComponent<tutorial1> ().flag = true;
}
aiteの中のオブジェクトにアタッチされているtutorial1の、flagにtrueを代入するという処理です。GetComponent<>で<>に入っているComponentを表しているのも地味にポイントです。この記事で一番重要です。
ここまで書けたら、ButtonのInspectorを見て、aiteの欄にさっきtutolial1をアタッチしたオブジェクトを、On Click()の欄に、tutorial2>Onpush()を設定してあげましょう。
上手くいっていれば、再生ボタンを押しても、tutorial1をつけたオブジェクトはビクともせず、さっきのButtonをクリックした途端に動き出すと思います。
駄目だった場合は・・・エラーメッセージが出ているならそこを治しましょう、そうでないなら、もっと簡単な間違いが想定されます。頑張って特定しましょう!
6. おわりに
これで今回の内容はおしまいです。前回に比べてライトで駆け足気味でしたが、言いたいことは言いました。あとは自分で色々勉強した方が身につくんじゃないでしょうか(適当)
というわけで長々ありがとうございました!
次回はsutoさんの記事です。 例によって12時公開のはずなので、そちらもぜひお楽しみに!