前回までの記事
この記事はUNITYの公式チュートリアル『Ruby's Adventure』を日本語で解説している記事です。
↓↓記事一覧↓↓
#2 タイルマップ~物理演算 ←いまここ
(番外編)うまく動かない場合の対処法
ワールドデザイン-タイルマップ
タイルマップを作成しよう
さて、キャラクターを動かせたところで、次はマップを作りたいと思います。
2Dのマップを作るには「タイルマップ」という機能が必要です。
↑こんなのです。RPGツクールとかでよく見るやつですね。
まずはUNITY画面上部の「Windows」→「Package Manager」をクリックしてください。
少し待って読み込みが終わったら、ウインドウ上の「Packages▼」から「Unity Registry」を選び、現れた項目から「2D Tilemap Editor」を選び、ウインドウ右下の「Install」をクリックします。
これでUNITYで「タイルマップ」が使えるようになったので、UNITY画面上部の「Window」→「2D」→「Tile Palette」をクリックします。
これがタイルマップを管理する「Tile Palette」ウインドウです。見やすい場所に配置してください。
次に、ヒエラルキーウインドウを見てください。
このなかの空いてるスペースで右クリック→「Create」→「2D Object」→「Tile Map」→「Rectangular」を選択してください。Rectangular=矩形(くけい。すべての角が直角の四角形)です。
作成されたオブジェクトは「FirstTile」という名前に設定しましょう。
次に、Projectウインドウ内の「Assets」→「Art」フォルダの中に「Tile」というフォルダを作成してください。
また、この画像をダウンロードして、そのTileフォルダにドラッグ&ドロップしてください。
Spriteになっていなかったら、Inspectorウインドウから2D Spriteに適用するのを忘れずに。
次に、Tile Paletteウインドウの「Create New Palette」をクリックします。
こんな画面が出てくると思います。
Name(パレット名)は「GamePalette」と名付けてください。Gridは「Rectangle(矩形)」、Cell Sizeは「Automatic(自動)」、Sort Modeは「Default」のままで大丈夫なので、右下のCreateをクリックしてください。
フォルダ選択画面になったら、先ほど作成したTileフォルダを指定してください。
次に、Projectウインドウ内の先ほど保存した画像をTile Paletteウインドウ内にドラッグ&ドロップしてください。
これでタイルマップが完成しました!初期設定は若干面倒ですが、ここまでくればあとは画像を追加していくだけなので簡単ですね。
次に、タイルパレットの上部にあるツールバーからブラシツールを選択し、
さっき置いたタイルを選択してからゲーム画面上にタイルを配置してみてください。
あれ、なんかスキマができちゃいましたね。
ここで、Hierarchyウインドウに先ほど自動生成された「Grid」というゲームオブジェクトを確認してください。これはTile Mapをゲーム画面に配置するときの枠を管理するオブジェクトです。
Cell Sizeは1となっています。ここは問題なさそうです。
次に、先ほどダウンロードしてProjectウインドウにドラッグ&ドロップした元画像をクリックしてください。
「Pixels Per Unit(ユニットあたりのピクセル数)」が100となっています。ということは、この画像は今のプロジェクトに追加すると、1ユニットあたり100ピクセル分描画されるということです。
説明が遅れましたが、「ユニット」とはUNITY内の距離を表すことばです。ゲーム画面は拡大縮小が可能なので、cmやpixelといった長さの単位を使えないため、ユニットという言葉を使います。
次に、同じウインドウの少し下にある「Sprite Editor」というボタンを押してみてください。
画像編集ウインドウが出てきますが、編集するわけではなく、↑赤枠の部分に注目してください。ここに画像サイズが書かれていますが、縦横64ピクセルとなっていますね。
つまり、この画像は1ユニットあたり100ピクセル描画されるにも関わらず、画像サイズは64ピクセルしか無かったため、配置したときに36ピクセルのスキマが発生していたわけです。
なので、先ほどの「Pixels Per Unit」の値を100から64に変更してみましょう。すると…
いい感じですね!
タイルセットを作ってみよう
続いて、この画像を見てください。
中央は先ほどのタイル画像ですが、周りにオレンジ色の草(?)が生えているようなデザインになっていますね。
このタイルは、↓このような構造になっています。
中央、上下、左右、カドの計9枚のタイルがあればこのような地面を再現できそうですね。これをタイルセットといいます。
で、これではなくてちょっと別のやつを置いてみましょう。
Projectウインドウの「Assets」→「Art」→「Sprites」→「Environment」フォルダのなかの「FloorBricksToGrassCorner」というデータ
これをProjectウインドウ内でクリックしてください。
クリックすると詳細がInspectorウインドウに現れるので、先ほどと同じように「Pixels Per Unit」の値を100から64に変更してみましょう。
続いて、この画像を9分割したいと思います。手作業でやると面倒なので、UNITYに自動でやってもらいましょう。
同じくInspectorウインドウのなかの「Sprite Mode」を「Single」から「Multiple」に変更して、ウインドウ右下の「Apply」ボタンを押してください。これによって一つの画像を分割して使用する準備が整います。
次に、同じくInspectorウインドウ内の「Sprite Editor」ボタンをクリックしてください。
こんなウインドウが出てきますが、ちょっと小さくてボタンが隠れてしまってるので、ウインドウをヨコに引き延ばしてください。
見えてきたウインドウ上部の「Slice▼」というボタンを押して、「Type」を「Grid By Cell Count(セル数によるグリッド)」に変更し、「Column & Row(列と行)」をそれぞれ「3」に変更し、「Slice」を押してください。
画像が9分割されたら、Sprite Editorウインドウ右上のApplyボタンで適用してください。
少し解りにくいですが、Projectウインドウの元画像の▶ボタンのなかに9分割された画像が生成されました。
次に、その元画像(分割された一つ一つではなく、もとの▶ボタンが付いてる画像)をTile Paletteウインドウにドラッグ&ドロップしてください。
これでタイルセットの完成です!
終わったら、Tileフォルダの中の「Floor」から始まる名前のファイルを全てタイルセットに分割して、Tile Paletteウインドウに追加してください。
だいたいこんな感じで使いやすいように配置してください。パレット内ではマウスホイールで拡大縮小ができ、変な場所に配置してしまった場合はTile Paletteウインドウ上部でEditボタンを押せば編集可能です。
それでは、実際にゲーム画面にタイルを配置してみましょう。
↑大体でいいので、こんな感じに配置してください(緑の矢印は気にしないでください)
塗りつぶしツールやブラシツール、消しゴムツールなどが有用です。
続いて、キャラクターがタイルに埋もれてしまったのでレイヤー順序を調整したいと思います。
まず、Hierarchyウインドウに作ったタイルマップのオブジェクトFirstTileをクリックしてください。
次に、Inspectorウインドウ内の「Tilemap Renderer」という枠内の「Additional Settings」→「Order in layer(レイヤー順序)」を「0」から「-10」に変更してみましょう。
この状態で始動すれば、マップ上を移動するRubyを眺めて楽しむことができましたね。
世界を飾りつけよう
レイヤー順序の入れ替わり判定を設定しよう
続いて、作成した世界に装飾を追加してみましょう。
Projectウインドウから「Assets」→「Art」→「Sprites」→「Environment」フォルダへ進み、「MetalCube」をHierarchyウインドウにドラッグ&ドロップしてください。
ゲーム画面にMetalCubeが現れたら、オブジェクトMetalCubeを選択した状態でWキーを押すと位置を移動できます。
さて、この状態で試動してみると、
箱を通り抜けられてしまう問題は一旦置いといて、レイヤー順序に注目してください。
左の箱はRubyよりも奥にあり、右の箱はRubyよりも手前にあるように見えます。
このままではどちらもダメです。
なにがダメか解りますでしょうか?
では、↓この画像をご覧ください。
こちらは箱がRubyよりも手前にあるパターンです。
左画像のようにRubyの足下が箱よりも下にあるとき、Rubyが箱の下敷きになっているように見え、不自然です。
しかし、右画像のようにRubyの足下が箱よりも上にあると、Rubyが箱の後ろに立っているように見え、自然ですよね。
こちらは箱がRubyよりも奥にあるパターンです。
左画像のようにRubyの足下が箱よりも下にあるとき、Rubyが箱の手前に立っているように見え、自然です。
しかし、右画像のようにRubyの足下が箱よりも上にあると、Rubyが箱の手前で浮いているように見え、不自然です。
この問題を解決するためには、オブジェクトよりも奥にいるか手前にいるかを、足元(オブジェクトの底辺)が下にあるか上にあるか(y軸)で判定する必要があります。
まずはy軸を基に判定する設定をします。
まずはUNITY画面上部を見ていただき、↓の赤丸の部分が「Center」になっている場合、クリックして「Pivot」モードに切り替えてください。
次に、UNITY画面上部の「Edit」→「Project Settings」→「Graphics」→「Transparency Sort Mode(透過並び替えモード)」を「Custom Axis(軸でカスタム)」に変更し、その下の「Transparency Sort Axis(透過並び替え軸)」を「x:0 y:1 z:0」に変更してください。これでOKです。
続いて、その判定をオブジェクトの底辺で行う設定をします。これはちょっと面倒です。
まず、現在の並び替え判定点がどこにあるかを確認するために、オブジェクトRubyを選択した上でTキーを押して矩形モードに切り替えてください。
…かなり見えにくいのですが、よーくみるとゲーム画面のオブジェクトの中心に青い丸マークがあります。ここが並び替え判定点なので、これを移動させます。
まず、HierarchyウインドウのオブジェクトRubyを選択した状態でInspectorウインドウの「Sprite Sort Point」を「Pivot」に変更してください。
次に、Projectウインドウにある元画像のRubyを探してクリックしてください。
Hierarchyウインドウのオブジェクトをクリックして、Inspectorウインドウの「Sprite」に適用されている画像ファイルをクリックすれば、Projectウインドウ内の元画像ファイルがハイライトされます。
Projectウインドウの元画像をクリックできたら、Inspectorウインドウの「Pivot(回転軸)」を「Center(中心)」から「Bottom(底)」に変更します。これでOKです。
青い丸がオブジェクトの底辺に移動しましたね。
※Pivotを手動で配置したい場合は、同じくInspectorウインドウの「Sprite Editor」を開き「Pivot」を「Custom」に切り替えれば、青い丸をドラッグして好きな位置に移動することが可能です。
↑こんな感じです。
終わったら、同じ事を鉄の箱にもしておきましょう。
プレハブを作ろう
プレハブを作りましょう!
…といっても、↑小屋を建てようと言っているのではありません。
「プレハブ(Prefab)」とは、オブジェクトを設定ごと保存したデータのことです。
あなたは先ほど鉄の箱をオブジェクトとしてゲーム画面に配置しましたね。
例えば、そのオブジェクトをメチャクチャ細かく調整しまくったとします。
で、別のマップに同じ箱を配置しようとすると、別のマップは別のシーン(Scene)ファイルで作業することになるため、オブジェクトは全てカラの状態から再スタートします。つまり、細かい調整をシーンごとにやり直さなければいけないわけです。
そんな時のために、オブジェクトを設定ごと保存する機能=プレハブがあるわけです。
作り方は簡単です。
まずは整理整頓のため、Projectウインドウの「Assets」フォルダ内に「Prefabs」というフォルダを作成して、そのフォルダを開いてください。
次に、Hierarchyウインドウから鉄の箱オブジェクトを「Prefab」フォルダにドラッグ&ドロップしてください。
これでプレハブ作成完了です。↑このように、プレハブをHierarchyウインドウにドラッグ&ドロップすれば同じオブジェクトを複製することも可能です。
とりあえず鉄の箱オブジェクトを複製して、3つの鉄の箱をゲーム画面に配置して、Ctrl+Sでシーンを保存してください。
あれ、なんか変ですね。中央の箱が右の箱よりも下にあるので、影まで手前に描画されてしまっています。
こんなときは書くオブジェクトのy軸をほんの少し(0.001とかでもOK)ずらして、右の箱を中央の箱よりも下に配置しましょう。
(本当は影と箱を別のオブジェクトにして影は地面と同じレイヤー順序に設定すればよいのですが、ちょっと面倒なので…。)
さて、お気づきのとおり、Prefab化したオブジェクトはアイコンと名前が青くなります。
これらのオブジェクトを一括で編集してみましょう。
まず鉄の箱オブジェクトを選択し、Inspectorウインドウの上の方にある「Prefab」という項目の「Open」ボタンを押してください。
Prefab編集モードになるので、Inspectorウインドウの「Color」で色を変えてみましょう。
適当に色を変えたら、Projectウインドウの左上の「<」ボタンを押してPrefab編集モードを抜けます。すると、
全ての箱の色が変わりました。Prefabを編集すれば、そのPrefabによって作られた全てのオブジェクトに変更が適用されるのですね。
Prefab化したオブジェクトでも個別に変更を加えることは可能です。
ゲーム画面で中央の箱を選択し、Inspectorウインドウで色を変えてみましょう。
このように、Prefab自体を編集しなければオブジェクトは個別に編集可能です。
スーパー・クリエイティブ・タイム!
それでは、ここまでの知識を活かして世界に飾りつけを追加しまくってみましょう。
まずは整理整頓のため、HierarchyウインドウのなかにCreate Emptyでカラのオブジェクトをつくり、「Environment」とでも名付けたうえでり、これまでに追加した鉄の箱を全てオブジェクトのなかにいれましょう。
Projectウインドウの「Art」→「Sprites」→「Environment」フォルダの中にある様々な画像を使って、ゲーム画面にオブジェクトを追加します。
画像からオブジェクトを追加する際の手順をおさらいしておきましょう。
- 元画像に「▶」ボタンが付いていなければ、Inspectorウインドウの「Texture Type」を「Sprite(2D and UI)」に切り替えてSprite化します。
- ProjectウインドウからHierarchyウインドウにドラッグ&ドロップします。
- Hierarchyウインドウからゲーム画面にドラッグ&ドロップます。
- 大きさが変ならRキーでサイズ調整するか、元画像のPixel Per Unitの値を調整します。
- オブジェクトのSprite Sort Point及び元画像のPivotを調整します。
なお、作業を進めるうちに「タテに長い物の手前/奥の判定がおかしい」という問題に直面した場合は、この記事を参考に解決してみてください。
あ、そうだ。
↑これなんですけど、これは地面に埋まっているものなので、Rubyよりも前にきてほしくないですよね。
その場合はPivotの位置をBottom(底辺)ではなくTop(上辺)にすると、重なってもRubyが常に手前になるので良い感じです。
物理演算に挑戦しよう
オブジェクトに物理演算を適用させよう
さて、これまでにゲームに追加したものはどれも2D画像として追加したものなので、↓のような物理的な動きはできません(スクリプトで無理矢理それっぽく動かすことは可能ですが)。
↑このような動きを実現するためには、オブジェクトに物理演算を適用させる必要があります。
まずは、HierarchyウインドウのオブジェクトRubyをProjectウインドウのPrefabフォルダにドラッグ&ドロップして、RubyをPrefab化してください。
次に、オブジェクトRubyを選択した状態でInspectorウインドウの「Add Component」から「Rigidbody 2D」を検索して追加してください。
↑こんな感じです。
この状態で試動すると、Rubyが画面下に落下していきます。Rubyに重力が働いているわけですね。
HierarchyウインドウのRubyオブジェクトを選択してうえで、InspectorウインドウのRigidbody 2D枠内のGravity Scale(重力)の値を0に変更してください。
これで画面下に落ちることはなくなります。
しかし、いま変更したのはRubyのオブジェクトであるため、Prefabの重力は0になっていません。
いまの変更をPrefab全体に適用させるために、Inspectorウインドウの上部の「Prefab」の項目の右側「Overrides」→「Apply All(全体に適用)」をクリックしてください。
これでRubyのPrefab全体に変更が適用されたので、異なるシーンにRubyを配置しても重力は0のままになりました。
先ほどの要領でRubyプレハブにコンポーネント「Box Collider 2D」を追加してください。
こんな風になったと思います。この緑色の四角い枠がRubyの当たり判定です。
できたら、鉄の箱Prefabにも同じく「Box Collider 2D」を追加してください。箱は動かさないので「Rigidbody 2D」は不要です。
さて、この状態で試動してみると…
あら、変ですね。ここでは次の3つの問題が発生しています。
問題3:Rubyの当たり判定がキャラクターの見た目よりも広くて四角い。
それでは、これらの問題を解決しましょう。
回転を止めよう
まずはRubyプレハブのInspectorから、Rigidbody 2D枠内のConstraints→Freeze Rotation(回転を固定)の「Z(z軸)」にチェックを入れてください。
これで「z軸を支点とした回転」=2D的な回転は止まります。簡単ですね。
FixedUpdateを使おう
次に、Rubyが箱に当たった時にガクガク震えている問題について説明します。
このモノとモノがぶつかった時にガクガク震える現象をJitterといいます。
Jitterの原因については………すみません、難しすぎて私も理解できてないです。
…で、どうすればJitterを解決できるのかというと、移動の処理をUpdate()からFixedUpdate()という処理に移す必要があります。
Update()が毎フレーム処理されるのに対して、FixedUpdate()は一定時間(「Edit」→「Project Settings」→「Time」のFixed Timestepの値。初期設定は0.2秒)ごとに処理が行われます。
※詳しくはかなり複雑な話になるのですが、だいたい↑の認識で大丈夫だと思います。
というわけで、RubyControllerスクリプトを開き、下記のとおり書き換えましょう。
public class RubyController : MonoBehaviour
{
Rigidbody2D rigidbody2d; //←ここ
float horizontal; //←ここ
float vertical; //←ここ
void Start()
{
rigidbody2d = GetComponent<Rigidbody2D>(); //←ここ
}
void Update()
{
horizontal = Input.GetAxis("Horizontal"); //←ここ
vertical = Input.GetAxis("Vertical"); //←ここ
}
void FixedUpdate() //←ここから
{
Vector2 position = rigidbody2d.position;
position.x = position.x + 3.0f * horizontal * Time.deltaTime;
position.y = position.y + 3.0f * vertical * Time.deltaTime;
rigidbody2d.MovePosition(position);
} //←ここまで
}
色々変わりましたね。//と書いてある箇所が変更点です。
まずここ。
Rigidbody2D rigidbody2d;
「rigidbody2d」はRubyオブジェクトのコンポーネント「Rigidbody2D」を入れるための変数です。
次にここです。
float horizontal;
float vertical;
void Update()
{
horizontal = Input.GetAxis("Horizontal");
vertical = Input.GetAxis("Vertical");
}
ここは以前、変数(horizonとvertical)の型(float)の初期値としてキー入力(Input.GetAxis)を入れていました。しかし、今回は別の用途でこの変数を使うこととなったので、このように書いて他の場所でも変数を使えるようにしています。
次にここ。
void Start()
{
rigidbody2d = GetComponent<Rigidbody2D>(); //←ここ
}
Start()は初めに一度だけ処理されるものです。
「GetComponent」は、(<>内で指定した)オブジェクトのコンポーネントをスクリプトで捕まえるためのコードです。
「<Rigidbody2D>」は、コンポーネントの名前ですね。
まとめると、「rigidbody2d = GetComponent<Rigidbody2D>();」は、変数rigidbody2dでコンポーネント「Rigidbody2D」をいじれるようにするよ、という意味です。
次にここです。
void FixedUpdate()
{
Vector2 position = rigidbody2d.position;
position.x = position.x + 3.0f * horizontal * Time.deltaTime;
position.y = position.y + 3.0f * vertical * Time.deltaTime;
rigidbody2d.MovePosition(position);
}
「FixedUpdate()」についてはさきほど説明しましたね。
このなかに、元々Update()内に入れていた移動制御に関するコードを移しています。
「rigidbody2d.MovePosition(position);」は、変数rigidbody2d=コンポーネント「Rigidbody 2D」のなかの「MovePosition(移動制御)」に変数positionを適用するよ、という意味です。
必ず「Rigitbody2Dを入れた変数.MovePosition(Positionの値を入れた変数);」というコードを記述して、コンポーネント「Rigidbody 2D」のなかの「MovePosition(移動制御)」に値を送り込む必要があるのです。
忘れやすいので注意しましょう。
当たり判定を調整しよう
続いて、当たり判定を調整していきましょう。
まずは鉄の箱PrefabのInspectorにあるBox Collider 2DのEdit Colliderのボタンを押してください。
当たり判定が緑の枠として表示されるので、箱が地面に接地しているあたりに調整しましょう。
終わったらOverridesのApply AllからPrefab全体に適用するのを忘れずに。
ちなみに、当たり判定が四角いとカドに引っかかってしまう可能性があります。
そのため、当たり判定を丸くしたい場合は「Box Collider 2D」ではなく「Capsule Collider 2D」を使用することで、楕円の当たり判定を付与することが可能です。
これで完了です。簡単ですね!
タイルマップにも当たり判定を追加しよう
続いて、Rubyが池の上を走れないようにタイルマップにも当たり判定を追加します。
HierarchyウインドウのオブジェクトGridの中に入っている子オブジェクトFirstTileを選択したうえで、Inspectorにコンポーネント「TilemapCollider2D」を追加してください。
これで、全てのタイルにスキマ無く当たり判定が追加されました。
次に、Projectウインドウ内の池以外のタイルを全て選択してください。Shiftキーを押しながら選択すれば複数選択可能です。
↑こんな感じです。
選択した状態でInspectorウインドウのCollider Typeを「None」に変更してください。
これで、池以外の全てのタイルから当たり判定が取り除かれました。
良い感じですね!
当たり判定を統合しよう
さて、いまは池のタイル一つ一つに当たり判定が付与されているため、マップが広くなると処理が重くなる可能性があります。
そのため、くっついている当たり判定は統合してしまいましょう。
再びHierarchyウインドウのFirstTileオブジェクトを選択し、Inspectorウインドウで「Composite Collider 2D」を追加してください(自動的にRigidbody 2Dも追加されます)。
次に、Tilemap Collider 2D内の「Used By Composite」にチェックを入れて複合化し、Rigidbody 2DのBody Typeを「Static(静的)」にして動かないようにします。
これで、当たり判定を持つタイルマップは、くっついている場合に自動的に複合化されるよう設定されました。あとで追加してもくっついていれば複合化されます。
(ちょっと寄り道)試動画面かどうかをわかりやすくしよう
さて、ここでちょっとチュートリアルから外れて寄り道をしてみましょう。
これまで、作ったゲームを試しに動かす時にはUNITY画面上部の▶ボタンを押してましたよね。
ここです。
このボタンを押して再生中は「試しにゲームを起動させしている状態」なので、例えばゲーム内容によってはオブジェクトが消えることもあれば値が書き換わることもあります。敵を倒せば敵のオブジェクトが消えますよね。
でも、もう一度▶ボタンを押して編集画面に戻ると、試動中の変更は全て元に戻ります。
つまり、▶ボタンを押したまま試動中であることを忘れてゲーム開発を進めてしまうと、後で気付いて▶ボタンを再び押して編集画面に戻ったとき、試動中に編集した内容が全て試動前の状態に戻ってしまうという問題が発生します。
これを防ぐために、試動中は「いまは試動中だよ」とわかりやすくしましょう。
UNITY画面上部の「Edit」→「Preference」→「Color」の項目で、UNITYの画面の色を変更することができます。
このなかの「Playmode tint」を緑色とかそんな感じにしてみましょう。すると、
こんな風に画面全体が緑色になり、試動中であることが視覚的にわかりやすくなります。
こうやって開発環境を整えるのって、気持ちいいですよね!
次の記事はこちらです。