このゲームの醍醐味でしょう、同じフルーツがくっついたら進化後のフルーツに変化する!
フルーツを進化させる(さくらんぼ→いちご)
フルーツを進化する処理は、幾つかに分けて実装を行います。いきなり完璧にはならない点を予めご理解ください
進化後のインスタンスを生成する
まずは一番わかり易い部分を実装しましょう。
- 同じフルーツがぶつかると消滅する
- 2つのフルーツの中間に進化後のフルーツを生成
- 生成する際、先に出現したフルーツ側が生成を行う
上の2点に関しては疑問も少ないと思いますが、「一番下の先に出現したフルーツが作る」という部分ですが、衝突では両方のフルーツで処理が動きます。そのためどちらがわで作るかを事前に決める必要があります。今回はstatic変数というものを使い、各フルーツの通し番号を利用します。スクリプトは以下。
public class Fruits : MonoBehaviour
{
public FRUITS_TYPE fruitsType;
private static int fruits_serial = 0;
private int my_serial;
public bool isDestroyed = false;
[SerializeField] private Fruits nextFruitsPrefab;
private void Awake()
{
my_serial = fruits_serial;
fruits_serial++;
}
private void OnCollisionEnter2D(Collision2D other)
{
if (isDestroyed)
{
return;
}
if (other.gameObject.TryGetComponent(out Fruits otherFruits))
{
if (otherFruits.fruitsType == fruitsType)
{
if (my_serial < otherFruits.my_serial)
{
isDestroyed = true;
otherFruits.isDestroyed = true;
Destroy(gameObject);
Destroy(other.gameObject);
Vector3 center = (transform.position + other.transform.position) / 2;
Quaternion rotation = Quaternion.Lerp(transform.rotation, other.transform.rotation, 0.5f);
Fruits next = Instantiate(nextFruitsPrefab, center, rotation);
}
}
}
}
}
ポイントとしては以下
- 自分の番号が何番かを知る
- Awake時にフルーツの通し番号をコピー
- コピー後に通し番号を増やすことで次のフルーツと同じ番号にならないようにする
- my_serial < otherFruits.my_serial
- 自分の番号と相手の番号を比較して、自分の番号が若い場合次のフルーツを作成する
- 生成時の処理
- center:自分と相手のフルーツの座標の中心を取得
- rotation:最初は気になりづらいが、お互いのフルーツの回転具合の平均を取る。
- こちらに関してはなくてもいいけど、実装しておいたほうがそれっぽくなる
さくらんぼのプレファブに進化プレファブをセット
まずはさくらんぼ同士がぶつかるといちごのプレファブが生成されるようにします。最終的には各プレファブに設定を行う必要があります。
さくらんぼのプレファブを選択したら、Next Fruitsにいちごのプレファブをセットします。
セットできたらチェリーを上下に2つ配置して実行してみてください。
重なったタイミングでいちごのプレファブが生成されます!あまり回転していないので、傾き具合は少し分かりづらいですね。確認したい場合は位置をそのままにしておいて、傾きだけ変えておくとわかりやすく変化します。
さらに機能を追加する
テストだけだと問題点に気づきにくい部分があります。ここでは次の点に関しての機能を追加したいと思います。
必要に応じて追加します。
物理的な挙動の補完
フルーツにはRigidBody2Dが実装されています。位置や角度の中心を取るだけでは速度がリセットされてしまいます。そのため速度と角速度の平均を与え直すことにします。
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.TryGetComponent(out Fruits otherFruits))
{
if (otherFruits.fruitsType == fruitsType)
{
if (my_serial < otherFruits.my_serial)
{
Destroy(gameObject);
Destroy(other.gameObject);
isDestroyed = true;
otherFruits.isDestroyed = true;
Vector3 center = (transform.position + other.transform.position) / 2;
Quaternion rotation = Quaternion.Lerp(transform.rotation, other.transform.rotation, 0.5f);
Fruits next = Instantiate(nextFruitsPrefab, center, rotation);
// 2つの速度と角速度の平均をとる
Rigidbody2D nextRb = next.GetComponent<Rigidbody2D>();
Vector3 velocity = (GetComponent<Rigidbody2D>().velocity + other.gameObject.GetComponent<Rigidbody2D>().velocity) / 2;
nextRb.velocity = velocity;
float angularVelocity = (GetComponent<Rigidbody2D>().angularVelocity + other.gameObject.GetComponent<Rigidbody2D>().angularVelocity) / 2;
nextRb.angularVelocity = angularVelocity;
}
}
}
}
ずらし具合によっては
最後のフルーツは進化させない
スイカがくっついた場合、消滅するだけになるのですが、現在のプログラムでは次のプレファブを作成しようとしてしまいます。そのためnextFruitsPrefabに何もセットされていない場合は削除のみを行うように処理を追加します。
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.TryGetComponent(out Fruits otherFruits))
{
if (otherFruits.fruitsType == fruitsType)
{
if ( my_serial < otherFruits.my_serial)
{
Destroy(gameObject);
Destroy(other.gameObject);
isDestroyed = true;
otherFruits.isDestroyed = true;
if( nextFruitsPrefab == null ){
return;
}
Vector3 center = (transform.position + other.transform.position) / 2;
Quaternion rotation = Quaternion.Lerp(transform.rotation, other.transform.rotation, 0.5f);
Fruits next = Instantiate(nextFruitsPrefab, center, rotation);
// 2つの速度の平均をとる
Rigidbody2D nextRb = next.GetComponent<Rigidbody2D>();
Vector3 velocity = (GetComponent<Rigidbody2D>().velocity + other.gameObject.GetComponent<Rigidbody2D>().velocity) / 2;
nextRb.velocity = velocity;
float angularVelocity = (GetComponent<Rigidbody2D>().angularVelocity + other.gameObject.GetComponent<Rigidbody2D>().angularVelocity) / 2;
nextRb.angularVelocity = angularVelocity;
}
}
}
}
コメント
コメント一覧 (1件)
[…] SG-フルーツを進化させる+位置や物理挙動の補完!part05 […]