仕様はいたってシンプルです。
- キーを押したら障害物にぶつかるまで進み続ける。
- 移動中にキーを押すと、その方向に移動できるようになったとき自動的にその方向に進む。
- ワープ地点に来たら反対側にワープする。
- エサ、パワーエサ、フルーツ、怯えた状態のゴーストを食べる。
- 通常状態のゴーストに食べられる。
Pacmanオブジェクトの作成
16px × 16pxの画像を用意し、Pixels Per Unitを8にします。画像はUnityのSprite Packerを使って1つの画像にまとめるとゲーム起動時の負荷が減ります。
画像からSpriteを作成し、Rigidbody2D、CirlceCollider2Dをアタッチします。適当にColliderの大きさを設定します。
Pacmanクラスの作成
移動
当たり判定
Physics2D.Linecastを使います。この関数の引数はグローバル座標なので注意してください。
private Collider2D collider2d;
private bool CanMove(Vector2 dir)
{
Vector2 p = transform.position;
var hit = Physics2D.Linecast(p + dir, p);
return hit.collider == collider2d;
}
フレームごとの移動
Vector2.MoveTowardsを使い現在座標、目標座標、移動速度からフレーム毎の移動座標を求め、Rigid2D.MovePositionで移動させます。
目標座標に限りなく近づいたら壁との当たり判定を行い、判定が偽の場合移動します。
また、キー入力もここで行います。
[SerializeField] private float speed;
private Rigidbody2D rigid2D;
private Vector2 dest;
private Vector2 nextDir;
public Vector2 Direction { get; private set; }
private void Move()
{
var p = Vector2.MoveTowards(transform.position, dest, speed);
rigid2D.MovePosition(p);
if (Input.GetAxis("Horizontal") > 0) nextDir = Vector2.right;
if (Input.GetAxis("Horizontal") < 0) nextDir = Vector2.left;
if (Input.GetAxis("Vertical") > 0) nextDir = Vector2.up;
if (Input.GetAxis("Vertical") < 0) nextDir = Vector2.down;
if (Vector2.Distance(dest, transform.position) < float.Epsilon)
{
if (CanMove(nextDir))
{
dest = (Vector2)transform.position + nextDir;
Direction = nextDir;
}
else
{
if (CanMove(Direction))
{
dest = (Vector2)transform.position + Direction;
}
}
}
}
ワープ
パックマンの現在地をWarpPointの出口にし、進行方向を1つ先に設定するだけです。継承したIWarpable.Warpに実装し、WarpPointに接触したら実行するようにします。
public void Warp(Vector2 pos)
{
transform.localPosition = pos;
dest = (Vector2)transform.position + Direction;
}
食べる
パックマンが食べることができるもの(エサ、パワーエサ、恐慌状態のゴースト、フルーツ)にIEatableインターフェイスを継承します。食べたときの動作は食べられる側で実装します。パックマン側はOnTriggerEnter2DでIEatable.Eatenを実行するだけです。
public interface IEatable
{
event EventHandler OnEaten;
int Score { get; }
void Eaten(Pacman pacman = null);
void Destroy();
}
private void OnTriggerEnter2D(Collider2D collider)
{
var e = collider.GetComponent<IEatable>();
e?.Eaten(this);
}
アニメーション
上下左右の移動と死亡時のアニメーションを作成します。
すべてのアニメーションはAny Stateから遷移するようにします。
Animation ControllerのParametersに以下の変数を作成します。
- float DirX
- float DirY
- bool isDead
遷移の条件は以下の通りです。また、Can Transition To Selfは必ずオフにしておきましょう。
- Up:DirY > 0.1 & isDead == false
- Right:DirX > 0.1 & isDead == false
- Down:DirY < -0.1 & isDead == false
- Left:DirX < -0.1 & isDead == false
- Dead: isDead == true
死亡のアニメション終了と同時に自身を削除するようにしておきます。
public void Destroy()
{
Destroy(gameObject);
}
移動時に、DirXとDirYにパックマンの進行方向を代入します。
private void Animate()
{
animator.SetFloat("DirX", Direction.x);
animator.SetFloat("DirY", Direction.y);
}
死亡時に、IsDeadを真にします。
public void Dead()
{
animator.SetBool("IsDead", true);
}
完成
PacmanオブジェクトにAnimator、Pacmanクラスをアタッチします。適当にSpeedを設定します。
毎フレーム、MoveとAnimateを実行させます。
private void FixedUpdate()
{
Move();
Animate();
}
nullsuke.com
上記で作成した迷路上にパックマンをセットすれば完成です。パックマンの初期位置は必ず整数にしてください。そうしないと、移動中に引っかかってしまいます。