Jump to content
Unity Insider Forum

Enemy Healthbar


BlackDullah

Recommended Posts

Hallo liebe Community,

wieder mal habe ich etliche Tutorials durchprobiert und stehe vor einem Problem.

Vielleicht kann mir ja einer helfen.

 

Ich bin an meinem ersten Spiel dran und habe nun einen Gegner. Der Mechanismus des Gegners funktioniert soweit schon. Ich kann ihn eliminieren, und er mich.

Jedoch brauche ich 10 Schüsse, damit er vernichtet wird. Das ganze soll ja nicht nach einem Treffer schon erledigt sein.

Das alles funktioniert bereits. 

 

Nun möchte ich eine Healthbar anzeigen lassen, die dem Spieler auch anzeigt, wie weit er schon gekommen ist.

Das ganze soll wie folgt aussehen: -> Screenshot 1

Die Anzeige soll erst erscheinen, wenn <spacebossCurrentHealth> kleiner ist als <spacebossMaxHealth>.

 

Ich weiß nicht ob die Methode für mein Healthsystem generell die beste ist. Es ist alles aus verschiedenen Tutorials.

Zu der ganzen Prozedur habe ich 4 Skripte:

SpacebossController:

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

public class SpacebossController : MonoBehaviour

    
{
    public GameObject spacebosslaserPrefab;
    public int damageToGive;
    float speed = 5;
    private Vector3 startPos;
    private Vector3 newPos;
    

    private void Start()
    {
        //speed = Random.Range(1, 3);
        startPos = transform.position;
        InvokeRepeating("shotlaser", 1, 1f);
    }

 /*   private void OnCollisionEnter2D(Collision2D collision)

{
    if (collision.gameObject.tag == "Laser")
    {
        Destroy(collision.gameObject);
        Destroy(gameObject);
    }

}
 */
   
    void shotlaser()
    {
        transform.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
        GameObject laser = Instantiate(spacebosslaserPrefab);
        laser.transform.position = transform.position + new Vector3(0, 1, 0);
    }

    // Update is called once per frame
    void Update()
    {
        //transform.position -= new Vector3(speed, 0, 0) * Time.deltaTime;
        newPos = startPos;
        newPos.x = newPos.x + Mathf.PingPong(Time.time * speed, 10) -5;

        transform.position = newPos;
    }
}

HurtSpaceboss:

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

public class HurtSpaceboss : MonoBehaviour
{

    public int damageToGive = 1;
    public GameObject spacebossDamageBurst;

    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if(other.gameObject.tag == "Spaceboss")
        {
            other.gameObject.GetComponent<SpacebossHealthSystem>().HurtSpaceboss(damageToGive);
            Instantiate (spacebossDamageBurst, transform.position, transform.rotation);
        }
    }


}

 

SpacebossHealthSystem:

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


public class SpacebossHealthSystem : MonoBehaviour
{
    public int spacebossMaxHealth;
    public int spacebossCurrentHealth;

    public SpacebossHealthBar spacebosshealthbar;

    void Start()
    {
        spacebossCurrentHealth = spacebossMaxHealth;
        spacebosshealthbar.SetMaxHealth(spacebossMaxHealth);
    }

    void Update()
    {
        if(spacebossCurrentHealth <= 0)
        {
            Destroy(gameObject);
        }
    }

    public void HurtSpaceboss(int damageToGive)
    {
        spacebossCurrentHealth -= damageToGive;

        spacebosshealthbar.SetHealth(spacebossCurrentHealth);
    }

    public void SetMaxHealth()
    {
        //wieder zurücksetzen
        spacebossCurrentHealth = spacebossMaxHealth;
    }

}

SpacebossHealthBar:

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


public class SpacebossHealthBar : MonoBehaviour

{

    public Slider slider;
    public Gradient gradient;
    public Image fill;

    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);
    }

    //internal static void SetHealth(int spacebossCurrentHealth)
   // {
      //  throw new NotImplementedException();
    //}
}

 

Ich hoffe es ist übersichtlich und nicht zu durcheinander.

Also in erster Linie geht es mir darum, dass die HealthBar für den "Spaceboss" korrekt angezeigt wird.

Falls sich wirklich jemand die Mühe macht sich da durch zu wurschteln, bin ich gerne bereit Kritik und Verbesserungsvorschläge für meine Programmierung anzunehmen.

Vielleicht kann man manche Sachen auch in einem Skript - oder einfacher zusammenführen..

 

 

Nun denn, ich denke es ist eine leicht zu beantwortende Frage, die kompliziert gestellt ist :D

 

 

 

 

 

 

 

 

 

screenshot1.PNG

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich bin nicht sicher das ich es richtig verstehe, aber ich würde die Leiste einfach unsichtbar schalten.

 if (spacebossCurrentHealth < spacebossMaxHealth)
        {
            spacebosshealthbar.enabled = true;
        }
        else
        {
            spacebosshealthbar.enabled = false;
        }

Also so würde die Gesundheitsanzeige angezeigt wenn die Gesundheit unter Max Leben ist.

Aber ich würde das Persönlich nicht so machen, da die Gesundheit ja erst angezeigt wird, wenn du ihn angeschossen und getroffen hast.

Der Boss Spawnt ja sicherlich irgendwann. Dann einfach die Lebensanzeige mit anzeigen lassen. Oder wenn du in seine Nähe kommst wäre sicher das beste.

Habt dein Code nur überlesen, aber hab glaube irgendwas mit Range gelesen. Also Abstand zum Boss schaltet die Gesundheitsanzeige an.

Aber Kaffeebecher gegen Raumschiff cool.

Hoffentlich ist das ein Kaffeebecher:rolleyes:

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo,

erstmal vielen Dank für deine Antwort.

Nein, das was du mit Range gelesen hast ist was anderes.

Das Problem ist, dass die Anzeige (Healthbar) nicht funktioniert. Sie wird angezeigt, aber funktioniert nicht..

 

Ich weiß, dass es mit meinem Code wahrscheinlich schwer ist den Überblick zu bewahren.. ich muss wohl noch weiter rumprobieren :D

 

Und ja, es ist ein Kaffeebecher :D Die Grafiken sind noch nicht final, aber der Becher wird bleiben..

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ist wirklich schwer den Überblick zu bekommen.

Was kommt den bei den Variablen an bzw. wird die Funktion ausgeführt?

 spacebossCurrentHealth -= damageToGive;

Versuch mal mit Debug.Log(spacebossCurrentHealth); usw. die Werte in der Console anzeigen zu lassen. Aber sollte in Update abgefragt werden um veränderungen zu sehen.

Oder

zu schauen, ob die Funktion aufgerufen wird z.b. mit Debug.Log("getroffen"); in die Funktion reinschreiben, dann siehst du, ob die Funktion überhaupt

aufgerufen wird.

Link zu diesem Kommentar
Auf anderen Seiten teilen

  • 2 weeks later...

Also die Health Funktion des Bosses funktioniert. Er muss genau X mal getroffen werden, damit er eliminiert wird (anders wie bei den Kometen). Ich kann auch einsehen, wie viele "Leben" er noch hat. Das ist zum Glück nicht das Problem.

 

Ich kriege es nur nicht hin, das Ganze in einer Lebensanzeige (Healthbar) darzustellen.

 

Wobei die Healthbar ja dargestellt wird, aber sich nicht verändert. 

Link zu diesem Kommentar
Auf anderen Seiten teilen

So wie ich das sehe musst du einfach rausfinden wie viel Prozent dein Boss als Leben hat und das als float darstellen.
Also caste sowohl das currentHealth als auch das maxHealth auf float und Teile das currentHealth durch maxHealth.
Dann setzt du den Fill Amount deines Images auf den Wert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also warum du einen Slider verwendest hmmm....?

Also ich hab ein Image verwendet 


 public Image imgGesundheitsanzeige;
    public static float PlayerGesundheit = 0.0f;

    void Update()
    {
        fctGesundheitsanzeige();

    }

    void fctGesundheitsanzeige()
    {
        if (PlayerGesundheit <= 1.0f)
        {
            PlayerGesundheit = PlayerGesundheit + 0.001f;
        }

        imgGesundheitsanzeige.fillAmount = PlayerGesundheit;
     }

Hab aus Testzwecken einfach mal die Variable in kleinen Schritten Pro Frame erhöht.

Ich denke noch immer, das du deine Funktion nicht in Update hast und somit nur einmal statt öfters Aktualisiert wird.

Link zu diesem Kommentar
Auf anderen Seiten teilen

.....warum erhöht sich die Gesundheit um 0.001 jeden Frame??

@BlackDullah In deiner Situation gibt es mehrere Möglichkeiten. Die meiner Meinung nach beste mit ScriptableObjects wird hier erläutert. Sehr guter Talk. Ich hab das, was er da beschreibt, mal implenentiert und es ist mein erfolgreichstes Paket im Asset Store. Eine simple Version kann man sich aber auch so zusammenbauen. Damit werden deine beiden Komponenten (Health + Heath Bar, mehr braucht's nicht) extrem schlank und übersichtlich.

Wenn der Einstieg in die ScriptableObject-Lösung aber etwas zu komplex ist (kein Ding, ist halt einfach nicht gerade mehr Anfängerkram), dann tut's auch erstmal ein bisschen statisches Zeug. Man kann da ganz simpel eine statische int-Variable haben und eine Healthbar, die jeden Frame schaut, ob sich was geändert hat. Ist natürlich alles andere als elegant, den jeden Frame arbeiten zu lassen, obwohl in den allermeisten Frames gar nichts passiert. Etwas schicker wird das direkt mit Events:

public static class Player
{
  public const int maxHealth = 100;
  private static int health;
  public static event Action<int> onHealthChanged = delegate{};
  
  public static void ApplyDamage(int amount)
  {
    health -= amount;
    onHealthChanged(health);
  }
}

Deine PlayerHealthbar kann dann so aussehen:

[RequireComponent(typeof(Image))]
public class PlayerHealthbar : MonoBehaviour
{
  private Image image;
  
  private void Awake()
  {
    image = GetComponent<Image>();
  }
  
  private void OnEnable()
  {
    Player.onHealthChanged += OnHealthChanged;
  }
  
  private void OnDisable()
  {
    Player.onHealthChanged -= OnHealthChanged;
  }
  
  private void OnHealthChanged(int newHealth)
  {
    image.fillAmount = newHealth / (float)Player.maxHealth;
  }
}

Sieht vielleicht auf den ersten Blick etwas lang aus, aber ist halt nur eine Zeile pro Methode. Wenn die Komponente aktiviert wird, fügt sie mit += eine Reaktion auf das Event beim Spieler hinzu, wenn sie deaktiviert wird trägt sie die Reaktion wieder aus.

Die Player-Klasse ruft in der letzten Zeile das Event mit dem neuen Health-Wert auf.

Wenn du jetzt keine ScriptableObjects benutzt, dann musst du entweder das gleiche nochmal für Boss.blub statt Player.blub coden oder evtl. ein bisschen Vererbung draufstreuen. Beides nicht optimal, aber in Ordnung, bis du dir ScriptableObjects ranholst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...