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

30.08.2016, 18:48

Sprinten des Spielers über die Ausdauerleiste begrenzen

Hallo,
ich habe eine Ausdauerleiste in Unity gebastelt. Nun möchte ich, dass der Spieler bei 0 Ausdauer logischerweise auch nicht mehr sprinten kann. In meiner verwaltenden Klasse füllt und senkt eine Methode die Leiste

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
public void StaminaManager(bool isRunning)
    {
        bool running = isRunning;
        float changeStamina = 20 * Time.deltaTime;

        if (running)
        {
            stamina -= changeStamina;

            // Minimal 0 Ausdauer
            if (stamina < 0)
            {
                stamina = 0;
            }
        }
        else if (!running)
        {
            // Ausdauer auffüllen
            if (stamina < maxStamina)
            {
                stamina += changeStamina;
            }
        }

        // Aktualisierung der Ausdauerleiste
        UpdateStaminaBar();
    }


Dann habe ich noch eine Methode, die prüft, ob ich noch Ausdauer habe

C#-Quelltext

1
2
3
4
5
6
7
8
9
10
public bool StaminaLeft()
    {
        if(stamina == 0)
        {
            // Sprinten deaktivieren
            return false;
        }
        // Sprinten zulassen
        return true;
    }


In meinem SpielerScript rufe ich diese Methoden auf

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
private void Update()
    {

        float movementSpeed = walkspeed;
        bool isRunning = false;
        bool hasStamina = playerStamina.StaminaLeft();

        // Bodenprüfung
        if (characterController.isGrounded)
        {
            // Springen
            if (Input.GetButton("Jump"))
            {
                verticalVelocity = jumpPower;
            }

            // Sprinten
            if (Input.GetKey(KeyCode.LeftShift))
            {
                // Nur bei Bewegung möglich
                if (lastposition != transform.position)
                {
                    // Ausdauer vorhanden
                    if (hasStamina)
                    {
                        movementSpeed = runSpeed;
                        isRunning = true;
                    }
                }
            }
            lastposition = transform.position;
        }

        // Ausdauerleiste aktualisieren
        playerStamina.StaminaManager(isRunning);

        // Bewegen
        movementDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
        movementDirection = transform.TransformDirection(movementDirection) * movementSpeed;

        verticalVelocity -= gravity * Time.deltaTime;
        movementDirection.y = verticalVelocity;
        characterController.Move(movementDirection * Time.deltaTime);

    }


Per Debuggen wird durch die Prüfung, ob noch Ausdauer vorhanden ist, ein korrekter bool zurückgeliefert. Es müsste also bei der Bewegung liegen. Dort steht sprinten aber grundsätzlich auf false, NUR wenn sämtliche Bedingungen zutreffen, ist das Sprinten möglich. Durch die Update Methode wird, sobald man nicht mehr Shift gedrückt halt das Sprinten wieder resettet und unterbrochen.

Nun lautet meine Frage, wieso kann ich trotz 0 Ausdauer immer noch sprinten ? Sobald die Ausdauer auf 0 steht muss das Sprinten doch aufgrund der if-Bedingungen gar nicht mehr möglich sein? ?(

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

2

30.08.2016, 19:00

Wenn du schon den Debugger benutzt, warum verfolgst du dann nicht den ganzen Codepfad nach? Dann musst du doch sehen, warum er trotzdem bis zu der Stelle kommt, wo gesprintet wird.

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

3

30.08.2016, 19:09

Bei 0 Ausdauer und gedrückter Shifttaste geschieht dann ein permanenter Wechsel zwischen true und false.

C#-Quelltext

1
if(stamina < 3)


Kann ich aber logischerweise auch nicht nehmen weil er sonst nur bis 3 Ausdauer sprintet.

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

4

30.08.2016, 19:14

Da kannst du mit Fuzzylogic ran gehen. Musst es noch nicht mal unnötig komplex machen. Im Prinzip reicht es ja schon aus wenn du sagst du kannst die Ausdauer bis 0 verbrauchen, danach muss aber mindestens x Ausdauer aufgefüllt werden um erneut sprinten zu können. Eine andere Möglichkeit wäre die Ausdauer nicht aufzuladen solange die Taste zum sprinten gedrückt wird. Dann muss der Spieler erst los lassen bis er wieder los legen kann. Weiterhin ginge es auch eine Verzögerung einzubauen. Hat man die gesamte Ausdauer aufgebraucht dauert es x Sekunden bis sie sich wieder auflädt. Dadurch gibst du der ganzen Sache etwas mehr Taktik. Verbraucht man seine Ausdauer nie komplett kann man relativ zügig weiter springen und muss nicht warten. Am Ende kommt es aber drauf an wie du dein System gern hättest. Guck doch vielleicht mal wie es bei anderen Spielen gelöst ist. Du hast da ja sicherlich ein Vorbild für dein System. Spiel das noch mal an und versuch das Verhalten genauer zu analysieren.
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

5

30.08.2016, 19:25

@Schorsch: Das hat aber nichts mit Fuzzy Logic zu tun ;)

6

30.08.2016, 22:36

@Schorsch: Das hat aber nichts mit Fuzzy Logic zu tun ;)

Hystereseist hier das Richtige Stichwort
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

Schorsch

Supermoderator

Beiträge: 5 145

Wohnort: Wickede

Beruf: Softwareentwickler

  • Private Nachricht senden

7

31.08.2016, 15:18

@Schorsch: Das hat aber nichts mit Fuzzy Logic zu tun

Was Fuzzylogic eigentlich ist ist mir bewusst. Habe aber mal irgendwo ein Codebeispiel von Microsoft zum Thema XNA gesehen wo solch ein Konzept auch als Fuzzylogic bezeichnet wurde. Mir war nicht bewusst dass es dafür dann einen anderen Begriff gibt. Aber an sich deshalb mein Satz "musst es nicht mal unnötig komplex machen" eben weil ich dachte dieses Konzept fällt auch unter Fuzzylogic und ist quasi eine Art Vereinfachung. Wieder was gelernt :)
„Es ist doch so. Zwei und zwei macht irgendwas, und vier und vier macht irgendwas. Leider nicht dasselbe, dann wär's leicht.
Das ist aber auch schon höhere Mathematik.“

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

8

31.08.2016, 16:38

Den Vorschlag von Schorsch kann man durchaus umsetzen, nicht aber um das Vorhandene Problem zu lösen.

@Garzec:
Das Problem ist deine lokale isRunning Variable.

Abgesehen davon solltest du nicht den Ansatz wählen "Dem Spieler wird eine Ausdauerleiste angezeigt und abhängig davon ist es, ob er sprinten kann", sondern eher "Der Spieler hat einen Ausdauerwert, der vom Sprinten aufgebraucht wird und sich wieder aufladen muss. Dieser Wert wird im UI angezeigt." Der Unterschied ist, dass nicht aus dem Code, der die Ausdauer managed, auf das UI zugegriffen wird, sondern das UI die anzuzeigenden Werte abruft.

Ein paar andere Feinheiten sind:
Du speicherst den Wert eines Parameters (isRunning) in einer lokalen Variable (running), statt direkt darauf zuzugreifen.
Zur Bedingung if (Bedingung) gibt es einen sonst Fall else if (!Bedingung) mit unnötiger Bedingung.
Für die Ausdauer wird die Obergrenze nicht abgefragt. Insgesamt würde sich eine Property anbieten, um sicherzustellen, dass nach einer Zuweisung auch immer ein Wert innerhalb des gültigen Bereichs gespeichert wird (-> Mathf.Clamp).
Du solltest nicht auf bestimmte Tasten abfragen (Shift beim Sprinten), sondern in den Inputeinstellungen eine Achse dafür definieren und diese Abfragen.
Manche "magische Werte" bieten sich dazu an, im Editor angepasst zu werden (bspw. die Füllrate der Ausdauer). Eine Membervariable wäre entsprechend besser geeignet. Sollen diese nicht im Editor angepasst werden, wäre eine Konstante besser.
Die Auffüllgeschwindigkeit und der Sprintverbrauch sollten separate Werte sein. (Dies macht spätere Anpassungen wesentlich einfacher, bspw. wenn das Sprinten kurzzeitig einen geringeren Verbrauch haben soll.)
Vielleicht wäre es besser, wenn in jedem Frame die Ausduer sich auffüllt (bspw. 20/s wie bisher), beim Rennen aber ein größerer Ausdauerwert verbraucht wird (bspw. 40/s, wenn das gleiche Verhalten wie bisher beibehalten werden soll).
StaminaLeft kann in einen Einzeiler umgewandelt werden (return stamina > 0;). Weiterhin würde sich die Methode anbieten, in eine Property umgewandelt zu werden.
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Garzec

Alter Hase

  • »Garzec« ist der Autor dieses Themas

Beiträge: 693

Wohnort: Gießen

  • Private Nachricht senden

9

31.08.2016, 20:09

@Sacaldur

Vielen Dank für die ganzen Tipps unten. Habe alle umgesetzt, hat meinen Code viel schlanker gemacht, gerade unten der Einzeiler :)
Das wusste ich nämlich noch nicht das man auch eine Bedingung mit return steuern kann, auch wenn jetzt bestimmt kommt, dass es zu den Grundlagen gehört,
Aber ich mache das Ganze ja noch nicht so lange .. ;)

Wo ist denn das Problem bei der lokalen Variable? Ich setze sie doch jeden Frame auf false, und setze sie nur auf true, solange man das Sprinten durch eine Taste auslöst. Oder muss man so etwas in einer separaten Methode abhandeln und nicht im Update?

Sacaldur

Community-Fossil

Beiträge: 2 301

Wohnort: Berlin

Beruf: FIAE

  • Private Nachricht senden

10

31.08.2016, 20:26

[...], dass es zu den Grundlagen gehört, [...]
Ich würde es eher als eine Kombination von Grundlagen bezeichnen. ;)

Und noch eine Anmerkung: du speicherst den boolean, der bestimmt, ob noch Ausdauer verfügbar ist, in einer lokalen Variable (hasStamina) zwischen, verwendest diese aber nur 1 mal. Einerseits ist es häufig sinnvoll, Variablen so spät wie möglich anzulegen (in deinem Fall vor der Bedingung, in der die Variable verwendet wird), andererseits könntest du dir diese sparen, indem du den Methodenaufruf direkt in die Bedingung setzt, das Ergebnis also für die Bedingung verwendet wird.


[...], und setze sie nur auf true, solange man das Sprinten durch eine Taste auslöst.
Sicher? Schau nochmal genau auf die Bedingungen... (auf alle 3)
Spieleentwickler in Berlin? (Thema in diesem Forum)
---
Es ist ja keine Schande etwas falsch zu machen, als Programmierer tu ich das täglich, [...].

Werbeanzeige