메인 게임 루프가 통제되지 않은 상태에서 실행되는 데 해가 있습니까?


19

게임 루프가 시스템이 허용하는 한 빨리 실행될 때 가능한 해가 있는지 궁금합니다.

나는 현재 통과 시간을 나노초로 측정하여 문제없이 사전 정의 된 속도로 게임 로직과 렌더링 로직을 실행하는 루프를 가지고 있습니다. 실제로 루프에서 수행하는 모든 논리는 초당 특정 양의 호출로 클럭됩니다.

루프 자체는 원하는 속도만큼 빠르게 실행되며 내 컴퓨터에서 초당 약 1,170 만 루프가 발생합니다.

루프 (간단한 의사 코드) :

while(!isGameOver){

 if(canPollInputs){
    pollInputs()
 }

 while(canStepLogic){
    stepLogic()
 }

 if(canRender){
    render()
 }
}

내 질문은 기본적으로 간단한 루프가 제어 된 속도로 실행되지 않으면 시스템에 해를 끼칠 수 있는지 여부입니다.

편집 : 그것은 내 논리가 초당 30 번 (30 tps) 실행되고 내 렌더러가 60fps로 실행 중이며 입력을 초당 100 회 폴링하고 논리에 대처하는 논리가 있거나 예상보다 오래 걸리는 렌더링이 있음을 의미합니다 . 그러나 루프 자체는 조절되지 않습니다.

편집 : Thread.sleep()예를 들어 메인 루프를 초당 250 루프로 낮추면 루프가 줄어들지 만 루프는 원하는 250 대신 초당 약 570 루프로 실행됩니다 (내 데스크탑 컴퓨터에있을 때 코드가 추가됩니다 ..)

편집 : 여기에 물건을 명확히하기 위해 작동하는 Java 게임 루프가 있습니다. 또한 자유롭게 사용하되 자신의 것으로 주장하지 마십시오.)

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 읽어보십시오. 또한 요청한 시간이 지나면 OS가 응용 프로그램으로 제어를 반환한다고 보장하지 않으므로 Thread.Sleep ()를 사용하여 시간 단계를 안정적으로 조절할 수 없습니다. (다를 수 있습니다).
Roy T.

예, 그것은 의사 코드의 문제입니다. 나는 gaffer가 쓰는 것의 대부분을 수행했다 (현재 루프 구조를 보완하는 델타 구현 작업 중). Thread.sleep ()을 사용할 수 없다면 표준 Java에서 사용할 수있는 다른 것이 있습니까?
dot_Sp0T

1
일반적으로 Thread.Sleep (0)과 함께 사용 중 루프를 사용하고 최선을 다하겠습니다. Gaffer는 몇 가지 기사에서 이것에 대해 많이 이야기합니다.
Roy T.

글쎄 그것은 기본적으로 thread.sleep (0)없이 내가하고있는 일이며, 원래이 질문을 일으킨 것입니다. 시스템의 사용 중 (반복적 인 로직이 제한되어 있어도 사용 중이 아님) 루프에 해가 있습니까?
dot_Sp0T

얼마 전, 특정 조건에서 스타 크래프트 II가 버그를 일으켰습니다. 말 그대로 몇 GPU를 녹였습니다. 따라서 통제되지 않은 게임 루프가 해를 입힐 수 있습니다.
메이슨 휠러

답변:


35

하나의 CPU 코어가 항상 100 %로 실행됩니다. 이것은 일반적으로 시스템에 끼치 지 않습니다 . CPU는 몇 시간 동안 100 %에서 실행되도록 설계되었습니다. 그러나 모바일 장치에서는 배터리가 빨리 소모되고 장치가 가열되므로 매장 등급의 별에 대한 비용이 발생할 수 있습니다. 데스크톱 컴퓨터에서는 이것이 문제가되지 않지만 더 많은 전력을 소비하고 CPU 팬이 더 빨리 회전하여 소음이 발생하고 CPU 사이클이 낭비되어 다른 프로세스에서 사용할 수 있습니다. 이러한 결함은 치명적인 결함은 아니지만 여전히 나쁜 스타일이므로 가능하면 피해야합니다.

게임 로직 루프가 내부적으로 어떻게 작동하는지에 대해서는 아무 말도하지 않았지만 델타 타임 접근법을 사용할 때 (각 계산은 마지막 호출 이후 시간이 걸린다) 델타 시간이 매우 작습니다. 시간 값. 즉, 부동 소수점 부정확성으로 인해 모든 종류의 이상한 동작이 발생할 수 있습니다. 또한 시스템 타이머의 해상도가 제한되는 경우가 많으므로 논리 루프가 너무 빠르면 델타 t 값이 0이되어 0으로 나누면 충돌이 발생할 수 있습니다.

이 문제를 완화하려면 프레임 속도 (그래픽 및 논리)를 육안으로 인식 할 수있는 최대 값으로 제한해야합니다. 이의 양은 논란의 여지가 있으며 애니메이션의 종류와 표시되는 디스플레이 종류에 따라 다르지만 추정 범위는 40FPS에서 120FPS입니다. 즉, 각 루프의 최소 실행 시간을 20ms에서 8ms 사이로 설정해야합니다. 루프 반복이 더 빨리 완료 sleep되면 남은 시간 동안 CPU 스레드 를 사용하십시오.


설명 Philipp에 감사드립니다. 필자는 실제로 특정 fps와 tps에서 실행 중이며 초당 특정 양의 폴링 만 수행한다는 사실을 언급했습니다. 그래도 더 명확하게하려고합니다.
dot_Sp0T

@ dot_Sp0T 질문을 편집 한 후 첫 번째 단락과 마지막 문장 만 사건과 관련이 있습니다. 그러나 다른 사람들에게 도움이 될 수 있기 때문에 대답의 두 번째 및 세 번째 단락을 유지하고 싶습니다.
Philipp

첫 번째 단락이 완벽하게 잘 답변 해 주었을 것입니다. 어떻게 든 나머지 답변과 시각적으로 구분 하시겠습니까?
dot_Sp0T

데스크탑에서 패치되지 않은 문명 2를 재생하면 문제가있는 것입니다. 적어도 그렇습니다. 어깨를 으
corsiKa

1
배터리 및 팬 고려 사항 외에도 CPU 사용량을 늘리면 과도한 열이 발생하여 불편할 수 있으며 (예 : 랩탑, eMBM 등) PC가 종료 될 수 있습니다 (더 오래된 PC의 먼지가 많은 쿨러). 모든 코어를 100 % 실행하면 이러한 요소가 악화됩니다 .
NPSF3000

2

CPU 사이클을 낭비하고 있습니다. 즉, 노트북, 태블릿 및 휴대 전화의 배터리 시간이 줄어들고 전기 요금이 높아지며 기계에서 더 많은 열이 발생하며 팬이 더 시끄 럽습니다. 또한 다른 중요한 시스템 프로세스 (예 : 윈도우 서버가 불안정해질 수 있음)에서 사이클을 먹고 게임 플레이에 영향을 줄 수 있습니다. 오늘날 선점 형 멀티 태스킹 시스템의 일부 시스템 스케줄러는 너무 많은주기를 사용하는 응용 프로그램에 불이익을 주므로, 빠른 속도에 빠질 수 있으며 시스템에 의해 쓰러 질 때 갑자기 이상한 소리가 나게됩니다.

또한 많은 하드 코어 게이머는 팬 사양의 가장자리에있는 맞춤형 PC를 처음부터 구축합니다.이 경우 더운 날과 게임에서 발생하는 열로 인해 안전이 기계에서 발생하거나 (최상의) 부품이 과열되거나 죽는다 (최악). 따라서 이것이 대상 독자라면 항상 "맨 위"에 약간의 공간을 남겨 두어야합니다.

마지막으로, 더 느린 컴퓨터보다 더 빠른 컴퓨터를 가진 플레이어에게 유리한 게임 플레이 문제가 있습니다. 게임 루프를 특정 주파수로 제한하고 게임 플레이와 관련이없는 측면 (고 충실도 그래픽 렌더링, 서라운드 사운드 효과 등)에 대해서만 추가주기를 사용하면 게임의 공정성이 향상됩니다.


반대로 기계를 열정적으로 만드는 사람들은 좋은 팬, 심지어 물 냉각을 사용한다고 말합니다. HTPC 또는 mini ITX 케이스 만 해당 부분에 제한이있을 수 있습니다. 그렇지 않으면 열악하지만 열성적인 사람들이 상자 통풍구를 사용할 것입니다. 100 %에서도 충분하지만 뜨겁지 만 괜찮습니다.
v.oddou

나는 단지 경험에서 반복되고 있습니다. Star Trek Online을 보면 실제로 GUI에 별도의 설정이있어 특정 기계가 과열되는 것을 막기 위해 메인 루프에 sleep ()을 삽입하므로 Neverwinter의 제조사와 STO는이를 추가 할 필요성을 보았다. 그 열정! = 기술을 명심하십시오. 많은 숙련되고 열정적 인 땜장이들이 있지만, 아직 배우고있는 초보자들과 다른 사람들도 있으며, 적절한 탈락률로 통계가 대다수라고 말합니다.
uliwitness

이 의견 덕분에 나는 당신의 대답을 다시 읽게되었습니다. 당신은 유효한 점수를 나열하지만 슬프게도 더 빠른 기계 대 느린 기계 논쟁으로 질문을 다루지 않습니다 . 논리 루프 (라고 gameloop 세 번째 단락)이 덮인된다. 컴퓨터가 정말 절름발이 경우를 제외하고 그래서 빨리 논리 - 문제는 단순히 입력 당겨 되겠지 경우, 로직은 계산 또는 프레임이 렌더링되지 않아야을 통해 모든 실행을 재평가 백본 루프 상한에 대해이었다
dot_Sp0T

1

불안한 움직임 / 게임 플레이가 없어야합니다

게임 로직을 구현할 수있는 두 가지 방법이 있습니다-실시간으로 연결되거나 "턴"/ 프로세스 단계의 수로 연결됩니다. 게임에서 무언가가 왼쪽으로 움직이면 stepLogic ()이 50 번이 아니라 100 번 호출되면 동작이 달라 집니까?

코드가 경과 시간을 모든 곳에서 명시 적으로 처리하고 올바르게 수행하면 괜찮을 것입니다. 그러나 코드에 '단계'수에 의존하는 것이 있으면 원치 않는 부작용이 발생합니다.

첫째, 지속적으로 움직여야하는 속도는 예측할 수없이 (프로세서 사용에 따라 다름) 매우 귀찮은 컨트롤을 만듭니다. 갑자기 게임 속도가 빨라지거나 속도가 느려지면 정확한 펀치 나 점프를 할 수 없습니다. 전혀 '비틀림'이없는 게임의 경우에도 원활하게 움직이지 않으면 성 가시고 불안해 보입니다.

둘째, 컴퓨터 속도에 따라 캐릭터 능력에 문제가 생길 수 있습니다. 고전적인 예는 최대 점프 범위가 실수로 fps에 의존했던 오래된 Quake 문제입니다.

이러한 문제는 코드를 fps와 무관하게 만들려고해도 반올림 오류가 누적되어 이러한 버그가 발생할 수 있습니다.


1
불안한 움직임 / 게임 플레이에 대해 묻지 않고 제어되지 않은 루프 (논리 또는 렌더링을 제어하지 않는 다른 것)가 시스템에 미칠 수있는 피해에 대해 귀하의 답변을 좋아하는 것은 질문과 관련이 없습니다.
dot_Sp0T

1

유일한 잠재적 인 피해는 전력 소비에 영향을 미치므로 모바일 장치에서는이 작업을 수행하지 마십시오. 반대로, 상당히 많은 임베디드 시스템이 일이 일어나기를 기다리는 동안 전체 수명을 보냅니다.

예전에는 게임 프레임을 다른 CPU 속도로 보상하기 위해 타이머 없이도 가능한 한 빨리 게임 프레임을 렌더링하는 것이 완전히 정상이었습니다. Bullfrog의 레이싱 게임 Hi-Octane은 특히 이것의 나쁜 희생자였습니다.

Windows 시스템 또는 이와 유사한 시스템에서 입력 패스를 신속하게 수행하려면 모든 패스에서 입력을 폴링하는 것이 좋습니다.


타이머 문제가 아니라 크로노 미터 나 성능 카운터 문제입니다. 어느 시점에서 실시간을 확보해야하며 자유 루프가 완벽하게 작동합니다. 그러나 (정기 중단의 의미에서) 타이머는 일반적인 사용에서 루프 속도를 조정하려고합니다. 나는 이것을 좋은 것으로 생각하지 않습니다. 사용하는 것이 바람직하다 swap/ present/ flip게임 루프를 조절, VSYNC 신호를 대기 할 기능.
v.oddou
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.