Có bất kỳ tác hại nào trong việc chạy vòng lặp trò chơi chính không kiểm soát?


19

Tôi đã tự hỏi nếu có bất kỳ tác hại có thể có khi vòng lặp trò chơi của tôi chạy nhanh như hệ thống cho phép?

Tôi hiện có một vòng lặp, bằng cách đo thời gian trôi qua tính bằng nano giây, chạy logic trò chơi và kết xuất logic ở tốc độ được xác định trước mà không gặp vấn đề gì. Trong thực tế, bất kỳ logic nào tôi thực hiện trong vòng lặp đều được ghi ở một số lượng cuộc gọi nhất định mỗi giây.

Bản thân vòng lặp mặc dù chỉ chạy nhanh như nó muốn với khoảng 11,7 triệu vòng một giây trên máy của tôi.

Vòng lặp (mã giả đơn giản):

while(!isGameOver){

 if(canPollInputs){
    pollInputs()
 }

 while(canStepLogic){
    stepLogic()
 }

 if(canRender){
    render()
 }
}

Câu hỏi của tôi về cơ bản là nếu vòng lặp đơn giản đó, nếu nó không chạy ở tốc độ được kiểm soát, có thể gây hại gì cho hệ thống không?

Chỉnh sửa: Điều đó có nghĩa là logic của tôi đang chạy 30 lần một giây (30 tps), trình kết xuất của tôi đang chạy ở tốc độ 60 khung hình / giây, tôi bỏ phiếu đầu vào 100 lần một giây và cũng có một số logic để đối phó với logic hoặc kết xuất mất nhiều thời gian hơn dự kiến . Nhưng bản thân vòng lặp không phải là điều tiết.

Chỉnh sửa: Sử dụng Thread.sleep()để điều chỉnh vòng lặp chính xuống 250 vòng mỗi giây dẫn đến giảm nhưng các vòng lặp chạy ở khoảng 570 vòng mỗi giây thay vì 250 vòng mong muốn (sẽ thêm mã khi tôi ở máy tính để bàn của mình ..)

Chỉnh sửa: Ở đây chúng tôi đi, một gameloop java hoạt động để làm rõ mọi thứ. Cũng cảm thấy thoải mái khi sử dụng nó nhưng đừng yêu cầu nó là của bạn;)

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

Như bạn có thể thấy, hầu như không có mã nào chạy trên mỗi vòng lặp mà luôn luôn là một lựa chọn nhất định dựa trên thời gian thực đã trôi qua. Câu hỏi đề cập đến 'vòng lặp công nhân' đó và nó ảnh hưởng đến hệ thống như thế nào.


2
bắt buộc 'sửa liên kết dấu thời gian của bạn': gafferongames.com/game-physics/fix-your-timestep vui lòng đọc nó. Cũng lưu ý rằng Thread.S ngủ () không thể được sử dụng để điều tiết thời gian của bạn một cách đáng tin cậy vì HĐH không đảm bảo trả lại quyền kiểm soát cho ứng dụng của bạn sau khoảng thời gian được yêu cầu. (Nó có thể thay đổi).
Roy T.

Vâng, đó là vấn đề với mã giả. Tôi đã làm hầu hết những gì gaffer viết về (hiện đang làm việc trên một triển khai delta bổ sung cho cấu trúc vòng lặp của tôi). Nếu tôi không thể sử dụng Thread.s ngủ () thì có gì khác trong Java tiêu chuẩn?
dot_Sp0T

1
Bạn thường sử dụng một vòng lặp bận rộn với Thread.S ngủ (0) và hy vọng điều tốt nhất. Gaffer nói về điều này rất nhiều trong một vài bài viết.
Roy T.

Vâng, về cơ bản đó là những gì tôi đã làm, chỉ cần không có thread.s ngủ (0), và những gì ban đầu đã gây ra câu hỏi này. Có bất kỳ tác hại nào trong một vòng lặp bận rộn (resp không bận rộn vì ngay cả logic lặp đi lặp lại ít ỏi đó được điều chỉnh xuống) cho hệ thống không?
dot_Sp0T

Một thời gian trước, một lỗi đã khiến Starcraft II thực hiện điều này trong một số điều kiện nhất định. Nó đã kết thúc theo nghĩa đen làm tan chảy một vài GPU. Vì vậy, vâng, rất có thể một vòng lặp trò chơi không được kiểm soát sẽ gây hại.
Mason Wheeler

Câu trả lời:


35

Nó sẽ khiến một lõi CPU luôn chạy trên 100%. Điều này thường không gây ra bất kỳ tác hại cho hệ thống. CPU được thiết kế để chạy trên 100% trong nhiều giờ. Nhưng trên một thiết bị di động, nó sẽ tiêu hao pin nhanh chóng và làm nóng thiết bị, điều này có thể sẽ khiến bạn mất khoảng một ngôi sao trong xếp hạng cửa hàng của mình. Trên máy tính để bàn, đây không phải là vấn đề, nhưng nó sẽ tiêu thụ nhiều điện năng của người dùng hơn, khiến quạt CPU quay nhanh hơn, có thể gây ra một số chu kỳ CPU gây ồn và lãng phí mà các quy trình khác có thể sử dụng. Mặc dù đây không phải là khuyết điểm nghiêm trọng, nhưng chúng vẫn là phong cách xấu, vì vậy bạn nên tránh chúng khi có thể.

Bạn đã không nói bất cứ điều gì về cách vòng lặp logic trò chơi của bạn hoạt động bên trong, nhưng khi bạn đang sử dụng cách tiếp cận theo thời gian delta (mỗi phép tính bạn đang thực hiện sẽ mất thời gian kể từ lần gọi cuối cùng vào tài khoản), bạn đang xử lý với delta rất nhỏ- giá trị thời gian. Điều này có nghĩa là bạn có thể gặp vấn đề với sự thiếu chính xác của dấu phẩy động có thể gây ra tất cả các loại hành vi lạ. Ngoài ra, độ phân giải của bộ định thời hệ thống thường bị giới hạn, do đó, khi vòng logic của bạn quá nhanh, bạn có thể nhận được giá trị delta-t bằng 0, sau đó có thể gây ra chia cho 0 dẫn đến sự cố.

Để giảm thiểu vấn đề này, bạn nên giới hạn tốc độ khung hình (đồ họa và logic) của mình ở mức tối đa những gì mắt người có thể cảm nhận được. Bao nhiêu đó là tranh chấp và phụ thuộc vào loại hình ảnh động và loại màn hình được hiển thị, nhưng ước tính dao động từ 40 FPS đến 120 FPS. Điều đó có nghĩa là bạn cần đặt thời gian thực hiện tối thiểu của mỗi vòng lặp trong khoảng từ 20ms đến 8ms. Nếu việc lặp vòng lặp kết thúc nhanh hơn, hãy để luồng cpu sleepcho khoảng thời gian còn lại.


Cảm ơn lời giải thích Philipp. Tôi thực sự đã đề cập đến thực tế là tôi đang chạy ở một khung hình / giây nhất định cũng như việc bỏ phiếu chỉ một số lần nhất định trong một giây. Sẽ cố gắng để làm cho nó rõ ràng hơn mặc dù.
dot_Sp0T

@ dot_Sp0T Sau khi chỉnh sửa câu hỏi của bạn, chỉ đoạn đầu tiên và câu cuối cùng có liên quan đến trường hợp của bạn. Tuy nhiên, tôi muốn giữ lại đoạn thứ hai và thứ ba trong câu trả lời của mình vì chúng có thể hữu ích cho người khác.
Philipp

Tôi có lẽ cũng sẽ chấp nhận câu trả lời của bạn vì đoạn đầu tiên hoàn toàn đưa ra câu trả lời. Bạn có phiền để bằng cách nào đó trực quan đặt nó ngoài phần còn lại của câu trả lời?
dot_Sp0T

Chơi một Civilization 2 chưa từng có trên máy tính để bàn và bạn sẽ thấy nó là một vấn đề. Ít nhất, tôi làm. nhún vai
corsiKa

1
Ngoài các cân nhắc về pin và quạt, việc sử dụng CPU tăng lên có thể dẫn đến nhiệt độ quá cao có thể gây khó chịu (ví dụ: máy tính xách tay, đặc biệt là rMBP của tôi) và thậm chí dẫn đến việc PC bị tắt (đặc biệt là PC cũ có bộ làm mát bụi). Các yếu tố này là bực tức nếu bạn chạy tất cả các lõi 100%.
NPSF3000

2

Bạn đang lãng phí chu kỳ CPU. Điều đó có nghĩa là thời gian sử dụng pin trên máy tính xách tay, máy tính bảng và điện thoại thấp hơn, hóa đơn tiền điện cao hơn, nhiệt do máy tạo ra nhiều hơn, quạt ồn hơn. Ngoài ra, bạn có thể đang ăn chu kỳ từ các quy trình hệ thống quan trọng khác (ví dụ: máy chủ cửa sổ có thể bị giật), sau đó có thể ảnh hưởng đến trò chơi. Một số bộ lập lịch hệ thống trên các hệ thống đa nhiệm ưu tiên hiện nay cũng xử phạt các ứng dụng sử dụng quá nhiều chu kỳ, do đó bạn có thể nhanh trước, sau đó đột nhiên thấy giật giật lạ khi bạn bị hệ thống điều khiển.

Nhiều game thủ khó tính cũng xây dựng các PC tùy chỉnh từ đầu ở cạnh thông số kỹ thuật của người hâm mộ của họ, trong trường hợp một ngày nóng và sức nóng mà trò chơi của bạn tạo ra có thể khiến các két sắt kích hoạt trong máy (tốt nhất) hoặc thậm chí làm cho các bộ phận bị quá nóng và chết (tệ nhất). Vì vậy, nếu đó là đối tượng mục tiêu của bạn, bạn có thể muốn đảm bảo rằng bạn luôn để lại một chút không gian "ở trên cùng".

Cuối cùng, có những vấn đề về lối chơi trong đó bạn có thể ưu tiên người chơi với những cỗ máy nhanh hơn những người chơi chậm hơn. Việc vòng lặp trò chơi được giới hạn ở một tần số nhất định và chỉ sử dụng các chu kỳ bổ sung cho các khía cạnh không liên quan đến trò chơi (như hiển thị đồ họa có độ trung thực cao hơn, hiệu ứng âm thanh vòm hoặc bất cứ điều gì) sẽ giúp trò chơi của bạn công bằng hơn.


Tôi sẽ nói ngược lại, những người say mê chế tạo máy móc của họ sử dụng quạt tốt, thậm chí là tưới nước. Chỉ các trường hợp HTPC hoặc ITX nhỏ có thể có những hạn chế về phần đó. Nếu không, người nghèo nhưng người đam mê sẽ sử dụng hộp ventirad. Đó là đủ ngay cả ở mức 100%, nóng nhưng ok.
v.oddou

Tôi chỉ đang lặp lại từ kinh nghiệm. Nếu bạn xem Star Trek Online, họ thực sự có một cài đặt riêng trong GUI sẽ chèn chế độ ngủ () vào vòng lặp chính của họ để giữ cho các máy nhất định không bị quá nóng, vì vậy đó không phải là điều hiếm gặp nếu nhà sản xuất Neverwinter và STO thấy sự cần thiết phải thêm nó. Hãy ghi nhớ rằng niềm đam mê! = Kỹ năng. Có rất nhiều người say mê lành nghề và đam mê, nhưng cũng có những người mới bắt đầu và những người khác vẫn đang học, và với tỷ lệ bỏ học khá, thống kê cho biết họ chiếm đa số.
uliwitness

Nhờ những bình luận này mà tôi đã đọc lại câu trả lời của bạn. Bạn liệt kê các điểm hợp lệ nhưng thật đáng buồn là không thực sự giải quyết câu hỏi với các máy nhanh hơn so với tranh cãi về máy chậm hơn . Các vòng lặp Logic (gọi tắt là gameloop trong đoạn thứ ba của bạn) bị giới hạn. Câu hỏi đặt ra là giới hạn vòng lặp xương sống, đơn giản là đánh giá lại mỗi lần chạy nếu đầu vào bị kéo, logic được tính toán hoặc khung hình sẽ được hiển thị - vì vậy không có logic nhanh hơn trừ khi máy của bạn bị khập khiễng khủng khiếp
dot_Sp0T

1

Bạn không nên có phong trào / lối chơi lộn xộn

Có hai cách bạn có thể thực hiện logic trò chơi - gắn với thời gian thực hoặc gắn với số lượng "lượt" / bước xử lý. Nếu một số thứ trong trò chơi của bạn di chuyển sang trái, thì chuyển động của nó có khác không nếu stepLogic () của bạn được gọi là 100 thay vì 50 lần?

Nếu mã của bạn xử lý thời gian trôi qua một cách rõ ràng ở mọi nơi và thực hiện đúng, thì nó có thể ổn; nhưng nếu có bất cứ điều gì trong mã của bạn phụ thuộc vào số lượng 'bước' thì bạn sẽ nhận được các tác dụng phụ không mong muốn.

Đầu tiên, tốc độ của những thứ nên di chuyển liên tục sẽ thay đổi một cách khó lường (tùy thuộc vào cách sử dụng bộ xử lý) và điều này tạo ra các điều khiển rất khó chịu - bạn không thể thực hiện một cú đấm hay cú nhảy chính xác nếu đột nhiên trò chơi tăng tốc hoặc chậm lại. Ngay cả đối với các trò chơi hoàn toàn không có 'co giật', nó vẫn có vẻ khó chịu và bồn chồn nếu mọi thứ không diễn ra suôn sẻ.

Thứ hai, bạn có thể gặp vấn đề với khả năng của nhân vật tùy thuộc vào tốc độ máy tính - một ví dụ kinh điển là vấn đề Quake cũ trong đó phạm vi nhảy tối đa vô tình phụ thuộc vào khung hình / giây của bạn.

Các vấn đề này có thể xuất hiện ngay cả khi bạn cố gắng để mã độc lập với khung hình / giây, việc tích lũy các lỗi làm tròn thường có thể gây ra các lỗi như vậy.


1
Nhiều như tôi thích câu trả lời của bạn không liên quan đến câu hỏi, vì tôi không hỏi về chuyển động / lối chơi lộn xộn mà về tác hại của một vòng lặp không kiểm soát (điều đó không kiểm soát bất kỳ logic hoặc kết xuất hoặc bất cứ điều gì khác) có thể làm cho các hệ thống
dot_Sp0T

1

Tác hại tiềm năng duy nhất là tiêu thụ năng lượng của bạn, vì vậy đừng làm điều này trên thiết bị di động. Ngược lại, khá nhiều hệ thống nhúng dành toàn bộ cuộc sống của họ trong một vòng lặp chờ đợi mọi thứ xảy ra.

Nó được sử dụng hoàn toàn bình thường để chỉ hiển thị các khung trò chơi nhanh nhất có thể, đôi khi không có bộ đếm thời gian để bù cho trò chơi cho các tốc độ CPU khác nhau. Trò chơi đua xe của Bullfrog Hi-Octane là một nạn nhân đặc biệt tồi tệ của điều này, và tôi nghi ngờ đây là những gì mà poster đề cập đến Civil2 đang đề cập.

Tôi khuyên bạn ít nhất nên thăm dò ý kiến ​​đầu vào trên mỗi lượt nếu bạn đang sử dụng hệ thống Windows hoặc tương tự, để đảm bảo phản hồi đầu vào linh hoạt.


Đây không phải là câu hỏi về bộ đếm thời gian, đó là câu hỏi về đồng hồ bấm giờ mà tôi muốn nói, hoặc bộ đếm hiệu suất. Một người cần có được thời gian thực tại một số điểm, và một vòng lặp miễn phí hoạt động hoàn hảo. Tuy nhiên, một bộ đếm thời gian (theo nghĩa gián đoạn thường xuyên) đang cố gắng điều chỉnh tốc độ vòng lặp trong sử dụng chung. Tôi không coi điều này là tốt. Đó là một lợi thế để sử dụng swap/ present/ flipchức năng làm việc chờ đợi trên tín hiệu vsync, để điều chỉnh vòng lặp game.
v.oddou
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.