턴 기반 게임에서 세계 상태와 애니메이션 분리


9

턴 기반 게임 내에서 애니메이션을 월드 상태와 분리하는 것을 어떻게 처리합니까? 현재 2D 그리드 기반 게임을 만들고 있습니다. 아래 코드는 더 잘 설명하기 위해 단순화되었습니다.

액터가 움직일 때, 생물이 움직이고 새로운 위치로 움직일 때 회전 흐름을 멈추고 싶습니다. 그렇지 않으면 화면이 월드 상태보다 크게 지연되어 시각적으로 이상하게 보일 수 있습니다. 또한 게임의 흐름을 차단하지 않는 애니메이션을 원합니다. 파티클 효과는 게임 플레이에 영향을 미치지 않고 여러 차례에 걸쳐 펼쳐질 수 있습니다.

내가 한 것은 블로킹 애니메이션과 비 블로킹 애니메이션이라고하는 두 가지 유형의 애니메이션을 소개하는 것입니다. 플레이어가 움직이기를 원할 때 실행되는 코드는

class Actor {
    void move(PositionInfo oldPosition, PositionInfo newPosition) {
        if(isValidMove(oldPosition, newPosition) {
             getGame().pushBlockingAnimation(new MoveAnimation(this, oldPosition, newPosition, ....));
             player.setPosition(newPosition);
        }
    }
}

그런 다음 기본 업데이트 루프는 다음을 수행합니다.

class Game {
    void update(float dt) {
        updateNonBlockingAnimations(dt); //Effects like particle explosions, damage numbers, etc. Things that don't block the flow of turns.
        if(!mBlockingAnimations.empty()) {
            mBlockingAnimations.get(0).update(dt);
        } else {
             //.. handle the next turn. This is where new animations will be enqueued..//
        }
        cleanUpAnimations(); // remove finished animations
    }
}

애니메이션이 액터의 화면 위치를 업데이트합니다.

내가 구현하고있는 또 다른 아이디어는 동시 차단 애니메이션을 사용하는 것입니다. 여기에서 여러 차단 애니메이션이 동시에 업데이트되지만 다음 차례는 모두 완료 될 때까지 발생하지 않습니다.

이것은 일을하는 제정신 방법처럼 보입니까? 누구든지 다른 유사한 게임이 어떻게 그런 일을하는지에 대한 제안이나 언급이 있습니까?

답변:


2

당신의 시스템이 당신을 위해 일한다면, 나는 그렇게하지 않을 이유를 보지 못합니다.

글쎄요, 한 가지 이유 : "player.setPosition (newPosition);"의 결과를 쉽게 판단 할 수 없을 때 혼란 스러울 수 있습니다. 더 이상

예 (만들기) : setPosition을 사용하여 플레이어를 트랩 위로 이동한다고 상상해보십시오. "player.setPosition"자체에 대한 호출은 트랩 리스너 코드에 대한 다른 호출을 유발합니다. 트랩 리스너 코드는 그 자체로 블로킹 애니메이션 자체를 푸시하여 자체에 "hurting splash"를 표시합니다.

문제가 발생합니다. 플레이어가 함정을 향해 움직이면 스플래시가 동시에 표시됩니다 . (여기서는 이것을 원하지 않지만 이동이 완료된 직후 트랩 애니메이션이 재생되기를 원한다고 가정하십시오).

"pushBlockingAnimation"호출 후에 수행 모든 작업 결과를 염두에두면 모든 것이 정상입니다.

애니메이션이 끝난 후 실행되도록 대기열에 넣을 수 있도록 게임 로직을 "무언가 차단"으로 랩핑해야 할 수도 있습니다. 또는 "callThisAfterAnimationFinishes"콜백을 pushBlockingAnimation에 전달하고 setPosition을 콜백 함수로 옮깁니다.

또 다른 방법은 스크립팅 언어입니다. 예를 들어 Lua에는 "coroutine.yield"가 있는데,이 함수는 특수 상태로 함수를 반환하므로 나중에 다음 명령문에서 계속 호출 할 수 있습니다. 이렇게하면 코드의 "정상적인"프로그램 흐름 모양을 어지럽히 지 않고 애니메이션의 끝이 게임 로직을 실행하기를 쉽게 기다릴 수 있습니다. (코드가 여전히 콜백을 전달하고 여러 함수를 통해 게임 로직을 어지럽히는 대신 "playAnimation (); setPosition ();"과 비슷하게 보입니다.

Unity3D (및 내가 아는 다른 게임 시스템 중 하나 이상)에는 C # 코드에서 직접 시뮬레이션하는 C # "yield return"문이 있습니다.

// instead of simple call to move(), you have to "iterate" it in a foreach-like loop
IEnumerable<Updatable> move(...) {
    // playAnimation returns an object that contain an update() and finished() method.
    // the caller will not iterate over move() again until the object is "finished"
    yield return getGame().playAnimation(...)
    // the next statement will be executed *after* the animation finished
    player.setPosition(newPosition);
}

물론,이 체계에서 move () 호출은 이제 모든 더러운 작업을 가져옵니다. 이 기술은 누가 어디에서 누구를 호출하는지 정확히 알고있는 특정 기능에만 적용 할 수 있습니다. 따라서 다른 엔진을 구성하는 기본 아이디어로만 사용하십시오. 현재 특정 문제에는 너무 복잡 할 수 있습니다.

실제 문제가 발생할 때까지 pushBlockingAnimation 아이디어를 따르는 것이 좋습니다. 그런 다음 수정하십시오. ;)


이 답변을 작성해 주셔서 감사합니다. 정말 감사합니다.
mdkess
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.