มีอันตรายในการมีการวนลูปเกมหลักที่ควบคุมไม่ได้?


19

ฉันสงสัยว่ามีอันตรายใด ๆ ที่เป็นไปได้หรือไม่เมื่อลูปเกมของฉันทำงานเร็วเท่าที่ระบบอนุญาต

ขณะนี้ฉันมีลูปซึ่งโดยการวัดเวลาที่ผ่านไปในหน่วยนาโนวินาทีเรียกใช้ตรรกะของเกมและตรรกะการเรนเดอร์ด้วยความเร็วที่กำหนดไว้ล่วงหน้าโดยไม่มีปัญหา ในความเป็นจริงตรรกะใด ๆ ที่ฉันทำในการวนซ้ำนั้นถูกโอเวอร์คล็อกไปที่การโทรในแต่ละวินาที

การวนซ้ำตัวเองนั้นวิ่งได้เร็วเท่าที่มันชอบซึ่งมีประมาณ 11.7 ล้านลูปต่อวินาทีในเครื่องของฉัน

วน (pseudocode ง่าย):

while(!isGameOver){

 if(canPollInputs){
    pollInputs()
 }

 while(canStepLogic){
    stepLogic()
 }

 if(canRender){
    render()
 }
}

คำถามของฉันนั้นก็คือถ้าลูปแบบง่ายนั้นถ้ามันไม่ทำงานด้วยความเร็วที่ควบคุมสามารถทำอันตรายต่อระบบได้หรือไม่?

แก้ไข: นั่นหมายความว่าตรรกะของฉันทำงาน 30 ครั้งต่อวินาที (30 tps), เครื่องมือแสดงภาพของฉันทำงานที่ 60 fps, ฉันสำรวจสัญญาณอินพุต 100 ครั้งต่อวินาทีและยังมีตรรกะบางอย่างที่จะรับมือกับตรรกะหรือการแสดงผลนานกว่าที่คาดไว้ . แต่ห่วงไม่ได้ควบคุมปริมาณ

แก้ไข: การใช้Thread.sleep()เช่น Throttle การวนลูปหลักลงไปที่ 250 ลูปต่อวินาทีนำไปสู่การลดลง แต่ลูปทำงานที่ประมาณ 570 ลูปต่อวินาทีแทนที่จะเป็น 250 ที่ต้องการ (จะเพิ่มรหัสเมื่อฉันอยู่ที่เครื่องเดสก์ท็อปของฉัน .. )

แก้ไข: เราไปกันแล้ว java gameloop ที่ใช้งานได้เพื่อชี้แจงสิ่งต่างๆ อย่าลังเลที่จะใช้มัน แต่อย่าอ้างสิทธิ์ว่าเป็นของคุณ)

private void gameLoop() {

    // Time that must elapse before a new run
    double timePerPoll = 1000000000l / targetPPS;
    double timePerTick = 1000000000l / targetTPS;
    double timePerFrame = 1000000000l / targetFPS;
    int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);

    int achievedPPS = 0;
    int achievedFPS = 0;
    int achievedTPS = 0;

    long timer = TimeUtils.getMillis();

    int loops = 0;

    int achievedLoops = 0;

    long currTime = 0l;
    long loopTime = 0l;

    long accumulatorPPS = 0l;
    long accumulatorTPS = 0l;
    long accumulatorFPS = 0l;

    long lastTime = TimeUtils.getNano();

    while(!isRequestedToStop) {
        currTime = TimeUtils.getNano();
        loopTime = currTime - lastTime;
        lastTime = currTime;

        loops = 0;

        accumulatorPPS += loopTime;
        accumulatorTPS += loopTime;
        accumulatorFPS += loopTime;

        if(accumulatorPPS >= timePerPoll) {
            pollInputs();
            playerLogic();
            achievedPPS++;
            accumulatorPPS -= timePerPoll;
        }

        while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
            tick();
            achievedTPS++;
            accumulatorTPS -= timePerTick;
            loops++;
        }

        // Max 1 render per loop so player movement stays fluent
        if(accumulatorFPS >= timePerFrame) {
            render();
            achievedFPS++;
            accumulatorFPS -= timePerFrame;
        }

        if(TimeUtils.getDeltaMillis(timer) > 1000) {
            timer += 1000;
            logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
                    + achievedPPS + " Polls, " + achievedLoops + " Loops");
            achievedTPS = 0;
            achievedFPS = 0;
            achievedLoops = 0;
        }

        achievedLoops++;
    }
}

อย่างที่คุณเห็นว่าแทบจะไม่มีโค้ดที่ทำงานในแต่ละลูป แต่จะมีการเลือกบางอย่างตามจำนวนเวลาจริงที่ผ่านไป คำถามหมายถึง 'ห่วงผู้ปฏิบัติงาน' และมันมีผลต่อระบบอย่างไร


2
หน้าที่ 'แก้ไขการประทับเวลา' ลิงค์: gafferongames.com/game-physics/fix-your-timestepโปรดอ่าน นอกจากนี้โปรดทราบว่า Thread.Sleep () ไม่สามารถใช้ในการเร่งเวลาตามกำหนดเวลาของคุณได้อย่างน่าเชื่อถือเนื่องจากระบบปฏิบัติการไม่รับประกันว่าจะคืนการควบคุมแอปพลิเคชันของคุณหลังจากระยะเวลาที่ร้องขอ (อาจแตกต่างกัน)
รอยต.

ใช่นั่นเป็นปัญหาของรหัสเทียม ฉันทำสิ่งที่นักเขียนส่วนใหญ่เขียนเกี่ยวกับ (ขณะนี้กำลังใช้งานเดลต้าที่เสริมโครงสร้างลูปของฉัน) ถ้าฉันไม่สามารถใช้ Thread.sleep () แล้วมีอะไรอีกบ้างใน Java มาตรฐาน?
dot_Sp0T

1
คุณมักจะใช้วนรอบไม่ว่างกับ Thread.Sleep (0) และหวังว่าจะดีที่สุด Gaffer พูดถึงเรื่องนี้มากในบทความไม่กี่
รอยต.

นั่นเป็นสิ่งที่ฉันได้ทำไปแล้วโดยไม่ต้องใช้ thread.sleep (0) และสิ่งที่กระตุ้นคำถามนี้ในตอนแรก มีอันตรายใด ๆ ในการไม่ว่าง (resp ไม่ยุ่งเนื่องจากแม้แต่วงจรวนซ้ำที่ซ้ำซ้อนถูกบีบลง) สำหรับระบบ?
dot_Sp0T

ในขณะที่กลับมาบั๊กทำให้ Starcraft II ทำสิ่งนี้ภายใต้เงื่อนไขบางประการ ในที่สุดมันก็ละลาย GPU ตัวน้อย ใช่มันเป็นไปได้มากสำหรับการวนซ้ำเกมที่ไม่สามารถควบคุมได้ที่จะก่อให้เกิดอันตราย
Mason Wheeler

คำตอบ:


35

มันจะทำให้ซีพียูหนึ่งคอร์รันบน 100% เสมอ ซึ่งมักจะไม่ก่อให้เกิดอันตรายใด ๆต่อระบบ ซีพียูถูกออกแบบมาเพื่อทำงานบน 100% เป็นเวลาหลายชั่วโมง แต่บนอุปกรณ์มือถือจะทำให้แบตเตอรี่หมดเร็วและทำให้อุปกรณ์ร้อนขึ้นซึ่งจะทำให้คุณต้องเสียค่าใช้จ่ายเกี่ยวกับดวงดาวในการจัดอันดับร้านค้าของคุณ บนคอมพิวเตอร์เดสก์ท็อปปัญหานี้น้อยลง แต่จะกินกระแสไฟฟ้าของผู้ใช้มากขึ้นทำให้พัดลมซีพียูหมุนเร็วขึ้นซึ่งอาจทำให้เกิดเสียงดังและเสียรอบ CPU ซึ่งกระบวนการอื่นอาจถูกนำมาใช้ ในขณะที่สิ่งเหล่านี้ไม่ใช่ข้อบกพร่องที่สำคัญพวกเขายังคงมีสไตล์ที่ไม่ดีดังนั้นคุณควรหลีกเลี่ยงเมื่อเป็นไปได้

คุณไม่ได้พูดอะไรเกี่ยวกับวิธีการวนรอบเกมตรรกะของคุณทำงานภายใน แต่เมื่อคุณใช้วิธีเดลต้าเวลา (การคำนวณแต่ละครั้งที่คุณทำต้องใช้เวลาตั้งแต่การโทรครั้งสุดท้ายเข้าบัญชี) คุณกำลังจัดการกับเดลต้าขนาดเล็กมาก - ค่าเวลา ซึ่งหมายความว่าคุณสามารถพบปัญหากับความไม่ถูกต้องของเลขทศนิยมซึ่งอาจทำให้เกิดพฤติกรรมแปลก ๆ ทุกชนิด นอกจากนี้ความละเอียดของตัวจับเวลาระบบมักจะถูก จำกัด ดังนั้นเมื่อลอจิกลูปของคุณเร็วเกินไปคุณสามารถรับค่าเดลตา - ทีเป็นศูนย์ซึ่งอาจทำให้การหารด้วยศูนย์ทำให้เกิดการชน

เพื่อลดปัญหานี้คุณควร จำกัด framerate ของคุณ (กราฟิกและตรรกะ) ให้มากที่สุดเท่าที่สายตามนุษย์สามารถรับรู้ได้ จำนวนที่มีการโต้แย้งและขึ้นอยู่กับประเภทของภาพเคลื่อนไหวและประเภทของการแสดงที่แสดง แต่การประมาณมีตั้งแต่ 40 FPS ถึง 120 FPS นั่นหมายความว่าคุณต้องตั้งค่าเวลาดำเนินการขั้นต่ำของแต่ละลูประหว่าง 20ms ถึง 8ms หากการวนซ้ำวนซ้ำเสร็จสิ้นเร็วขึ้นให้ cpu thread sleepสำหรับช่วงเวลาที่เหลือ


ขอบคุณสำหรับคำอธิบายของฟิลิปป์ จริง ๆ แล้วฉันอ้างถึงข้อเท็จจริงที่ว่าฉันทำงานที่ fps และ tps ที่แน่นอนรวมทั้งทำการสำรวจเพียงไม่กี่ครั้งต่อวินาที จะพยายามทำให้ชัดเจนยิ่งขึ้น
dot_Sp0T

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

ฉันคงจะยอมรับคำตอบของคุณเช่นกันในย่อหน้าแรกที่ให้คำตอบอย่างสมบูรณ์ คุณคิดจะตั้งมันอย่างชัดเจนด้วยวิธีนอกเหนือจากคำตอบที่เหลือ?
dot_Sp0T

เล่น Civilization 2 ที่ไม่ตรงกันบนเดสก์ท็อปและคุณจะพบว่าเป็นปัญหา อย่างน้อยฉันก็ทำ ยัก
corsiKa

1
นอกเหนือจากข้อควรพิจารณาเกี่ยวกับแบตเตอรี่และพัดลมแล้วการใช้งาน CPU ที่เพิ่มขึ้นอาจทำให้เกิดความร้อนสูงเกินไปซึ่งอาจทำให้รู้สึกไม่สบายใจ (เช่นแล็ปท็อป, esp rMBP ของฉัน) และยังทำให้พีซีปิดตัวลง ปัจจัยเหล่านี้ทำให้โกรธถ้าคุณเรียกใช้คอร์ทั้งหมดเป็น 100%
NPSF3000

2

คุณกำลังสูญเสียรอบ CPU นั่นหมายถึงเวลาที่แบตเตอรีลดลงในโน้ตบุ๊กแท็บเล็ตและโทรศัพท์ค่าไฟฟ้าที่สูงขึ้นความร้อนที่เกิดขึ้นจากเครื่องพัดลมที่มีเสียงดัง นอกจากนี้คุณอาจกำลังกินวงจรจากกระบวนการระบบที่สำคัญอื่น ๆ (เช่นเซิร์ฟเวอร์หน้าต่างอาจกลายเป็นกระตุก) ซึ่งอาจส่งผลกระทบต่อการเล่นเกม ตัวกำหนดเวลาระบบบางระบบในระบบมัลติทาสกิ้งแบบ pre-emptive ของวันนี้ยังลงโทษแอพพลิเคชั่นที่ใช้วงจรมากเกินไปดังนั้นคุณอาจเร็วก่อนจากนั้นก็เห็นความกระตุกอย่างฉับพลันเมื่อคุณควบคุมระบบ

นักเล่นเกมไม่ยอมใครง่ายๆหลายคนยังสร้างพีซีแบบกำหนดเองตั้งแต่เริ่มต้นซึ่งอยู่ที่ข้อกำหนดของแฟนเกมในกรณีที่เป็นวันที่อากาศร้อนและความร้อนที่เกมของคุณสร้างขึ้นอาจทำให้เกิดความปลอดภัยในการทำงาน ตาย (ที่แย่ที่สุด) ดังนั้นหากนั่นคือกลุ่มเป้าหมายของคุณคุณอาจต้องการให้แน่ใจว่าคุณออกจากพื้นที่ "ด้านบน" อยู่เสมอ

ในที่สุดก็มีปัญหาการเล่นเกมที่คุณอาจได้รับประโยชน์จากผู้เล่นที่มีเครื่องจักรเร็วกว่าเกมที่ช้ากว่า การวนลูปเกมที่ความถี่ที่กำหนดและใช้รอบเพิ่มเติมเฉพาะด้านที่ไม่เกี่ยวข้องกับการเล่นเกม (เช่นการแสดงผลกราฟิกความคมชัดที่สูงขึ้น, เอฟเฟกต์เสียงรอบทิศทางหรืออะไรก็ตาม) จะทำให้เกมของคุณยุติธรรมมากขึ้น


ฉันจะบอกว่าคนที่สร้างเครื่องจักรด้วยความหลงใหลนั้นใช้แฟน ๆ ที่ดีแม้กระทั่งการระบายความร้อนด้วยน้ำ เฉพาะ HTPC หรือ mini ITX เคสเท่านั้นที่อาจมีข้อ จำกัด ในส่วนนั้น มิฉะนั้นคนจน แต่ผู้ที่ชื่นชอบจะใช้กล่อง ventirad ซึ่งเพียงพอแม้ที่ 100% ร้อน แต่ก็โอเค
v.oddou

ฉันแค่ทำซ้ำจากประสบการณ์ ถ้าคุณดูที่ Star Trek Online พวกเขามีการตั้งค่าแยกต่างหากใน GUI ของพวกเขาที่จะแทรก sleep () ในลูปหลักของพวกเขาเพื่อป้องกันไม่ให้เครื่องร้อนเกินไปดังนั้นมันจึงไม่ใช่เรื่องแปลกถ้าผู้ผลิตของ Neverwinter และ ขืนเห็นความจำเป็นที่จะต้องเพิ่ม โปรดจำไว้ว่าความรัก! = ทักษะ มีคนจรจัดที่มีทักษะและหลงใหลมากมาย แต่ก็มีผู้เริ่มต้นและคนอื่น ๆ ที่ยังเรียนรู้อยู่และด้วยอัตราการออกกลางคันที่เหมาะสมสถิติกล่าวว่าพวกเขาส่วนใหญ่
uliwitness

ขอบคุณความคิดเห็นเหล่านี้ฉันมาเพื่ออ่านคำตอบของคุณอีกครั้ง คุณแสดงรายการคะแนนที่ถูกต้อง แต่น่าเสียดายที่ไม่ได้ตอบคำถามด้วยเครื่องที่เร็วกว่าและการโต้เถียงเครื่องช้าลง ห่วงตรรกะ (เรียกว่าgameloopในวรรคสามของคุณ) เป็นราก คำถามคือเกี่ยวกับ capping ห่วงกระดูกสันหลังซึ่งก็จะประเมินการทำงานผ่านถ้าใส่ oughta ถูกดึงตรรกะได้รับการคำนวณหรือกรอบควรจะแสดงผลทุก - ดังนั้นไม่ได้เร็วขึ้นตรรกะเว้นแต่เครื่องของคุณเป็นง่อยชะมัด
dot_Sp0T

1

คุณไม่ควรมีการเคลื่อนไหว / การเล่นที่กระวนกระวายใจ

มีสองวิธีที่คุณสามารถใช้ตรรกะของเกมได้ - เชื่อมโยงกับเวลาจริงหรือเชื่อมโยงกับจำนวนของ "การเปลี่ยน" / ขั้นตอนการประมวลผล หากมีบางสิ่งในเกมของคุณเคลื่อนไปทางซ้ายมันจะมีการเคลื่อนไหวที่แตกต่างกันหาก stepLogic () ของคุณถูกเรียกว่า 100 แทนที่จะเป็น 50 ครั้ง

หากรหัสของคุณปฏิบัติตามเวลาที่ผ่านไปอย่างชัดเจนทุกที่และดำเนินการอย่างถูกต้องอาจเป็นไปได้ แต่ถ้ามีอะไรในรหัสของคุณที่ขึ้นอยู่กับจำนวนของ 'ขั้นตอน' คุณจะได้รับผลข้างเคียงที่ไม่พึงประสงค์

ขั้นแรกความเร็วของสิ่งต่าง ๆ ที่ควรเคลื่อนไหวอย่างต่อเนื่องจะแตกต่างกันอย่างไม่คาดคิด (ขึ้นอยู่กับการใช้งานโปรเซสเซอร์) และสิ่งนี้ทำให้การควบคุมที่น่ารำคาญมาก - คุณไม่สามารถหมัดได้อย่างแม่นยำหรือกระโดดถ้าเกมความเร็วขึ้นหรือช้าลง แม้แต่เกมที่ไม่มี 'twitch' แต่ก็ดูน่ารำคาญและกระวนกระวายใจหากสิ่งต่าง ๆ ไม่ราบรื่น

ประการที่สองคุณอาจประสบปัญหากับความสามารถของตัวละครโดยขึ้นอยู่กับความเร็วของคอมพิวเตอร์ตัวอย่างคลาสสิกคือปัญหา Quake แบบเก่าที่ช่วงการกระโดดสูงสุดนั้นขึ้นอยู่กับเฟรมต่อวินาทีของคุณโดยไม่ได้ตั้งใจ

ปัญหาเหล่านี้อาจปรากฏขึ้นแม้ว่าคุณพยายามที่จะให้รหัสเป็นอิสระต่อ fps การสะสมของข้อผิดพลาดในการปัดเศษอาจทำให้เกิดข้อผิดพลาดดังกล่าว


1
เท่าที่ฉันชอบคำตอบของคุณมันไม่เกี่ยวข้องกับคำถามที่ฉันไม่ได้ถามเกี่ยวกับการเคลื่อนไหว / การเล่นเกมที่กระวนกระวายใจ แต่เกี่ยวกับอันตรายเป็นวงที่ไม่สามารถควบคุมได้ (ที่ไม่ควบคุมตรรกะหรือการแสดงผลหรือสิ่งอื่นใด)
dot_Sp0T

1

อันตรายที่อาจเกิดขึ้นเพียงอย่างเดียวคือการใช้พลังงานของคุณดังนั้นอย่าทำเช่นนี้กับอุปกรณ์พกพา ในทางกลับกันระบบฝังตัวบางส่วนใช้เวลาทั้งชีวิตในการรอให้เกิดสิ่งต่าง ๆ

มันเคยเป็นเรื่องปกติอย่างสิ้นเชิงที่จะทำการเรนเดอร์เฟรมเกมให้เร็วที่สุดเท่าที่จะเป็นไปได้บางครั้งโดยไม่มีแม้แต่ตัวจับเวลาเพื่อชดเชยการเล่นเกมด้วยความเร็วซีพียูที่แตกต่างกัน เกมแข่งรถของ Bullfrog Hi-Octane เป็นเหยื่อที่เลวร้ายเป็นพิเศษโดยเฉพาะและฉันสงสัยว่านี่คือสิ่งที่โปสเตอร์กล่าวถึง Civ2 ที่อ้างถึง

ฉันแนะนำให้คุณป้อนข้อมูลแบบสำรวจความคิดเห็นอย่างน้อยในทุก ๆ Pass หากคุณใช้ระบบ Windows หรือคล้ายกัน


มันไม่ใช่คำถามเกี่ยวกับตัวจับเวลามันเป็นคำถามเกี่ยวกับนาฬิกาที่เที่ยงตรงที่ฉันอยากบอกหรือเป็นตัวนับประสิทธิภาพ หนึ่งต้องได้รับเวลาจริงในบางจุดและวนฟรีทำงานอย่างสมบูรณ์ อย่างไรก็ตามตัวจับเวลา (ในแง่ของการหยุดชะงักปกติ) พยายามควบคุมความเร็วของลูปในการใช้งานทั่วไป ฉันไม่คิดว่าสิ่งนี้ดี มันจะดีกว่าที่จะใช้swap/ present/ flipฟังก์ชั่นทำการรอสัญญาณ vsync เพื่อควบคุมวงเกม
v.oddou
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.