はじめに
Project Tinyでミニゲームを作成時に使用した機能やトラブルを説明していきます。
今回はゲーム中の当たり判定・アニメーションの実装についてです。
リポジトリはこちら。
当たり判定
使用するコンポーネントはRectHitBox2Dです。
マニュアル
https://docs.unity3d.com/Packages/com.unity.tiny@0.16/manual/module-hitbox2d.html
判定方法
Sprite2DRnederer,RectHitBox2Dが設定されているEntity同士が接触すると
HitBoxOverlapコンポーネントが追加され、非接触の状態になると削除されます。
このHitBoxOverlapコンポーネントの存在の有無で当たり判定を行います。
今回のゲームではキャラクターが障害物に接触したら即ゲームオーバーなので、
HitBoxOverlapが存在したらゲームオーバーフラグを立てる処理を行っています。
Entities.ForEach((Entity entity, ref Character character, ref RectHitBox2D rectHitBox2d) => {
if (EntityManager.HasComponent<HitBoxOverlap>(entity)) {
isGameOver = true;
}
});
不便な点
Colliderであれば設定したサイズをSceneビューで見ることが出来ますが、
RectHitBox2Dではそういうプレビュー的なものが存在しないためサイズ調整がなかなか難しいです。
なので、このランゲームではけっこういい加減な判定になっています。
アニメーション
Sprite2DSequenceとSprite2DSequencePlayerの2つのコンポーネントを使用します。
リファレンス
Sprite2DSequence
Sprite2DSequencePlayer
設定手順
-
適当なEntityにSprite2DSequenceをAdd Componentする
-
Sprite2DRendererが設定されているEntityにSprite2DSequencePlayerをAdd Componentする
-
Sprite2DSequencePlayerのsequenceにSprite2DSequenceのEnitityを設定する
Sprite2DSequencePlayerのフィールドの説明
sequence
Sprite2DSequenceが設定されているEntity
speed
再生スピード
1が通常スピード
1未満でスロー再生、1以上で倍速再生
time
現在の時間
値を設定することで途中からの再生を行うことができる
paused
一時停止
ループタイプ
Name | Description |
---|---|
ClampFoever | 再生後最終フレームを維持する |
Loop | 通常ループ |
Once | 一度だけ再生 |
PingPong | いったり来たりをする再生を繰り返す |
PingPongOnce | PingPongを一度だけ行う |
アニメーションの切り替え
Animationsコンポーネントを作成しその中に各アニメーションのSprite2DSequenceのEntityを設定できるようにしてあります。
public struct Animations : IComponentData {
public Entity SequenceIdleEntity;
public Entity SequenceRunEntity;
public Entity SequenceJumpEntity;
public Entity SequenceDeathEntity;
}
あとはCharacterAnimationSystemで入力や状態を見て、Sprite2DSequencePlayerのsequenceのEntityを変更することでアニメーション切り替えを行っています。
public class CharacterAnimationSystem : ComponentSystem {
protected override void OnUpdate() {
Entities.ForEach((ref Animations anims) => {
var sequenceIdleEntity = anims.SequenceIdleEntity;
var sequenceRunEntity = anims.SequenceRunEntity;
var sequenceJumpEntity = anims.SequenceJumpEntity;
var sequenceDeathEntity = anims.SequenceDeathEntity;
var isGameOver = false;
var isPlaying = false;
var begun = false;
var retry = false;
Entities.ForEach((ref GameState game) => {
isGameOver = (!game.GameOverPrev && game.GameOver);
isPlaying = game.Playing;
begun = game.Begun;
retry = game.Retry;
});
Entities.ForEach((ref Character character, ref Sprite2DSequencePlayer sequencePlayer) => {
if (true) {
if (isGameOver) {
// ゲームオーバー
sequencePlayer.time = 0.0f;
sequencePlayer.loop = LoopMode.ClampForever;
sequencePlayer.sequence = sequenceDeathEntity;
}
else if (begun) {
// ジャンプ
sequencePlayer.time = 0.0f;
sequencePlayer.loop = LoopMode.ClampForever;
sequencePlayer.sequence = sequenceJumpEntity;
}
else if (retry) {
// 走り
sequencePlayer.time = 0.0f;
sequencePlayer.loop = LoopMode.Loop;
sequencePlayer.sequence = sequenceRunEntity;
}
else {
if (!character.jumpingPrev && character.jumping) {
// ジャンプ
sequencePlayer.time = 0.0f;
sequencePlayer.loop = LoopMode.ClampForever;
sequencePlayer.sequence = sequenceJumpEntity;
}
else if (character.jumpingPrev && !character.jumping) {
// 着地
sequencePlayer.time = 0.0f;
sequencePlayer.loop = LoopMode.Loop;
sequencePlayer.sequence = sequenceRunEntity;
}
}
}
});
});
}
}