ฉันจะเพิ่มตัวแปรโดยไม่ให้เกินค่าสูงสุดได้อย่างไร


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

คำตอบ:


227

ฉันจะทำสิ่งนี้ โดยทั่วไปจะใช้เวลาขั้นต่ำระหว่าง 100 (พลังชีวิตสูงสุด) และพลังชีวิตจะเป็นอย่างไรโดยมีคะแนนพิเศษ 15 คะแนน เพื่อให้แน่ใจว่าสุขภาพของผู้ใช้ไม่เกิน 100

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

เพื่อให้มั่นใจว่า hitpoints 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) ไม่น่าเป็นไปได้สำหรับโครงการระดับนี้ฉันคิดว่า แต่ควรบังคับใช้แนวทางปฏิบัติที่ดีตั้งแต่เนิ่นๆ
อ่อนโยน

6
@bland ถ้าใครจะใช้วิธีนี้วิธีหลีกเลี่ยงสภาวะการแข่งขันดังกล่าวคือการใช้ตัวแปรชั่วคราวเพื่อเก็บค่าพลังชีวิตใหม่จากนั้นตั้งค่าสุขภาพเป็นค่าพลังชีวิตใหม่นี้ในที่เดียวโดยการซิงโครไนซ์หากจำเป็น
Bob

13
@bland: เงื่อนไขการแข่งขันจะเกี่ยวข้องเมื่อมีการเชื่อมต่อแบบมัลติเธรดเท่านั้น และถ้าเขากำลังทำมัลติเธรด(ซึ่งฉันสงสัยอย่างมาก)วิธีแก้ปัญหาคือล็อคการเข้าถึงทั้งหมดhealthหรือเพื่อให้แน่ใจว่าhealthเข้าถึงได้จากเธรดเดียวเท่านั้น ข้อ จำกัด"ไม่ควรปล่อยให้สุขภาพเกิน 100"ไม่ใช่สิ่งที่เป็นจริง
BlueRaja - Danny Pflughoeft

@ BlueRaja-DannyPflughoeft ฉันบอกว่ามันไม่น่าเป็นไปได้สำหรับโครงการนี้ โดยทั่วไปแล้วการล็อคจะไม่ถูกใช้งานเสมอไปและหากคุณมีค่าสูงสุดก็ควรยึดติดกับการเล่นเกมหรืออย่างอื่นอย่างเคร่งครัด ตัวอย่าง: หากเหตุการณ์เชื่อมโยงกับการเปลี่ยนแปลงของคุณสมบัติและใช้เปอร์เซ็นต์ตอนนี้คุณได้บิดเบือนการประมวลผลนั้นอย่างมากและมีการเรียกใช้สองครั้ง ฉันพยายามทำตัวทั่วไปที่นี่และมั่นใจว่า OP เรียนรู้ - ฉันรู้สึกว่าคำตอบนี้มันแคบและเฉพาะเจาะจงเกินไปสำหรับนักเรียนเพราะมันจะบังคับให้เขาไม่คิดถึงภาพรวม
อ่อนโยน

@ Bob ฉันคิดว่ามันไม่จำเป็นสำหรับบางสิ่งที่เรียบง่ายนี้
Math chiller

45

คุณไม่จำเป็นต้องเป็นกรณีที่แยกต่างหากสำหรับแต่ละข้างต้นint 85เพียงแค่มีหนึ่งelseเพื่อที่ว่าถ้าสุขภาพที่มีอยู่แล้วหรือที่สูงขึ้นแล้วเพียงแค่ตั้งโดยตรงไปยัง86100

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

25
ตัวเลขเวทย์มนตร์มากเกินไปสำหรับฉัน (แม้จะพิจารณาถึง 100 ที่อนุญาต) - เมื่อเปลี่ยน 15 เป็น 16 จะต้องปรับ 85 จะไม่เปลี่ยน 85 เป็นอย่างน้อย100 - 15(หรือ100 -HEALED_HEALTH) เป็นการปรับปรุง?
Maciej Piechotka

37

ฉันคิดว่าวิธีการทำแบบนี้เชิงวัตถุเชิงสำนวนคือการมีsetHealthในCharacterชั้นเรียน การใช้งานวิธีนั้นจะมีลักษณะดังนี้:

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)วิธีเรียกว่าวิธีของคุณ
Chris Forrence

18
มีอะไรผิดปกติกับการเรียกฟังก์ชันไลบรารี ตามชื่อฟังก์ชันพวกเขาแสดงเจตนาชัดเจนกว่าตรรกะเงื่อนไขมากมาย
erickson

2
นอกจากนี้ยังมีฟังก์ชั่นไลบรารีจำนวนมาก (และเป็นไปได้มากว่าฟังก์ชันเหล่านี้) มีอยู่แล้วภายในและจะไม่ทำการโทร
kriss

2
@ แมทเทโอตอบผิด - ส่วนใหญ่แล้วฟังก์ชันไลบรารีจะทำสิ่งเดียวกันภายในทุกประการดังนั้นทำไมต้องทำซ้ำตัวเองและทำให้รหัสของคุณเป็นมลพิษ การไม่ใช้ฟังก์ชันห้องสมุดไม่เป็นไปตามหลักการพื้นฐานของ DRY
NickG

2
@Matteo นี่ไม่ใช่การหลีกเลี่ยงif. เป็นการป้องกันตัวเองไม่ให้ยิงโดนเท้าตัวเอง ถ้ามันละเอียดเกินไปให้ใช้การนำเข้าแบบคงที่ จากนั้นจะมีลักษณะดังนี้: health = max(0, min(100, newValue)) หากคุณยังไม่สามารถอ่านได้ให้แยกเป็นวิธีการที่มีชื่อclampเพื่อให้บรรทัดมีลักษณะดังนี้:health = clamp(0, 100, newValue)
Daniel Kaplan

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

1
คำตอบที่ดีที่สุดที่นี่
Glitch Desire

@JYelton ใช่คุณแค่พูด (สุขภาพ <= 0) ในคำสั่ง if คุณสามารถจัดการได้ตามที่คุณต้องการหากคุณต้องการให้พวกเขามีชีวิตคุณเพียงแค่ลบ 1 จาก lifeCount หรือเพียงแค่ถ้าพวกเขาแบนแพ้ก็สามารถจัดการได้ หากคุณต้องการคุณสามารถทำให้พวกเขาเริ่มชีวิตใหม่ได้ด้วยจำนวน -HP ที่พวกเขามี คุณสามารถวางรหัสนี้ได้ทุกที่และมันจะทำงานได้ดีนั่นคือประเด็นของคำตอบนี้
5tar-Kaster


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

หากคุณต้องการทำตัวหน้าด้านและพอดีกับโค้ดของคุณในบรรทัดเดียวคุณสามารถใช้ตัวดำเนินการที่เกี่ยวข้อง :

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

โปรดทราบว่าบางคนจะขมวดคิ้วกับไวยากรณ์นี้เนื่องจาก (เนื้อหา) การอ่านไม่ดี!


4
ฉันพบว่าhealth = (health <= 85)?(health+15):100สามารถอ่านได้มากขึ้น (หากคุณต้องการใช้ตัวดำเนินการ ternary)
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

&& health < 100สภาพที่ไม่จำเป็น ถ้าเป็น 100 จะกำหนดเป็น 100 ไม่มีการเปลี่ยนแปลง เหตุผลเดียวที่คุณต้องการก็คือถ้าเป็นไปได้ที่จะได้รับ> 100 อย่างใดอย่างหนึ่งและเราไม่ต้องการให้การรักษาลดลงเหลือ 100
Darrel Hoffman

@DarrelHoffman ฉันคิดว่าคุณพูดถูกถ้าเกมไม่ให้สุขภาพพิเศษ 100+ คุณพูดถูกฉันได้แก้ไขคำตอบของฉันแล้ว :) ขอบคุณ
MarmiK

1

ถ้าฉันต้องการให้เธรดปลอดภัยฉันจะทำด้วยวิธีนี้แทนที่จะใช้บล็อกที่ซิงโครไนซ์

atomic 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 เป็นพารามิเตอร์ :)
จอร์แดน

@ จอร์แดน: มันขึ้นอยู่กับบริบทที่ฉันเขียนโค้ด :-)
จูบรักแร้
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.