Бар жизни не меняется после того, как игроки уничтожили коллайдер - PullRequest
1 голос
/ 18 марта 2020

Я пытаюсь сделать 2d игру, и мой объект не влияет на спасательный круг игрока после его столкновения. Панель здоровья игрока получит большую продолжительность жизни, но я думаю, что-то не так со скриптами. (Также проверяется коллайдер объекта, который должен быть уничтожен). Я поместил это PowerUp на объект, а также скрипт персонажа и скрипт панели здоровья на игрока.

Character.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;

public class Character : MonoBehaviour
{
    Rigidbody2D rb;
    float dirX;

    [SerializeField]
    float moveSpeed = 5f, jumpForce = 600f, bulletSpeed = 500f;

    Vector3 localScale;

    public Transform barrel;
    public Rigidbody2D bullet;

    // Use this for initialization
    void Start()
    {
        localScale = transform.localScale;
        rb = GetComponent<Rigidbody2D>();
    }

    // Update is called once per frame
    void Update()
    {
        dirX = CrossPlatformInputManager.GetAxis("Horizontal");

        if (CrossPlatformInputManager.GetButtonDown("Jump"))
            Jump();

        if (CrossPlatformInputManager.GetButtonDown("Fire1"))
            Fire();
    }

    void FixedUpdate()
    {
        rb.velocity = new Vector2(dirX * moveSpeed, rb.velocity.y);
    }

    void Jump()
    {
        if (rb.velocity.y == 0)
            rb.AddForce(Vector2.up * jumpForce);
    }

    void Fire()
    {
        var firedBullet = Instantiate(bullet, barrel.position, barrel.rotation);
        firedBullet.AddForce(barrel.up * bulletSpeed);
    }

}

HealthBar.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class HealthBar : MonoBehaviour
{
    public Slider slider;
    public Gradient gradient;
    public Image fill;
    public float health = 100;

    public void SetMaxHealth(int health)
    {
        slider.maxValue = health;
        slider.value = health;

        fill.color = gradient.Evaluate(1f);
    }

    public void SetHealth(int health)
    {
        slider.value = health;

        fill.color = gradient.Evaluate(slider.normalizedValue);
    }

}

PowerUp.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PowerUp : MonoBehaviour
{
    public float multiplayer = 1.4f;
    public GameObject pickupEffect;

    private void OnTriggerEnter(Collider other)
    {
         if (other.CompareTag("Player"))
        {
            Pickup(other);
        }
    }

    void Pickup(Collider player)
    {
        //Spawn a cool effect
        Instantiate(pickupEffect, transform.position, transform.rotation);
        //Apply effect to the player
        HealthBar stats =player.GetComponent<HealthBar>();
        stats.health *= multiplayer;
        // Remove Effect
        Destroy(gameObject);
    }
}

Ответы [ 2 ]

1 голос
/ 19 марта 2020

Прежде всего, как уже упоминалось для игры 2D с Rigidbody2D и (надеюсь) Collider2D компонентами, которые вы хотите использовать OnTriggerEnter2D вместо!

Физика и Физика2D - это два полностью разделенных движка, которые не знают друг друга. 3D OnTriggerEnter никогда не будет вызываться для событий двумерной физики, таких как столкновения и т. Д. c.


Затем обратите внимание, что

Также коллайдер объекта, который должен быть Уничтожение - это "спусковой крючок" проверено

Это совершенно неверный способ. Если ваш объект должен отслеживать OnTriggerEnter, то у входящего ( игрока ) должна быть включена isTrigger! В большинстве случаев вы не хотите этого делать, потому что игрок должен, например, фактически сталкиваться с полом и не проваливаться сквозь него и т. Д. c.

Так что вам нужно будет скорее поставить дополнительный сценарий на Сам игрок, который ожидает ввода других триггерных объектов!

Затем, чтобы быть уверенным, либо построчно отлаживайте свой код , либо добавьте дополнительные журналы, чтобы увидеть, что происходит:

PowerUp

// put this on the pickup item
public class PowerUp : MonoBehaviour
{
    // Make these private, nobody else needs access to those
    // (Encapsulation)
    [SerializeField] private float multiplayer = 1.4f;
    [SerializeField] private GameObject pickupEffect;

    public void Pickup(HealthBar stats)
    {
        //Spawn a cool effect
        Instantiate(pickupEffect, transform.position, transform.rotation);
        //Apply effect to the player
        stats.health *= multiplayer;
        // Remove Effect
        Destroy(gameObject);
    }
}

PowerUpDetector (на плеере)

// put on player!
public class PowerUpDetector : MonoBehaviour
{
    // reference this via the Inspector
    [SerializeField] private HealthBar healthbar;

    private void Awake()
    {
        if(!healthBar) healthBar = GetComponent<HealthBar>();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        // or whatever tag your powerups have
        if (!other.CompareTag("PowerUp"))
        {
            Debug.LogWarning($"Registered a collision but with wrong tag: {other.tag}", this);
            return;
        }

        var powerup = other.GetComponent<PowerUp>();
        if(!powerup)
        {
            Debug.LogError($"Object {other.name} is tagged PowerUp but has no PowerUp component attached", this); 
            return;
        }

        Debug.Log("Found powerup, pick it up!", this);
        powerup.Pickup(healthbar);
    }
}

Ну, а то, что вы делаете, это только изменяя значение float

stats.health *= multiplayer;

, но вы никогда не обновите GUI соответственно, как это было бы при использовании

stats.SetHealth(stats.health * multiplayer)

(Кстати: я думаю, вы имеете в виду multiplier ;))


Я бы предложил реализовать свойство , например, например

public class HealthBar : MonoBehaviour
{
    // Make these private, nobody else needs access to those
    // (Encapsulation)
    [SerializeField] private Slider slider;
    [SerializeField] private Gradient gradient;
    [SerializeField] private Image fill; 
    [SerializeField] private float health = 100;

    public float Health 
    { 
        get { return health; }
        set 
        {
            health = value;
            slider.value = health;
            fill.color = gradient.Evaluate(slider.normalizedValue);
        }
    } 

    // be careful with variable names if you have this name already 
    // for a class field .. was ok this time but might get confusing
    public void SetMaxHealth(int value)
    {
        slider.maxValue = value; 
        // The property handles the rest anyway
        Health = value;
    }
}

, поэтому теперь вместо вызова SetHealth вы просто назначаете новый значение Health, и его установщик также автоматически запускается, поэтому ваш GUI обновляется.

public void Pickup(HealthBar stats)
{
    //Spawn a cool effect
    Instantiate(pickupEffect, transform.position, transform.rotation);
    //Apply effect to the player
    stats.Health *= multiplayer;

    Destroy(gameObject);
}
0 голосов
/ 19 марта 2020

Ваши предложения ниже,

  • игрок получит большее время жизни
  • Также коллайдер объекта, который нужно уничтожить

В какой ситуации возможно, у вас может быть

    1. Проверьте, что ваш персонаж запущен, поэтому он вызывает 'OnTriggerEnter', а также проверьте тег.
  • Проверьте элемент powerUp, который проверил true как триггер, 'isTrigger' enter image description here
  • Проверьте, является ли масштаб коллайдера или объекта попадания крошечным, он не будет работать с коллайдером.
  • Если у вас ничего нет с вышеуказанным контрольным списком, значит, он должен работать
...