任意の地点に重力ポイントを設置。
円の内周を移動するプレイヤーと、外周を移動する敵キャラを実装。
横スクロールで有りながら、見下ろし型ゲームのように、画面を上まで余す所なく使える。
サンプル動画
プレイヤーのジャンプ力が高過ぎて、重力反転のようになった。
面白いと思ったので、そのままにしてみた。
前提
- キャラクター画像は、各自任意のアセットで。
(この例では、無料アセットの[Ansimuz] Sunny Landを使用) - プロジェクト作成時に、2Dテンプレートを選択。
(細かい所の設定が2D向けになり、2D用の機能が導入される)
ざっくりな解説
- 地面(フレーム)作成。
- Sprite RendererのSpriteに画像を設定。
フレーム画像(512 x 512) - 小さいので、TransformのScaleを(2, 2, 2)に変更。
- Polygon Collider 2Dをアタッチ。
- Sprite RendererのSpriteに画像を設定。
- プレイヤー作成。
- Sprite RendererのSpriteに画像を設定。
- Capsule Collider 2Dをアタッチ。
- 画像に合わせて、位置とサイズを調整。
- Rigidbody 2Dをアタッチ。
- Gravity Scaleを0に設定(基本の重力の無効化)。
- ConstraintsでRotationを固定(転倒防止)。
- 新規スクリプトに、後述のPlayer用コードを記述。
- 敵キャラ作成。
- Sprite RendererのSpriteに画像を設定。
- Capsule Collider 2Dをアタッチ。
- 画像に合わせて、位置とサイズを調整。
- Rigidbody 2Dをアタッチ。
- Gravity Scaleを0に設定(基本の重力の無効化)。
- ConstraintsでRotationを固定(転倒防止)。
- 新規スクリプトに、後述のEnemy用コードを記述。
詳細な解説
地面(フレーム)の画像をダウンロード
- ライセンス:CC0
- 圧縮済み
地面(フレーム)を作成&設定
- 上部メニュー -> GameObject -> 2D Object -> Spriteを選択、Frameと命名。
- インスペクター -> Transformコンポーネント
- Position:(0, 0, 0)に変更。
- Scale:(2, 2, 2)に変更。
- インスペクター -> Sprite Rendererコンポーネント
- Sprite:インポートした画像”Frame512″を選択。
- インスペクター -> Add Component -> Polygon Collider 2Dをアタッチ。
- インスペクター -> Transformコンポーネント
プレイヤーを作成&設定
- 上部メニュー -> GameObject -> 2D Object -> Spriteを選択、Playerと命名。
- インスペクター -> Transformコンポーネント。
- Position:(0, 0, 0)に変更。
- インスペクター -> Add Component -> Capsule Collider 2Dをアタッチ。
- Offset:ズラす値。キャラクターに合わせて調整。
- Size:キャラクターの大凡のサイズ。
- インスペクター -> Add Component -> Rigidbody 2D
- Gravity Scale:0
- Constraints -> 左の三角をクリック -> Freeze Rotation -> Z:有効化
- インスペクター -> Add Component -> 新規スクリプトを作成&アタッチ。
- インスペクター -> Transformコンポーネント。
敵キャラを作成&設定
前項の「プレイヤーを作成&設定」と同じ手順を繰り返す。
オブジェクトや、スクリプトの命名のみ「Enemy」に変更。
プレイヤーのコード
Playerにアタッチしたスクリプトへ、以下を記述。
//使わなかった為、一応コメントアウト。
//using System.Collections;
//using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
//キャラクターのRigidbody2Dをインスペクターから紐付けしておく。
[SerializeField]
Rigidbody2D rb2d;
//キャラクター画像の表示用コンポーネントをインスペクターから紐付けしておく。
[SerializeField]
SpriteRenderer sr;
//ジャンプ時に掛ける力。任意の値。
float jumpForce = 1000.0f;
//移動時に掛ける力。任意の値。
float moveForce = 30.0f;
//スピード制限。任意の値。余り高過ぎると、ちょっとバグる。
//「Rigidbody2D.velocityのsqrMagnitudeが、speedLimit以上出ていた場合は、AddForceしない」という仕様なので、スピードの上限としては厳密に守られていない。
float speedLimit = 100.0f;
//移動キーの入力値。
float moveDirection;
//重力の中心となる任意の座標。
//ロングステージの任意の地点に重力ポイントを設置したい場合は、シングルトンに座標を持たせておいて適宜、読み込むと良い。
Vector3 gravityPoint = Vector3.zero;
//通常の重力値。変えないなら定数にしていても良い。
float defaultGravity = -9.81f;
//Physics2D.gravityを使うと共通の重力値になってしまう為、キャラクターそれぞれに個別の重力を持たせている。
Vector3 gravity;
void FixedUpdate()
{
//キャラクターの相対的な上を変更、そこを基準としてrotationを決定している。内部で自動的にノーマライズされる。
transform.up = gravityPoint - transform.position;
//十字キーが入力されていたら、キャラクター画像の向きを変更&キャラクターを移動。
if (moveDirection != 0) {
//本当は、相対的なvelocityのX値のみで判定したかったが、色々やっても抽出出来なかった為、妥協。
//ジャンプや落下のスピードも判定に含まれてしまう。
if (rb2d.velocity.sqrMagnitude < speedLimit) {
//移動の入力値に応じて、キャラクター画像の向きを変更。
sr.flipX = moveDirection < 0;
//キャラクターと相対的に移動。
rb2d.AddForce(transform.right * moveDirection * moveForce, ForceMode2D.Force);
}
}
//(先に重力に合わせた向きにしているので、)向きに合わせて重力を設定。
gravity = transform.up * defaultGravity;
rb2d.AddForce(gravity, ForceMode2D.Force);
}
//入力の受付はFixedUpdate内でやると、取得しそびれが発生した。
void Update()
{
//キーボードの十字キー左右の入力を-1.0f ~ 1.0fまでの値として取得。
moveDirection = Input.GetAxis("Horizontal");
//Zキーを押すと、適当にジャンプする。ジャンプ力が高過ぎて重力反転みたいな感じになった。
if (Input.GetKeyDown("z")) {
//相対的な上にジャンプ。
rb2d.AddForce(transform.up * jumpForce, ForceMode2D.Force);
}
}
}
敵キャラのコード
Enemyにアタッチしたスクリプトへ、以下を記述。
//使わなかった為、一応コメントアウト。
//using System.Collections;
//using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField]
Rigidbody2D rb2d;
[SerializeField]
SpriteRenderer sr;
//ジャンプ力。余り高過ぎると、どこかに飛んでいく。
float jumpForce = 300.0f;
float moveForce = 10.0f;
//スピード制限。余り高過ぎると、バグる。この値でも若干、跳ねてしまっている。
//これ以上の速さにするなら、Transform.RotateAroundを使った方が良いかも。
float speedLimit = 30.0f;
//テストとして右に入力しっ放しにしている。
float moveDirection = 1.0f;
Vector3 gravityPoint = Vector3.zero;
float defaultGravity = -9.81f;
Vector3 gravity;
void FixedUpdate()
{
transform.up = transform.position - gravityPoint;
if (moveDirection != 0) {
//敵の画像が左向きだったので、プレイヤー側と条件式を逆にしている。
sr.flipX = 0 < moveDirection;
if (rb2d.velocity.sqrMagnitude < speedLimit) {
rb2d.AddForce(transform.right * moveDirection * moveForce, ForceMode2D.Force);
}
}
gravity = transform.up * defaultGravity;
rb2d.AddForce(gravity, ForceMode2D.Force);
}
void Update()
{
//【テスト用】Xキーを押すと、適当にジャンプする。ジャンプフラグと接地判定は割愛した為、各自で追加してください。
if (Input.GetKeyDown("x")) {
rb2d.AddForce(transform.up * jumpForce, ForceMode2D.Force);
}
}
}
カジュアルゲームや、宇宙アクションゲーム等にどうぞ。