最大値を超えずに変数をインクリメントするにはどうすればよいですか?


89

私は学校向けの簡単なビデオゲームプログラムに取り組んでおり、そのメソッドが呼び出された場合にプレイヤーが15ヘルスポイントを獲得するメソッドを作成しました。ヘルスを最大100に保つ必要があり、この時点で限られたプログラミング能力で、私はこのようなことをしています。

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

構文が完全ではないことは理解していますが、問題は、それを行うためのより良い方法は何ですか?損傷点についても同様のことを行い、0未満にならないようにする必要があるためです

これは飽和演算と呼ばれます。


7
補足として、このメソッドには別の名前を選択します。Java標準(および私が知っている他のほとんどの言語)では、「get」で始まるメソッド名は値を返し、何も変更しないでください。同様に、「set」で始まるメソッド名は値を変更し、通常は何も返しません。
ダレルホフマン

回答:


225

私はただこれをします。基本的に、最小値は100(最大ヘルス)と15の追加ポイントでのヘルスです。ユーザーの健康が100を超えないようにします。

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

ヒットポイントがゼロを下回らないようにするには、同様の関数を使用できますMath.max

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

71

ヘルスに15を追加するだけなので、

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

しかし、当たり障り述べたように、時々 (一度に実行されるコードの複数のブロック)をマルチスレッドとで100以上の健康行くを有する任意の点は問題を引き起こす可能性があり、および健康特性を変更する複数回も悪いことができます。その場合、他の回答で述べたように、これを行うことができます。

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

9
これを超えることが決して許されない場合、これは、キャラクターのヘルスが最大で定義されたヘルス最大(100)であると想定される競合状態などの新しい問題を引き起こす可能性があります。このレベルのプロジェクトではありそうもないことですが、早い段階で適切な実践を実施する必要があります。
穏やかな2013

6
@blandこのアプローチを使用する場合、このような競合状態を回避する方法は、一時的な変数を使用して新しいヘルス値を格納し、必要に応じて同期してこのヘルス値を1か所に設定することです。
ボブは

13
@bland:競合状態は、マルチスレッドの場合にのみ関係します。そして、もし彼がマルチスレッディングをしているなら(私はこれは非常に疑わしいです)、解決策はへのすべてのアクセスをロックhealthするか、またはhealth1つのスレッドからのみアクセスされることを確認することです。「ヘルスが100を超えることは絶対に許すべきではない」という制約は現実的ではありません。
BlueRaja-Danny Pflughoeft 2013

@ BlueRaja-DannyPflughoeft私はそれがこのプロジェクトにはありそうもないと述べました。一般に、ロックは常に使用されるとは限りません。最大値がある場合は、ゲームなどに厳密に準拠する必要があります。例:イベントがプロパティの変更に関連付けられており、パーセンテージを使用している場合は、その処理を大幅に歪め、2回呼び出すことになります。私はここで一般的であり、OPが確実に学習できるようにしています。この答えはうまくいきますが、生徒にとって全体像を考えないように強制するため、狭すぎて具体的ではないと感じます。
穏やかな2013

@ボブ私はこれがこのシンプルなものには不要だと思います。
数学チラー

45

int上記のそれぞれに個別のケースは必要ありません85。ちょうど1つを持っているelseので、健康がすでにある場合86高いか高い直接にに設定し100ます

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

25
マジックナンバーが少し多すぎます(許可されている100を考慮しても)。15から16に変更する場合、85を調整する必要があります。85を少なくとも100 - 15(または100 -HEALED_HEALTH)に変更しても、改善されませんか?
Maciej Piechotka 2013

37

これを行う慣用的なオブジェクト指向の方法はsetHealthCharacterクラスにを持つことだと思います。このメソッドの実装は次のようになります。

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

これにより、設定した値に関係なく、ヘルスが0未満または100を超えるのを防ぐことができます。


あなたのgetHealed()実装はこれだけにすることができます:

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

Character持っているのが理にかなっているかどうかのgetHealed()方法は、読者に任せる練習です:)


5
+1:これは、オブジェクト指向の方法でこれを行うのに最適な方法です!私が提案するかもしれない唯一のこと(そしておそらくこれは読者に委ねられるでしょう)は、それぞれがあなたのメソッドを呼び出す2つのメソッド(heal(int hp)damage(int hp))を持つsetHealth(int newValue)ことです。
Chris Forrence 2013

18
ライブラリ関数の呼び出しの何が問題になっていますか?名前付き関数として、それらは一連の条件付きロジックよりも意図をより明確に表現します。
エリクソン2013

2
また、多くのライブラリー関数(そしておそらくこれらの関数)は実際に組み込まれており、呼び出しをまったく実行しません。
クリス、2013

2
@マッテオ間違った答え-ライブラリ関数は内部的にまったく同じことをする可能性が高いので、なぜ自分自身を繰り返してコードを汚染するのですか?ライブラリ関数を使用しないことは、DRYの基本原則に従っていません。
NickG 2013

2
@Matteoこれはを避けるためではありませんif。これは、足元で自分を撃つことができないようにするためです。冗長すぎる場合は、静的インポートを使用してください。そして、それは次のようになります。health = max(0, min(100, newValue)) それはあなたにまだ読めないなら、名前のメソッドにそれを抽出しclamp、このようなラインに見えるように、:health = clamp(0, 100, newValue)
ダニエル・カプラン

14

私はより再利用可能なコードのスライスを提供するつもりです、それは最小ではありませんが、あなたはそれをどんな量で使用することもできるので、それはまだ言われる価値があります

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

作成したゲームに統計を追加する場合は、100をmaxHealth変数​​に変更することもできるため、メソッド全体は次のようになります。

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

編集

追加情報について

プレーヤーが破損した場合も同じようにできますが、minHealthは必要ないため、いずれにしても0になります。この方法でこれを行うと、同じコードで任意の量を損傷して修復することができます。


1
minHealthたとえば、D&Dなどでは負の値になる可能性があります... :)
JYelton 2013

1
ここで断然最良の答えです。
Glitch Desire

@JYelton、ええ、ifステートメントで(health <= 0)と言うだけです。あなたが好きなようにそれを処理することができます、彼らがあなたにlifeCountからマイナス1だけの寿命を持たせたい場合、または彼らが完全に負けた場合、それはそれを処理できます。もし望むなら、彼らが持っていた-HPの量で彼らに彼らの新しい人生を開始させることさえできるでしょう。このコードはどこにでも貼り付けることができ、うまく機能します。それがこの回答のポイントでした。
5tar-Kaster 2013


4

ヘルパークラスで静的メソッドを作成します。このように、いくつかの境界内に収まる必要があるすべての値に対してコードを繰り返すのではなく、1つの多目的メソッドを持つことができます。最小値と最大値を定義する2つの値と、その範囲内にクランプされる3番目の値を受け入れます。

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

あなたの場合、どこかにあなたの最小と最大の健康を宣言します。

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

次に、最小、最大、および調整されたヘルスを渡す関数を呼び出します。

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

3

私はこれが学校のプロジェクトであることを知っていますが、後でゲームを拡張して、ヒーリングパワーをアップグレードできるようにしたい場合は、次のように関数を記述します。

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

そして関数を呼び出します:

getHealed(15);
getHealed(25);

...等...

さらに、関数に対してローカルではない変数を作成することにより、最大HPを作成できます。使用している言語がわからないため、構文が間違っている可能性があるため、例を示しません。


2

多分これ?

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

2

生意気でコードを1行に収めたい場合は、三項演算子を使用できます。

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

(おそらく)読みやすさが悪いために、一部の人々はこの構文に不快感を抱くでしょう。


4
私はhealth = (health <= 85)?(health+15):100もっと読みやすいと思います(本当に三項演算子を使用したい場合)
Matteo

1

これでうまくいくと思います

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

説明:

  • ヒーリングのギャップが15以下の場合、ヘルスは100になります。

  • それ以外の場合、ギャップが15より大きいと、ヘルスが15増加します。

たとえば、ヘルスが83の場合、98になりますが、100ではありません。


これがリクエスタの質問を解決するためにどのように機能するかについて詳しく説明できますか?
Ro Yo Mi

回復のギャップが15以下の場合、ヘルスは100になり、ギャップが15より大きい場合、ヘルスは15増加します。たとえば、83の場合、ヘルスは98になりますが、100ではありません。具体的な懸念がある場合は、お知らせください。コメントをありがとうございます。
MarmiK 2013

&& health < 100条件は不要です。100の場合、100に設定され、変更されません。それは取得することが可能であったならば、あなたはそれを必要とするだろう唯一の理由は何とか> 100であり、我々は治癒が100まで戻ってあなたを減らすためにしたくない
ダレル・ホフマン

@DarrelHoffmanゲームが余分なヘルス100+を提供しない場合、あなたは正しいと思います。それからあなたは正しいです。私は私の答えを修正しました:)ありがとう
MarmiK

1

スレッドセーフにしたい場合は、同期ブロックを使用するのではなく、この方法を使用します。

アトミックcompareAndSetは、オーバーヘッドなしで同期されたのと同じ結果を実現します。

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

モジュラス演算子を使用する最も簡単な方法。

健康=(健康+ 50)%100;

ヘルスは100以下になることはありません。


しかし、あなたがその操作をするとき health 100の、ヘルスは50になります。
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;
    }

関数を作成する場合は、少なくとも15をパラメータにする必要があります:)
Jordan

@ジョーダン:私がコードを書いているコンテキストに依存します。:-)
私の脇の下にキス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.