Skip to main content

卵の「体力」

次、卵が強く衝突したら体力が減り、ゼロになったら卵が消える処理を追加しましょう。

スクリプト

まず、単純な考え方で、「ぶつけたら、体力が減る」処理をにしましょう。

// 卵の体力
public class EggHP : MonoBehaviour
{
    // ぶつかるときに受けるダメージ
    [SerializeField] 
    private float hitDamage = 30;
    
    // 体力
    private float hp = 100;
    
    // 衝突の時
    private void OnCollisionEnter(Collision other)
    {
        // ぶつけたら、体力が減る
        hp -= hitDamage;

        // UIまだないため、Debug.Logで確認
        Debug.Log(hp);
      
        // 体力ゼロ以下の場合、ゲームオブジェクトを廃止
        if (hp <= 0)
            Destroy(gameObject);
    }
}

スクリプトを卵にアタッチし、転がしてみましょう。

問題1:すぐ消えてしまう!

ぶつかる時に体力が減るようにしたが、床面ともぶつかるので、転がるだけで死んでしまう!床面に新しい「Floor」タグを付けて、スクリプトで床を無視しましょう。

image.png

// 衝突の時
private void OnCollisionEnter(Collision other)
{
    // 床面を無視する
    if (other.gameObject.CompareTag("Floor"))
        return;
    
    // ぶつけたら、体力が減る
    hp -= hitDamage;

    // UIまだないため、Debug.Logで確認
    Debug.Log(hp);
    
    // 体力ゼロ以下の場合、ゲームオブジェクトを廃止
    if (hp <= 0)
        Destroy(gameObject);
}

これでまた確認してみてください。

問題2:優しくにしても、すぐ体力が減る

たしか、これで床で転がしても体力が減らないが、優しく壁を触れても、体力が30を減る!衝突の強さに合わせて体力が減る処理を追加しましょう。このため Collision の  impulse を使用できる。impulse を確認するため、一旦 OnCollisionEnter を以下のように変えてください:

// 衝突の時
private void OnCollisionEnter(Collision other)
{
    // 床面を無視する
    if (other.gameObject.CompareTag("Floor"))
        return;
    
    // ぶつけたら、体力が減る
    hp -= hitDamage;

    // 一時的に impulse を表示
    // impulseはベクトル(強さと向き)なので、ベクトルの長さを求める
    float hitForce = other.impulse.magnitude;
    Debug.Log($"衝突の強さ:{hitForce}");
    
    // UIまだないため、Debug.Logで確認
    //Debug.Log(hp);
    
    // 体力ゼロ以下の場合、ゲームオブジェクトを廃止
    //if (hp <= 0)
    //    Destroy(gameObject);
}

で実行するとこのように表示される(転がり方による)

image.png

これを使って、スクリプトを直しましょう。最小値と最大値の強さを Unityで設定し、

  • 最小値以下なら:ゼロダメージ
  • 最大値以上んら:最大ダメージ
  • その間は:線形的に補間

ならば、以下のようにスクリプトを直す:

// 卵の体力
public class EggHP : MonoBehaviour
{
    // ぶつかるときに受けるダメージ
    [SerializeField] 
    private float hitDamage = 30;
    
    // 最低の衝突の強さ
    [SerializeField] 
    private float minImpulse = 4;
    
    // 最大の衝突の強さ
    [SerializeField] 
    private float maxImpulse = 20;
    
    // 体力
    private float hp = 100;
    
    // 衝突の時
    private void OnCollisionEnter(Collision other)
    {
        // 床面を無視する
        if (other.gameObject.CompareTag("Floor"))
            return;
        
        // impulseはベクトル(強さと向き)なので、ベクトルの長さを求める
        float hitForce = other.impulse.magnitude;
        
        // 最低と最大の間に正規化する
        float hitNorm = (hitForce - minImpulse) / (maxImpulse - minImpulse);
        hitNorm = Mathf.Clamp01(hitNorm); // 絶対に0と1の間にする
        
        // ぶつけたら、体力が減る
        hp -= hitDamage * hitNorm;

        // UIまだないため、Debug.Logで確認
        Debug.Log($"衝突の強さ:{hitForce}, 残りの体力:{hp}");

        // 体力ゼロ以下の場合、ゲームオブジェクトを廃止
        if (hp <= 0)
            Destroy(gameObject);
    }
}

これで試して、体力の減り方を見てください。

UIを作成

まだUIを作っていないため、先に新しい Canvas を作成し、必要な素材を追加しましょう。Canvasが画面サイズに合わせて自動的にリサイズするように設定しましょう:

image.png

ゲージの作り方

「スライス(Sliced)」スプライトについて

 

 

そして、中には卵の絵とHPのゲージを追加してください(Canvas > Image):