Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

1

27.06.2017, 08:45

Unity - Zelda Herzcontainer nachbauen

Hallo,
ich würde gerne ein Healthsystem im Stil von Zelda nachbauen. Deshalb wollte ich dieses erstmal kopieren und hinterher verändern.

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
[SerializeField]
Image[] healthContainers; // 5 Herzcontainer

int currentHealth;
int maxHealth;
int healthPerHealthContainer = 4; // 1 Container = 4 Leben

private void Start()
{
    maxHealth = healthContainers.Length * healthPerHealthContainer; // maximale HP festlegen
    currentHealth = maxHealth;
    UpdateHealthBar();
}

public void ChangeHealth(int amount) // Geheilt werden oder Dmg bekommen
{
    currentHealth = Mathf.Clamp(currentHealth + amount, 0, maxHealth); // Die aktuellen Lebenspunkte dürfen nicht unter 0 fallen oder über die maxHealth kommen
    UpdateHealthBar();
}

 public void UpdateHealthBar() // Healthbar aktualisieren
{
    int healthContainerIndex = currentHealth / healthPerHealthContainer; // das aktuelle, zu verändernde, Herz ermitteln
    int healthContainerFillAmount = currentHealth % healthPerHealthContainer; // Die Füllmenge

    if (healthContainerFillAmount == 0)
    {
        if (currentHealth == healthContainers.Length) // volles Leben
        {
            healthContainers[healthContainerIndex - 1].fillAmount = 1;
            return;
        }

        if (healthContainerIndex > 0)
        {
            healthContainers[healthContainerIndex].fillAmount = 0;
            healthContainers[healthContainerIndex - 1].fillAmount = 1;
        }
        else // 0 Leben
        {
            healthContainers[healthContainerIndex].fillAmount = 0;
            return;
        }
    }

    healthContainers[healthContainerIndex].fillAmount = healthContainerFillAmount / (float)healthPerHealthContainer; // das jeweilige Herz befüllen
}


Das Ganze funktioniert auch schon .. fast. Bei 5 Herzcontainern mit jeweils 4 Leben pro Container starte ich also mit 20 Leben.

Ich erhalte eine out of Range Exception an der Stelle (Zeile 36)

C#-Quelltext

1
healthContainers[healthContainerIndex].fillAmount = 0;


das ist ja auch logisch, weil ich bei

C#-Quelltext

1
int healthContainerIndex = currentHealth / healthPerHealthContainer;


(20/4) die Zahl 5 erhalte, das Array einen Bereich von 0 bis 4 besitzt und somit 5 zu einem Fehler führt. Ich kann aber nicht

C#-Quelltext

1
healthContainers[healthContainerIndex - 1].fillAmount = 0;


schreiben, da ich ja sonst das vorherige Herz komplett leere. Hat jemand eine Idee, wo mein Denkfehler liegt?

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »Garzec« (27.06.2017, 09:52)


Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

2

27.06.2017, 10:11

Ich habe hier nochmal einen alternativen Code,

C#-Quelltext

1
2
3
4
5
6
7
        void UpdateHealthBar()
        {
            for (int i = 0; i < HealthContainers.Length; i++)
            {
                healthContainers[i].fillAmount = Mathf.Clamp01((float)currentHealth / healthPerHealthContainer - i);
            }
        }


Der befüllt immer wieder die Container komplett neu, der Code ist dafür aber kürzer und er tut zumindest beim Test, das, was er soll .. Dann nehme ich den wohl.

3

27.06.2017, 10:43

Du musst vorher eins vom gesamten Leben abziehen und dann durch die Anzahl pro Herz teilen. Musst dann aber auch prüfen, sodass bei null Leben kein Fehler entsteht.

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

4

28.06.2017, 16:09

Da das Thema bereits in Discord geklärt wurde..

Ich hätte dazu noch etwas. Die Technik ist fertig, ich kann Container hinzufügen, die Healthbar baut sich nur 1x zu beginn auf etc. etc. Die Berechnungen stimmen laut Debugger ebenfalls. Nun habe ich "nur noch" das Problem, dass die Container nicht bei den passend berechneten Koordinaten oben links erzeugt werden, sondern komplett unterhalb der Canvas. Hier mal ein kleiner Ausschnitt, wenn sich die Healthbar zu Beginn der Szene aufbaut:

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  private Transform healthBar = GameObject.FindGameObjectWithTag("HealthController").transform; // der Container für die "Herzen"

    private GameObject healthWrapperObject = Resources.Load("HealthContainer") as GameObject; // Das übergeordnete Hintergrundbild, das das eigentliche "Herz" beinhaltet

    private List<Image> healthContainers = new List<Image>(); // Liste aller "Herzen" für spätere Health Updates etc.

    private int maxHealth = 12;
    private int currentHealth;

    private int healthPerHealthContainer = 4; // 4 Leben pro "Herz"
    private int healthContainersPerRow = 5; // 5 "Herzen" pro Reihe

    private int healthContainerStartPositionX = 0; // Healthbar beginnt bei 0 auf x
    private int healthContainerStartPositionY = 0; // Healthbar beginnt bei 0 auf y

    private int healthContainerSpacingX = 10; // horizontaler Abstand
    private int healthContainerSpacingY = -10; // vertikaler Abstand

    private void Start()
    {
        currentHealth = maxHealth;
        InitializeHealthBar();
    }

    public void InitializeHealthBar()
    {
        int neededHealthContainers = maxHealth % healthPerHealthContainer == 0 ? maxHealth / healthPerHealthContainer : maxHealth / healthPerHealthContainer + 1; // Benötigte Container ermitteln
        int counter = 0; // Zählt die Herzen pro Reihe für den nächsten Umbruch
        int x = healthContainerStartPositionX; // Horizontale Position des Containers
        int y = healthContainerStartPositionY; // vertikale Position des Containers

        for (int i = 0; i < neededHealthContainers; i++)
        {
            counter++;

            if (counter >= healthContainersPerRow) // Umbruch nach 5 Herzen
            {
                x = healthContainerStartPositionX; // Wieder ganz links anfangen
                y += healthContainerSpacingY; // 1 Zeile tiefer
                counter = 0; // Zähler Reset
            }
            else
                x += healthContainerSpacingX; // nächsten Container weiterschieben

            Transform newHealthContainerTransform = Instantiate(healthWrapperObject, new Vector2(x, y), healthWrapperObject.transform.rotation).transform; // Das übergeordnete Hintergrundbild erzeugen
            newHealthContainerTransform.SetParent(healthBar); // Das übergeordnete Hintergrundbild der Healthbar hinzufügen
            healthContainers.Add(newHealthContainerTransform.GetChild(0).GetComponent<Image>()); // Das eigentliche Herz ermitteln und der Liste hinzufügen für weitere Aktionen
        }
    }


So, nun befinden sich die Herzen bei Spielstart unterhalb der Canvas (Bild). Beigefügt habe ich noch die Transform Einstellungen der Healthbar, des Herzen("HealthContainer" Container als Hintergrund) und des eigentlichen Herzen ("HealthFill"), also dem Bild, das sich verändert. Bei allen 3 Transform Einstellungen habe ich Strg+Shift+Alt gedrückt, also Position, Verankerung etc. gesetzt.

Der Healthbar soll der erzeugte HerzContainer (verankert oben links) hinzugefügt werden und diesem dann das Herzobjekt (stretch, soll genauso groß sein, wie der HerzContainer).

Innerhalb der Schleife im Code wird x und y korrekt berechnet, aber bei Spielstart haben sie auf der y-Achse dann eine falsche Position, also außerhalb der Canvas.

Ich hoffe, jemand hat eine Idee, was ich da am Code ändern muss, damit die Container oben links im Canvas liegen.
»Garzec« hat folgende Bilder angehängt:
  • Healthbar.png
  • HealthContainer.png
  • HealthObjekt.png
  • Ingame.png
  • Szene.png

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Garzec« (28.06.2017, 16:15)


Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

5

28.06.2017, 21:39

Ich habe jetzt verschiedene Möglichkeiten ausprobiert, die Container werden immer unter der Canvas erzeugt. egal ob mit Parent, ohne Parent oder sonst was.

Nachträglich kann ich im Inspektor aber ihre berechnete Position eingeben, das stimmt und funktioniert dann. Im Script kann ich aber nicht in der allerletzten Zeile sagen,

C#-Quelltext

1
containerTransform.position = new Vector2(x,y);


das wäre anscheinend wieder zu einfach, da bleibt der "Bug" noch bestehen ...

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

6

29.06.2017, 07:17

Ich habs gefixt bekommen. Lösung des Rätsels:

C#-Quelltext

1
newHealthContainerTransform.SetParent(healthBar);


ersetzen durch

C#-Quelltext

1
newHealthContainerTransform.SetParent(healthBar, false);


:thumbsup:

Werbeanzeige