如何在不超过最大值的情况下递增变量?


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”开头的方法名称应更改一个值,通常不会返回任何内容。
Darrel Hoffman

Answers:


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

但是,正如bland所指出的那样,有时候在多线程(一次执行多个代码块)中,运行状况随时超过100 可能会引起问题,并且多次更改运行状况属性也可能很糟糕。在这种情况下,您可以执行此操作,如其他答案中所述。

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

9
永远不要让它过去,这可能会带来新的问题,例如种族状况,假定角色健康状况最多为已定义的健康状况最大值(100)。我猜不太可能针对此级别的项目,但应尽早实施良好实践。
平淡的

6
@bland如果要使用这种方法,避免这种竞争状况的一种方法是使用临时变量存储新的健康值,然后将健康设置为该新的健康值在一个地方,并在必要时进行同步。
Bob

13
@bland:竞争条件仅在多线程时才相关。而且,如果他正在执行多线程(我非常怀疑),解决方案将是锁定对的所有访问health,或者确保health仅从一个线程进行访问。限制条件“绝不允许健康值超过100”是不现实的。
BlueRaja-Danny Pflughoeft 2013年

@ BlueRaja-DannyPflughoeft我说这个项目不太可能。通常,锁不会一直使用,如果您有最大值,则应严格遵守游戏或其他规定。示例:如果一个事件与属性的更改相关联,并且使用百分比,那么您现在已经使该处理产生了巨大的偏差,并且调用了两次。我试图在这里保持一般性,以确保OP能够学习-我觉得这个答案虽然有效,但对于学生来说过于狭窄和具体,因为它将迫使他不去思考大局。
平淡的2013年

@Bob我认为这对于简单的事情是不必要的。
数学冷却器

45

您不需要为int上述每个单独的案例85。只需拥有一个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:这是一种以面向对象的方式执行此操作的好方法!我唯一建议的内容(可能留给读者)是可能有两个方法(heal(int hp)damage(int hp)),每个setHealth(int newValue)方法都调用您的方法。
克里斯·福伦斯

18
调用库函数有什么问题?作为命名函数,它们比一堆条件逻辑更清楚地表达意图。
erickson

2
而且,许多库函数(很可能是这些函数)是真正内置的,根本不会执行任何调用。
克里斯,

2
@Matteo错误的答案-最有可能的是库函数在内部执行完全相同的操作,所以为什么要重复自己并污染代码?不使用库函数不遵循DRY的基本原理。
NickG 2013年

2
@Matteo这不是要避免if。这是为了防止自己被脚击中。如果太冗长,只需使用静态导入即可。然后,它看起来像这样:health = max(0, min(100, newValue)) 如果您仍然不理解它,请将其提取到一个名为的方法中,clamp从而使该行看起来像这样:health = clamp(0, 100, newValue)
Daniel Kaplan 2013年

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 2013年

@JYelton,是的,您只需要在if语句中说(健康状况<= 0)。您可以按照自己的意愿进行处理,如果您希望他们拥有的生命只是从lifeCount减去1,或者只是他们平息了损失,那么它就可以解决。如果您愿意,甚至可以用他们拥有的-HP来使他们开始新的生活。您可以将此代码粘贴到几乎任何地方,这样就可以很好地完成工作,这就是答案的重点。
5tar-Kaster

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

4

我会在助手类中创建一个静态方法。这样,您可以拥有一个通用的方法,而不是为需要适合某些边界的每个值重复执行代码。它将接受两个定义最小值和最大值的值,以及第三个将被限制在该范围内的值。

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

如果您想要厚脸皮并且将代码放在一行上,则可以使用三元运算符

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 2013年

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。


但是,如果您在health100 时进行该操作,那么您的生命值将为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

@乔丹:这取决于我编写代码的上下文。:-)
亲吻我的腋窝
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.