Bir maksimum değeri aşmadan bir değişkeni nasıl artırabilirim?


89

Okul için basit bir video oyun programı üzerinde çalışıyorum ve bu yöntem çağrılırsa oyuncunun 15 sağlık puanı alacağı bir yöntem geliştirdim. Sağlığı maksimum 100'de tutmalıyım ve bu noktada sınırlı programlama yeteneğimle böyle bir şey yapıyorum.

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

Sözdizimimin mükemmel olmadığını anlıyorum ama sorum şu: Bunu yapmanın daha iyi bir yolu ne olabilir, çünkü hasar puanlarıyla da benzer bir şey yapmalı ve 0'ın altına düşmemeliyim.

Buna doygunluk aritmetiği denir .


7
Yan not olarak, bu yöntem için farklı bir isim seçerdim. Java standardına (ve bildiğim diğer dillerin çoğuna) göre, "get" ile başlayan bir yöntem adı bir değer döndürmeli ve hiçbir şeyi değiştirmemelidir. Benzer şekilde, "set" ile başlayan yöntem isimleri bir değeri değiştirmeli ve genellikle hiçbir şey döndürmemelidir.
Darrel Hoffman

Yanıtlar:


226

Ben sadece bunu yapardım. Temel olarak 100 (maksimum sağlık) ile 15 ekstra puanla sağlığın ne olacağı arasındaki minimum değeri alır. Kullanıcının sağlığının 100'ü geçmemesini sağlar.

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

Hitpoints sıfırın altına düşmediği emin olmak için, benzer bir işlevi kullanabilirsiniz: Math.max.

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

71

sadece sağlığa 15 ekleyin, yani:

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

Bununla birlikte, mülayim bir şekilde belirttiği gibi, bazen çoklu iş parçacığı (aynı anda çalıştırılan birden fazla kod bloğu) ile sağlığın herhangi bir noktada 100'ün üzerine çıkması sorunlara neden olabilir ve sağlık özelliğini birden çok kez değiştirmek de kötü olabilir. Bu durumda, diğer cevaplarda da belirtildiği gibi bunu yapabilirsiniz.

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

9
Asla geçmesine izin vermemelidir, bu, karakter sağlığının en fazla tanımlanan sağlık maksimum (100) olduğu varsayıldığı bir yarış durumu gibi yeni sorunlar ortaya çıkarabilir. Tahminimce bu seviyedeki proje için pek olası değil ama iyi uygulamaları erken uygulamaya koymalıyım.
mülayim

6
@bland Bu yaklaşımı kullanacak olsaydınız, böyle bir yarış durumundan kaçınmanın bir yolu, yeni sağlık değerini depolamak için geçici bir değişken kullanmak ve ardından gerekirse senkronizasyon ile bu yeni sağlık değerine sağlığı tek bir yerde ayarlamak olacaktır.
Bob

13
@bland: Yarış koşulları yalnızca çoklu iş parçacığı ile ilgilidir. Ve eğer çoklu iş parçacığı yapıyorsa (şüpheliyim ki) , çözüm tüm erişimleri kilitlemek healthveya healthyalnızca bir iş parçacığından erişildiğinden emin olmak olacaktır . "Sağlığın 100'ün üzerine çıkmasına asla izin vermemeli" kısıtlaması gerçekçi değildir.
BlueRaja - Dany Pflughoeft

@ BlueRaja-DannyPflughoeft Bu proje için pek olası olmadığını belirttim. Genel olarak, kilitler her zaman kullanımda olmayacaktır ve eğer maksimum bir değere sahipseniz, o zaman buna kesinlikle uyulmalıdır, oyun oynamaya veya başka türlü. Örnek: Bir olay, bir özelliğin değişikliğine bağlıysa ve yüzde kullanıyorsa, artık bu işlemeyi büyük ölçüde çarpıtmış olursunuz ve aynı zamanda onu iki kez çağırırsınız. Burada genel kalmaya ve OP'nin öğrenmesini sağlamaya çalışıyorum - bu cevabın bir öğrenci için çok dar ve spesifik olduğunu düşünüyorum çünkü onu büyük resmi düşünmemeye zorlayacak.
mülayim

@ Bob bence bu kadar basit bir şey için gereksiz.
Math chiller

45

intYukarıdakilerin her biri için ayrı bir vakaya ihtiyacınız yoktur 85. Sadece bir tane alın else, böylece sağlık zaten 86veya daha yüksekse, o zaman doğrudan olarak ayarlayın 100.

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

25
Benim için biraz fazla sihirli sayı (100'e izin verildiği düşünülse bile) - 15'i 16'ya değiştirirken 85'in ayarlanması gerekir. 85'i en azından 100 - 15(veya 100 -HEALED_HEALTH) olarak değiştirmek bir gelişme olmaz mı?
Maciej Piechotka

37

Bence bunu yapmanın deyimsel, nesne yönelimli bir yolu setHealth, Charactersınıfta bir fikir sahibi olmaktır . Bu yöntemin uygulanması şöyle görünecektir:

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

Bu, ne ayarladığınızdan bağımsız olarak, sağlığın 0'ın altına veya 100'ün üzerine çıkmasını önler.


Sizin getHealed()uygulaması sadece bu olabilir:

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

CharacterBir getHealed()yönteme sahip olmanın mantıklı olup olmadığı , okuyucuya bırakılmış bir alıştırmadır :)


5
+1: Bu, bunu nesne odaklı yapmanın harika bir yolu! Önerebileceğim tek şey (ve bu muhtemelen okuyucuya bırakılacaktır), muhtemelen her biri sizin yönteminizi çağıran iki yönteme ( heal(int hp)ve damage(int hp)) sahip olmaktır setHealth(int newValue).
Chris Forrence

18
Kitaplık işlevlerini çağırmanın nesi yanlış? Adlandırılmış işlevler olarak, amacı bir grup koşullu mantıktan daha açık bir şekilde ifade ederler.
erickson

2
Ayrıca birçok kütüphane işlevi (ve büyük olasılıkla bunlar) gerçekten yerleşiktir ve herhangi bir arama yapmaz.
kriss

2
@Matteo Yanlış cevap - büyük olasılıkla kütüphane işlevi dahili olarak tamamen aynı şeyi yapıyor, öyleyse neden kendinizi tekrar edip kodunuzu kirletiyorsunuz? Kitaplık işlevlerinin KULLANILMAMASI, DRY'nin temel ilkelerini takip etmez.
NickG

2
@Matteo bu bir if. Bu, kendinizi ayağınızdan vurabilmenizi engellemek içindir. Çok ayrıntılıysa, statik içe aktarmaları kullanın. Öyleyse şuna benziyor: health = max(0, min(100, newValue)) Bu hala sizin için okunamıyorsa clamp, satırın aşağıdaki gibi görünmesi için onu bir yönteme çıkartın :health = clamp(0, 100, newValue)
Daniel Kaplan

14

Ben sadece daha yeniden kullanılabilir bir kod dilimi sunacağım, bu en küçük değil ama onu herhangi bir miktarda kullanabilirsiniz, bu yüzden hala söylenmeye değer

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

Yaptığınız oyuna istatistik eklemek istiyorsanız 100'ü bir maxHealth değişkenine de değiştirebilirsiniz, böylece tüm yöntem bunun gibi olabilir.

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

DÜZENLE

Ek bilgi için

Aynı şeyi oyuncu hasar aldığında da yapabilirsiniz, ancak minHealth'e ihtiyacınız olmaz çünkü bu zaten 0 olurdu. Bu şekilde yapmak, aynı kodla herhangi bir miktara zarar verebilir ve iyileştirebilirsiniz.


1
minHealthnegatif olabilir, örneğin, D&D ... :)
JYelton

1
Açık ara en iyi cevap burada.
Acil Durum Desire

@JYelton, evet, if ifadesinde (sağlık <= 0) diyeceksin. İstediğin gibi halledebilirsin, eğer hayatlarının sadece lifeCount'tan 1 eksi olarak yaşamalarını istiyorsan ya da sadece kaybederlerse bunu halledebilir. İsteseydin, yeni hayatlarına sahip oldukları -HP miktarıyla başlamalarını bile sağlayabilirsin. Bu kodu hemen hemen her yere yapıştırabilirsiniz ve işi gayet iyi yapacaktır, bu cevabın amacı buydu.
5tar-Kaster

10
health = health < 85 ? health + 15 : 100;

4

Bir yardımcı sınıfta statik bir yöntem yapardım. Bu şekilde, bazı sınırlara sığması gereken her değer için kodu tekrarlamak yerine, tek bir çok amaçlı yönteme sahip olabilirsiniz. Min ve maks tanımlayan iki değer ve bu aralık içinde kenetlenecek üçüncü bir değer kabul eder.

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

Durumunuz için minimum ve maksimum sağlığınızı bir yerde beyan edersiniz.

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

Ardından min, maks ve ayarlanmış sağlığınızda geçen işlevi çağırın.

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

3

Bunun bir okul projesi olduğunu biliyorum, ancak oyununuzu daha sonra genişletmek ve iyileştirme gücünüzü yükseltmek istiyorsanız, işlevi şu şekilde yazın:

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

ve işlevi çağırın:

getHealed(15);
getHealed(25);

...vb...

Ayrıca işleve yerel olmayan bir değişken oluşturarak maksimum HP'nizi oluşturabilirsiniz. Hangi dili kullandığınızı bilmediğim için, yanlış sözdizimine sahip olabileceğinden bir örnek göstermeyeceğim.


2

Belki bu?

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

2

Küstah olmak ve kodunuzu bir satıra sığdırmak istiyorsanız, üçlü bir operatör kullanabilirsiniz :

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

Bazı kişilerin bu sözdizimine (muhtemelen) kötü okunabilirlik nedeniyle kaşlarını çatacağını unutmayın!


4
health = (health <= 85)?(health+15):100Daha okunaklı buluyorum (eğer gerçekten üçlü bir operatör kullanmak istiyorsanız)
Matteo

1

Bunun işe yarayacağına inanıyorum

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

Açıklama:

  • İyileşme için boşluk 15 veya daha az ise, sağlık 100 olacaktır.

  • Aksi takdirde boşluk 15'ten büyükse sağlığa 15 ekler.

Örneğin, sağlık 83 ise 98 olur ama 100 olmaz.


İstekte bulunan kişinin sorusunu çözmek için bunun nasıl çalışacağını genişletebilir misiniz?
Ro Yo Mi

İyileşme için boşluk 15 veya daha az ise sağlık 100 olur, eğer boşluk 15'ten büyükse sağlığa 15 ekler. Yani Örnek için sağlık 83 olacak, ancak 100 olmayacak. Herhangi bir endişeniz varsa lütfen bana bildirin, yorumunuz için teşekkür ederim.
MarmiK

&& health < 100Koşul gereksizdir. 100 ise 100 olacak, değişiklik olmayacak. Buna ihtiyaç duymanızın tek nedeni, bir şekilde 100'den fazla almanın mümkün olması ve iyileşmenin sizi 100'e düşürmesini istemememizdir.
Darrel Hoffman

@DarrelHoffman Bence oyun ekstra sağlık 100+ sağlamıyorsa haklısın, o zaman haklısın, cevabımı düzelttim :) teşekkür ederim
MarmiK

1

İş parçacığı güvenli olmak istersem, senkronize bir blok kullanmak yerine bunu bu şekilde yapardım.

Atomic CompareAndSet, ek yük olmadan senkronize edilmiş olarak aynı sonucu elde eder.

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

1

Modül operatörünü kullanmanın en basit yolu.

sağlık = (sağlık + 50)% 100;

sağlık hiçbir zaman 100'e eşit veya 100'ü aşmayacaktır.


Ama bu operasyonu health100 yaşındayken yaparsanız, 50 sağlıkla bitirirsiniz.
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;
    }

fonksiyon yapacaksanız, en azından 15'i bir parametre yapmalısınız :)
Ürdün

@Jordan: Kodu yazdığım içeriğe bağlı. :-)
koltuk altımı öp
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.