Wie kann ich eine Variable erhöhen, ohne einen Maximalwert zu überschreiten?

89

Ich arbeite an einem einfachen Videospielprogramm für die Schule und habe eine Methode erstellt, bei der der Spieler 15 Gesundheitspunkte erhält, wenn diese Methode aufgerufen wird. Ich muss die Gesundheit auf maximal 100 halten und mit meinen begrenzten Programmierfähigkeiten mache ich zu diesem Zeitpunkt so etwas.

public void getHealed(){
    if(health <= 85)
        health += 15;
    else if(health == 86)
        health += 14;
    else if(health == 87)
    health += 13; 
}// this would continue so that I would never go over 100

Ich verstehe, dass meine Syntax nicht perfekt ist, aber meine Frage ist, was ein besserer Weg ist, weil ich auch mit den Schadenspunkten etwas Ähnliches machen muss und nicht unter 0 gehe.

Dies nennt man Sättigungsarithmetik .

Steven Eck
quelle
7
Als Randnotiz würde ich einen anderen Namen für diese Methode wählen. Gemäß dem Java-Standard (und den meisten anderen mir bekannten Sprachen) sollte ein Methodenname, der mit "get" beginnt, einen Wert zurückgeben und nichts ändern. Ebenso sollten Methodennamen, die mit "set" beginnen, einen Wert ändern und normalerweise nichts zurückgeben.
Darrel Hoffman

Antworten:

224

Ich würde das einfach machen. Grundsätzlich beträgt das Minimum zwischen 100 (die maximale Gesundheit) und der Gesundheit mit 15 zusätzlichen Punkten. Es stellt sicher, dass der Gesundheitszustand des Benutzers 100 nicht überschreitet.

public void getHealed() {
    health = Math.min(health + 15, 100);
}

Um sicherzustellen, dass die Trefferpunkte nicht unter Null fallen, können Sie eine ähnliche Funktion verwenden : Math.max.

public void takeDamage(int damage) {
    if(damage > 0) {
        health = Math.max(health - damage, 0);
    }
}
Chris Forrence
quelle
71

Fügen Sie einfach 15 zur Gesundheit hinzu, also:

health += 15;
if(health > 100){
    health = 100;
}

Wie langweilig jedoch festgestellt hat, kann es bei Problemen mit Multithreading (mehrere gleichzeitig ausgeführte Codeblöcke) manchmal zu Problemen kommen, wenn der Zustand zu jedem Zeitpunkt über 100 liegt , und es kann auch schlecht sein, die Gesundheitseigenschaft mehrmals zu ändern. In diesem Fall können Sie dies tun, wie in anderen Antworten erwähnt.

if(health + 15 > 100) {
    health = 100;
} else {
    health += 15;
}
Jordanien
quelle
9
Sollte es niemals passieren, könnte dies zu neuen Problemen führen, wie zum Beispiel einer Rassenbedingung, bei der angenommen wird, dass die Charaktergesundheit höchstens das definierte Gesundheitsmaximum (100) beträgt. Für dieses Level-Projekt ist es unwahrscheinlich, aber ich sollte frühzeitig bewährte Verfahren durchsetzen.
milder
6
@bland Wenn Sie diesen Ansatz verwenden würden, besteht eine Möglichkeit, eine solche Racebedingung zu vermeiden, darin, eine temporäre Variable zum Speichern des neuen Integritätswerts zu verwenden und dann den Integritätswert an einer Stelle auf diesen neuen Integritätswert zu setzen und gegebenenfalls zu synchronisieren.
Bob
13
@bland: Die Rennbedingungen sind nur beim Multithreading relevant. Und wenn er Multithreading ausführt (was ich sehr bezweifle) , wäre die Lösung, alle Zugriffe auf zu sperren healthoder sicherzustellen, dass healthnur von einem Thread aus zugegriffen wird. Die Einschränkung "Sollte niemals zulassen, dass die Gesundheit über 100 steigt" ist nicht realistisch.
BlueRaja - Danny Pflughoeft
@ BlueRaja-DannyPflughoeft Ich sagte, es sei unwahrscheinlich für dieses Projekt. Im Allgemeinen werden Schlösser nicht immer verwendet. Wenn Sie einen Maximalwert haben, sollten Sie diese strikt einhalten, spielen oder auf andere Weise. Beispiel: Wenn ein Ereignis an eine Änderung einer Eigenschaft gebunden ist und den Prozentsatz verwendet, haben Sie diese Verarbeitung jetzt immens verzerrt und zweimal aufgerufen. Ich versuche, hier allgemein zu bleiben und sicherzustellen, dass OP lernt. Ich bin der Meinung, dass diese Antwort, obwohl sie funktioniert, für einen Studenten zu eng und spezifisch ist, da sie ihn dazu zwingt, nicht an das Gesamtbild zu denken.
langweilig
@ Bob Ich denke, das ist unnötig für etwas so Einfaches.
Math Chiller
45

Sie benötigen für jeden intoben genannten Fall keinen eigenen Fall 85. Haben Sie nur eine else, damit, wenn die Gesundheit bereits 86oder höher ist, stellen Sie sie einfach direkt auf 100.

if(health <= 85)
    health += 15;
else
    health = 100;
rgettman
quelle
25
Ein bisschen zu viele magische Zahlen für mich (selbst wenn man 100 erlaubt) - wenn man 15 auf 16 ändert, müssten die 85 angepasst werden. Wäre es nicht eine Verbesserung, 85 auf mindestens 100 - 15(oder 100 -HEALED_HEALTH) zu ändern ?
Maciej Piechotka
37

Ich denke , eine idiomatisch, objektorientierte Art und Weise , dies zu tun ein haben , ist setHealthauf der CharacterKlasse. Die Implementierung dieser Methode sieht folgendermaßen aus:

public void setHealth(int newValue) {
    health = Math.max(0, Math.min(100, newValue))
}

Dies verhindert, dass die Gesundheit unter 0 oder höher als 100 fällt, unabhängig davon, auf was Sie sie eingestellt haben.


Ihre getHealed()Implementierung kann einfach so sein:

public void getHealed() {
    setHealth(getHealth() + 15);
}

Ob es Sinn macht, Charactereine getHealed()Methode zu haben , ist eine Übung, die dem Leser überlassen bleibt :)

Daniel Kaplan
quelle
5
+1: Dies ist eine großartige Möglichkeit, dies objektorientiert zu tun! Das einzige, was ich vorschlagen könnte (und dies würde wahrscheinlich dem Leser überlassen bleiben), ist möglicherweise zwei Methoden ( heal(int hp)und damage(int hp)), die jeweils Ihre setHealth(int newValue)Methode aufrufen .
Chris Forrence
18
Was ist falsch daran, Bibliotheksfunktionen aufzurufen? Als benannte Funktionen drücken sie die Absicht klarer aus als eine Reihe von bedingten Logik.
Erickson
2
Auch viele Bibliotheksfunktionen (und sehr wahrscheinlich diese) sind wirklich integriert und führen überhaupt keinen Aufruf aus.
Kriss
2
@Matteo Falsche Antwort - höchstwahrscheinlich macht die Bibliotheksfunktion intern genau dasselbe. Warum sollten Sie sich also wiederholen und Ihren Code verschmutzen? Die NICHT-Verwendung von Bibliotheksfunktionen folgt nicht den Grundprinzipien von DRY.
NickG
2
@Matteo das ist nicht zu vermeiden if. Dies soll verhindern, dass Sie sich in den Fuß schießen können. Wenn es zu ausführlich ist, verwenden Sie einfach statische Importe. Dann sieht es so aus: health = max(0, min(100, newValue)) Wenn das für Sie immer noch nicht lesbar ist, extrahieren Sie es in eine Methode mit dem Namen, clampdamit die Zeile so aussieht:health = clamp(0, 100, newValue)
Daniel Kaplan
14

Ich werde nur ein wiederverwendbareres Stück Code anbieten, es ist nicht das kleinste, aber Sie können es mit jeder Menge verwenden, so dass es immer noch wert ist, gesagt zu werden

health += amountToHeal;
if (health >= 100) 
{ 
    health = 100;
}

Sie können die 100 auch in eine maxHealth-Variable ändern, wenn Sie dem von Ihnen erstellten Spiel Statistiken hinzufügen möchten. Die gesamte Methode könnte also ungefähr so ​​aussehen

private int maxHealth = 100;
public void heal(int amountToHeal)
{
    health += amountToHeal;
    if (health >= maxHealth) 
    { 
        health = maxHealth;
    }
}

BEARBEITEN

Für zusätzliche Informationen

Sie könnten das Gleiche tun, wenn der Spieler beschädigt wird, aber Sie würden keine minHealth benötigen, da dies sowieso 0 wäre. Wenn Sie dies auf diese Weise tun, können Sie alle Beträge mit demselben Code beschädigen und heilen.

5tar-Kaster
quelle
1
minHealthkönnte negativ sein, sagen wir zum Beispiel in D & D ... :)
JYelton
1
Mit Abstand die beste Antwort hier.
Glitch Desire
@JYelton, ja, du würdest einfach (Gesundheit <= 0) in der if-Anweisung sagen. Sie können damit umgehen, wie Sie wollen, wenn Sie möchten, dass sie Leben haben, die Sie nur minus 1 von lifeCount haben, oder wenn sie auf Anhieb verlieren, dann kann es damit umgehen. Wenn Sie wollten, könnten Sie sie sogar dazu bringen, ihr neues Leben mit der Menge an -HP zu beginnen, die sie hatten. Sie können diesen Code so ziemlich überall einfügen, und er macht den Job einwandfrei, das war der Punkt dieser Antwort.
5tar-Kaster
10
health = health < 85 ? health + 15 : 100;
Aroo
quelle
4

Ich würde eine statische Methode in einer Hilfsklasse machen. Auf diese Weise können Sie eine Allzweckmethode verwenden, anstatt Code für jeden Wert zu wiederholen, der in bestimmte Grenzen passen muss. Es würde zwei Werte akzeptieren, die min und max definieren, und einen dritten Wert, der innerhalb dieses Bereichs geklemmt werden soll.

class HelperClass
{
    // Some other methods

    public static int clamp( int min, int max, int value )
    {
        if( value > max )
            return max;
        else if( value < min )
            return min;
        else
            return value;
    }
}

Für Ihren Fall würden Sie irgendwo Ihre minimale und maximale Gesundheit angeben.

final int HealthMin = 0;
final int HealthMax = 100;

Rufen Sie dann die Funktion auf, die Ihre minimale, maximale und angepasste Gesundheit übergibt.

health = HelperClass.clamp( HealthMin, HealthMax, health + 15 );
MildWolfie
quelle
3

Ich weiß, dass dies ein Schulprojekt ist, aber wenn Sie Ihr Spiel später erweitern und Ihre Heilkraft verbessern möchten, schreiben Sie die Funktion wie folgt:

public void getHealed(healthPWR) {
    health = Math.min(health + healthPWR, 100);
}

und rufen Sie die Funktion auf:

getHealed(15);
getHealed(25);

...etc...

Darüber hinaus können Sie Ihre maximale HP erstellen, indem Sie eine Variable erstellen, die nicht lokal für die Funktion ist. Da ich nicht weiß, welche Sprache Sie verwenden, werde ich kein Beispiel zeigen, da es möglicherweise die falsche Syntax hat.

BlackBeltScripting
quelle
2

Vielleicht das?

public void getHealed()
{
  if (health <= 85)
  {
    health += 15;
  } else
  {
    health = 100;
  }
}
Juto
quelle
2

Wenn Sie frech sein und Ihren Code in eine Zeile einfügen möchten, können Sie einen ternären Operator verwenden :

health += (health <= 85) ? 15 : (100 - health);

Beachten Sie, dass einige Leute diese Syntax wegen (wohl) schlechter Lesbarkeit missbilligen werden!

Oleksiy
quelle
4
Ich finde health = (health <= 85)?(health+15):100besser lesbar (wenn Sie wirklich einen ternären Operator verwenden möchten)
Matteo
1

Ich glaube, das wird reichen

if (health >= 85) health = 100;
else health += 15;

Erläuterung:

  • Wenn die Heilungslücke 15 oder weniger beträgt, wird die Gesundheit 100.

  • Andernfalls erhöht sich die Gesundheit um 15, wenn die Lücke größer als 15 ist.

Zum Beispiel: Wenn die Gesundheit 83 ist, wird sie 98, aber nicht 100.

MarmiK
quelle
Können Sie erläutern, wie dies funktioniert, um die Frage des Anforderers zu lösen?
Ro Yo Mi
Wenn die Heilungslücke 15 oder weniger beträgt, wird die Gesundheit zu 100, wenn die Lücke größer als 15 ist, erhöht sich die Gesundheit um 15. Zum Beispiel wird der Gesundheitszustand 83 zu 98, aber nicht zu 100. Wenn Sie spezielle Bedenken haben, lassen Sie es mich bitte wissen, danke für Ihren Kommentar.
MarmiK
Die && health < 100Bedingung ist nicht erforderlich. Wenn es 100 ist, wird es auf 100 gesetzt, keine Änderung. Der einzige Grund, warum Sie das brauchen würden, wäre, wenn es möglich wäre, irgendwie> 100 zu bekommen, und wir wollen nicht, dass die Heilung Sie wieder auf 100 reduziert.
Darrel Hoffman
@DarrelHoffman Ich denke, Sie haben Recht, wenn das Spiel keine zusätzliche Gesundheit 100+ bietet, dann haben Sie Recht, ich habe meine Antwort korrigiert :) Danke
MarmiK
1

Wenn ich threadsicher sein wollte, würde ich dies auf diese Weise tun, anstatt einen synchronisierten Block zu verwenden.

Das atomare compareAndSet erzielt das gleiche Ergebnis wie das ohne Overhead synchronisierte.

AtomicInteger health = new AtomicInteger();

public void addHealth(int value)
{
    int original = 0;
    int newValue = 0;
    do
    {
        original = health.get();
        newValue = Math.min(100, original + value);
    }
    while (!health.compareAndSet(original, newValue));
}
Robert Sutton
quelle
1

Einfachste Methode mit dem Moduloperator.

Gesundheit = (Gesundheit + 50)% 100;

Gesundheit wird niemals 100 erreichen oder überschreiten.

Bindung
quelle
Aber wenn Sie diese Operation ausführen, wenn health100 ist, würden Sie mit 50 Gesundheit enden.
Parziphal
0
   private int health;
    public void Heal()
    {
        if (health > 85)
            health = 100;
        else
            health += 15;
    }
    public void Damage()
    {
        if (health < 15)
            health = 0;
        else
            health -= 15;
    }
Küss meine Achselhöhle
quelle
Wenn Sie Funktionen erstellen möchten, sollten Sie mindestens die 15 als Parameter festlegen :)
Jordan
@ Jordan: Es hängt vom Kontext ab, in dem ich den Code schreibe. :-)
küss meine Achselhöhle