Unityでカメラを操作したい
やりたいこと
キーボード上のキーを押すと、そのキーに対応した方向にカメラが移動する。
こーいうことを出来るようにしてみます。
キーを押したら処理を実行するには?
キーを押したら何かが反応する、という処理なので、
void update()
の中に処理を記述しなければいけません。
update()は1フレーム毎に呼び出されるためです。
start()は最初の一度しか呼び出されませんがupdate()は無限ループで呼び出されます。
まず2020年現在で基本的な入力っていったら以下ぐらいかなと思ってます。
- キーボード
- マウス
- タッチ
そしてこれらは全てInputという関数で取得できます。
- キーボード → Input.GetKey
- マウス → Input.GetMouseButton
- タッチ → Input.GetTouch
またキーボードとマウスの場合は、Input.xxxの最後にUpとDownをつけることもできます。
まず、UpもDownも何もない場合は押している間ずっと反応しつづけます。
例えば、あるキーを押したらボールを1つ生成するような処理を付け加えた場合、押している間ずっとボールを生成し続けます。
それに対しUpもDownも同じで、キーを押したら1回反応します。
なので上の例では、ボールは1個しか生成されません。
ではUpとDownの違いは何かというと
キーを押し始めた時に反応する(Down)のと
キーを離し始めた時に反応する(Up)の違いです。
なかなか細かいですよね。
まとめると以下です。(Input.GetMouseButtonも同様)
- Input.GetKey → 押している間中ずっと
- Input.GetKeyDown → 押し始めた時(1回のみ反応)
- Input.GetKeyUp → 離し始めた時(1回のみ反応)
Input.GetTouchについてはTouchとTouchPhaseで判定を行います。
画面に指が触れた時、画面を指が動いている時、画面から指が離れた時の3つの処理を扱えるみたいです。
カメラを移動させるには?
transform.Translate(x,y,z)でオブジェクトの移動ができます。
x,y,zに指定した値の分、オブジェクトをその方向に移動させます。
ここで便利なのがVector3の以下機能です。
Vector3.up = (0,1,0)
Vector3.down= (0,-1,0)
Vector3.left = (-1,0,0)
Vector3.right = (1,0,0)
Vector3.forward = (-1,0,0)
Vector3.back = (1,0,0)
例えばtransform.Translate(Vector3.up)
とすれば上方向にオブジェクトが移動してくれるんです。
(スゲー!)
ここでやっとキーボードのキーを押すと反応してくれることが確認できるようになりました。ゲーム制作をしているっていう実感がちょっと沸いた瞬間でした。
カメラの移動範囲を制限するには?
Mathf.Clamp(制限したい値,最小値,最大値)を使えばよさそうです。
Mathf.Clamp(transform.position.x,0,5)とするとオブジェクトのx方向は0~5の間にしか進めなくなります。
0以下の場合は0が設定され、5以上の場合は5が設定されます。
Clampの意味は「遮断する」だそうです。
今までの処理をカメラに適応させるには?
以前も紹介した通り、作成したC#ScriptをMain CameraのInspectorウィンドウでComponentの追加を行えばよいです。
これでメインカメラがキーボードで操作できるようになりました!
カメラの端の位置情報を取得するには?
Camera.main.ViewportToWorldPoint(new Vector3(x,y))
で取得できます。
ここでnew Vector3(x,y)にはViewportを指定します。
x,yは0 ~1の間で指定します。
C#ScriptにC#Scriptのコンポーネントを追加したい
なんでそんなことしたいの?って最初は思いましたが、例えばstart()メソッドの中で計算した値を別のC#Scriptで保持しておきたい場合とかに使えます。
まず設定したい側のC#ScriptのClass中に、追加されるC#Scriptのクラスを変数で定義します。(言葉だけだと自分でも何言ってるか分からなくなってきました…)
例えば「aaa」というクラスに「bbb」というクラスを追加したい場合、
aaaのクラスの中にprivate bbb hensuという感じで変数を定義します。
更にこれに[SerializeField]をつけてあげるとUnity上で認識できるようになります。
この状態でC#Scriptをドラッグ&ドロップするとコンポーネントが追加できるのです。色々なことが出来すぎてちょっと頭がこんがらがってきますね。。
ここは頑張って慣れていきましょう。
そもそもMonoBehaviourってなんなの?
地面の座標を保持しておくと色々なことに使えそうですよね。
例えば特定の地面の上に敵が来たら何かアクションを起こすとか。
そこで地面の座標を保持する方法をみていきましょう。
まずは構造体について理解していくところからです。
構造体とは?
複数の値をまとめて格納できる型だそうです。(ザックリ)
これだけ聞いても何もイメージ沸かないと思うので具体的にみていきましょう。
例として座標情報の構造体を定義してみます。
public struct Point // struct = 構造体 , Point = この構造体の名前
{
public int X {get;set;} // X座標を定義
public int Y {get;set;} // Y座標を定義
//x,y座標を引数とした点を定義
public Point(int x,int y)
{
this.X = x;
this.Y = y;
}
}
上記はx座標の値、y座標の値、x-y座標を引数とした点の値を格納できるPointという構造体です。
このPoint構造体を使いたい場合は使いたいクラス側でPointを以下のように定義してあげればいいです。
public Point zahyou {get; set;}
地面の座標を保持する
構造体がなんとなく理解できたところで、本題の地面の座標を保持するにはどうすればよいかというところですが、こちらは毎度おなじみ。
地面のPrefabに対しC#Scriptのコンポーネントを追加してあげればいいです。
で、このC#Scriptの中身に地面の座標情報を設定するクラスを定義してあげればよさそうです。具体的にみていきましょう。
まずはC#Scriptの方からです。(この中で構造体が暗に出てきます)
public class TileScript : MonoBehaviour
{
public Point GridPosition { get; private set; }
// 地面の位置情報を設定します。
// 引数はPointとVector3です。
// gridPositionでx,y座標を保持して
// 引数のworldPosでこの地面のゲーム上の位置を設定します。
public void Setup(Point gridPos, Vector3 worldPos)
{
this.GridPosition = GridPos;
transform.position = worldPos;
}
}
今更だけどMonoBehaviourって何?
すごい今更だけどクラスの横のMonoBehaviourっていうのが
何か気になったので調べてみました。
MonoBehaviourはUnityで使うスクリプトのベースとなるスクリプトだそうです。
つまりUnityでスクリプトを独自に作りたい場合はこれを継承しないといけなそうです。
継承?
継承の意味は「受け継ぐこと」。そのままです。
継承するとそのクラスの機能をそのまま使うことができるようになります。
public class TileScript : MonoBehaviour
上の例ではTileScriptっていうクラスがMonoBehaviourというクラスが持っている機能を継承しています。
継承先クラス名 : 継承元クラス名
っていう風に記載すると継承されます。
つまりMonoBehaviourっていうクラスの中にはUnity上で使うような機能がたくさん詰め込まれているんでしょうね。
なのでこれを継承しないといけませんよってことみたいです。
prefabにc#scriptを追加する
prefabにある地面の画像をクリック→InspectorウィンドウのAdd Componentをクリックしさきほど作成したTile Scriptを検索しましょう。
Tile ScriptがPrefabに追加されました。
このTile Scriptをゲームスタート時に実行させるようにします。
つまりTile Scriptという変数を定義してあげます。
TileScript newTile = Instantiate(tilePrefavs[tileIndex]).GetComponent< TileScript>();
そしてこの変数のSetupを呼び出して位置情報を設定してあげます。
newTile.Setup(new Point(x, y), new Vector3(worldStart.x + (TileSize * x), worldStart.y - (TileSize * y), 0));
最初の引数であるnew Point(x, y)が地面のxy座標を設定してあげています。
2つめの引数がゲーム上の地面の位置を設定してあげています。
これで完成しました。実行してみましょう。
以前と何も変わらずに地面が表示されました。
中身の構造を変えただけなのでゲーム上では変化はありません。
しかしこれで色々なゲームの分岐処理を書けるようになったのです!
今回は以上です。