태그 보관물: architecture

architecture

완료하기 위해 여러 프레임이 필요한 게임 동작

나는 실제로 많은 게임 프로그래밍을 한 적이 없었습니다.

테트리스 게임을 만들고 있는데, 메인 루프가 이런 식으로 보인다고 상상해보십시오.

for every frame
    handle input
    if it's time to make the current block move down a row
        if we can move the block
            move the block
        else
            remove all complete rows
            move rows down so there are no gaps
            if we can spawn a new block
                spawn a new current block
            else
                game over

게임에서 모든 것은 지금까지 즉시 발생 – 상황이 즉시 양산하는, 내가하면 행이 즉시 등 그러나 제거 하지 않는 것을 즉시 (즉, 애니메이션 일)이 일어날까요?

for every frame
    handle input
    if it's time to make the current block move down a row
        if we can move the block
            move the block
        else
            ?? animate complete rows disappearing (somehow, wait over multiple frames until the animation is done)
            ?? animate rows moving downwards (and again, wait over multiple frames)
            if we can spawn a new block
                spawn a new current block
            else
                game over

내 탁구 복제에서는 모든 프레임이 공을 움직이고 충돌을 확인하기 때문에 문제가되지 않았습니다.

이 문제를 어떻게 해결해야합니까? 확실히 대부분의 게임에는 프레임보다 많은 작업이 필요하며 다른 작업은 작업이 완료 될 때까지 중지됩니다.



답변

이것에 대한 전통적인 해결책은 유한 상태 머신이며 여러 의견에서 제안되고 있습니다.

나는 유한 상태 기계가 싫어.

물론, 그들은 간단하고 모든 언어로 지원되지만 작업하기에는 너무나 큰 고통입니다. 모든 조작에는 버그가 발생하기 쉬운 복사 및 붙여 넣기 코드가 많이 필요하며, 작은 방식으로 효과를 조정하면 코드가 크게 변경 될 수 있습니다.

당신이 그들을 지원하는 언어를 사용할 수 있다면, 나는 코 루틴을 권장합니다. 그들은 다음과 같은 코드를 작성할 수있게합니다.

function TetrisPieceExplosion()
  for brightness = 0, 1, 0.2 do
    SetExplosionBrightness(brightness)
    coroutine.yield()
  end

  AllowNewBlockToFall()

  SpawnABunchOfParticles()

  RemoveBlockPhysics()

  for transparency = 0, 1, 0.5 do
    SetBlockTransparency(transparency)
    coroutine.yield()
  end

  RemoveBlockGraphics()
end

분명히 의사 코드이지만, 이것이 특수 효과에 대한 간단한 선형 설명 일뿐 만 아니라 애니메이션이 여전히 끝나는 동안 새 블록 쉽게 떨어 뜨릴 수 있음이 분명해야합니다 . 스테이트 머신으로 이것을 달성하는 것은 일반적으로 대단합니다.

내가 아는 한,이 기능은 C, C ++, C #, Objective C 또는 Java에서 쉽게 사용할 수 없습니다. 이것이 내가 모든 게임 로직에 Lua를 사용하는 주요 이유 중 하나입니다. 🙂


답변

Mike McShaffry의 Game Coding Complete에서 가져 왔습니다.

그는 ‘프로세스 관리자’에 대해 이야기하며,이 프로세스 관리자는 수행해야 할 작업 목록으로 요약됩니다. 예를 들어, 프로세스는 검 (AnimProcess)을 그리거나 문을 열거 나 행을 사라지게하는 애니메이션을 제어합니다.

프로세스는 프로세스 관리자의 목록에 추가되며, 매 프레임마다 호출되고 각 프레임에서 Update ()가 호출됩니다. 매우 많은 실체이지만 행동을위한 것입니다. 완료되면 목록에서 제거 할 kill 플래그가 있습니다.

그들에 대한 또 다른 깔끔한 점은 다음 프로세스에 대한 포인터를 가져서 어떻게 연결할 수 있는지입니다. 이러한 방식으로 애니메이션 행 프로세스는 실제로 다음으로 구성 될 수 있습니다.

  • 행이 사라지는 애니메이션 프로세스
  • 조각을 제거하는 MovementProcess
  • 점수에 점수를 추가하는 ScoreProcess

(프로세스는 일회용 일 수도 있고, 조건부 또는 X 시간 동안있을 수도 있기 때문에)

더 자세한 정보가 필요하면 물어보십시오.


답변

우선 순위 작업 대기열을 사용할 수 있습니다. 당신은 행동과 시간을 밀어 넣습니다. 각 프레임마다 시간이 표시되고 그 시간 이전과 같이 지정된 시간이있는 모든 작업을 수행하여 실행합니다. 보너스 : 접근 방식은 훌륭하게 병렬 처리되며 실제로 거의 모든 게임 로직을이 방법으로 구현할 수 있습니다.


답변

항상 이전 프레임과 현재 프레임의 시차를 알아야하며 두 가지 작업을 수행해야합니다.

-모델 업데이트시기 결정 : 예. 테트리스에서 행 제거가 시작되면 더 이상 행과 충돌하는 것을 원하지 않으므로 응용 프로그램의 ‘모델’에서 행을 제거하십시오.

그런 다음 전환 상태에있는 객체를 일정 기간 동안 애니메이션 / 이벤트를 해결하는 별도의 클래스로 처리해야합니다. 테트리스 예제에서는 행이 천천히 페이드 아웃됩니다 (각 프레임의 불투명도를 약간 변경). 불투명도가 0이면 행의 맨 위에있는 모든 블록을 아래로 전송합니다.

처음에는 약간 복잡해 보일지 모르지만이 문제를 해결하려면 다른 클래스에서 많은 부분을 추상화해야합니다. 또한 테트리스에서 행을 제거하는 것과 같이 시간이 걸리는 이벤트가 “Fire and Forget”종류인지 확인하고, 자동으로 수행해야하는 모든 것을 처리하고 모든 작업이 완료되면 장면 그래프에서 자신을 제거합니다.


답변

게임을 “유한 상태 머신”으로 생각해야합니다. 게임은 여러 가지 상태 중 하나 일 수 있습니다. 귀하의 경우 “예상 입력”, “조각 아래로 이동”, “행 폭발”.

상태에 따라 다른 일을합니다. 예를 들어, “조각 아래로 이동”중에는 플레이어 입력을 무시하고 대신 현재 행에서 다음 행으로 조각을 애니메이션합니다. 이 같은:

if state == ACCEPTING_INPUT:
    if player presses any key:
        handle input
    row_timer = row_timer - time_since_last_frame
    if row_timer < 0:
        state = MOVING_PIECE_DOWN
elif state == MOVING_PIECE_DOWN:
    piece.y = piece.y + piece.speed*time_since_last_frame
    if piece.y >= target_piece_y:
        piece.y = target_piece_y
        state = ACCEPTING_INPUT

답변