게임 동작을 수행하기위한 패턴


11

게임 내에서 다양한 작업을 수행하기 위해 일반적으로 허용되는 패턴이 있습니까? 플레이어가 행동을 수행하고 AI가 이동, 공격, 자기 파괴 등과 같은 행동을 수행 할 수있는 방법.

현재 .NET 제네릭을 사용하여 다양한 동작으로 반환되는 다른 객체를 지정하는 추상 BaseAction이 있습니다. 이것은 모두 명령과 유사한 패턴으로 구현되며 각 작업은 자체적으로 책임지고 필요한 모든 작업을 수행합니다.

추상적 인 이유는 하나의 ActionHandler를 가질 수 있기 때문에 AI는 baseAction을 구현하는 다른 액션을 대기시킬 수 있습니다. 그리고 일반적인 이유는 다른 액션이 일반적인 beforeAction 및 afterAction 구현과 함께 액션과 관련된 결과 정보를 반환 할 수 있기 때문입니다.

그래서 ...이 작업을 수행하는 데 더 허용되는 방법이 있습니까?


잘 들리 네요. 질문은 대기열에서 무엇을 의미합니까? 대부분의 게임은 매우 빠른 반응을 보입니까? "AI는 다른 행동을 대기 할 수 있습니다"
AturSams

좋은 지적. 대기열이 없습니다. 바쁜 경우에만 알 수 있고, 그렇지 않은 경우에는 조치를 실행하십시오.
Arkiliknam

답변:


18

내가 생각하지 않는 이 개념을 구현하는 허용 방법은,하지만 난 정말 공유하고 싶은 방법 나는 보통 내 게임이 처리합니다. Command 디자인 패턴과 Composite 디자인 패턴 의 조합입니다 .

Update각 프레임이라고 하는 메소드 주위의 래퍼에 불과 Finished하고 액션 실행이 완료되었음을 나타내는 플래그 인 액션에 대한 추상 기본 클래스 가 있습니다.

abstract class Action
{
    abstract void Update(float elapsed);
    bool Finished;
}

또한 복합 디자인 패턴을 사용하여 다른 작업을 호스팅하고 실행할 수있는 작업 유형을 만듭니다. 이것 역시 추상 클래스입니다. 아래로 비등합니다 :

abstract class CompositeAction : Action
{
    void Add(Action action) { Actions.Add(action); }
    List<Action> Actions;
}

그런 다음 병렬 실행순차적 실행 을 위한 복합 작업의 두 가지 구현이 있습니다. 그러나 병렬 및 시퀀스는 작업 자체이므로 더 복잡한 실행 흐름을 만들기 위해 결합 할 수 있다는 것이 장점 입니다.

class Parallel : CompositeAction
{
    override void Update(float elapsed) 
    {
        Actions.ForEach(a=> a.Update(elapsed));
        Actions.RemoveAll(a => a.Finished);
        Finished = Actions.Count == 0;
    }
}

그리고 순차적 인 행동을 지배하는 것.

class Sequence : CompositeAction
{
    override void Update(float elapsed) 
    {
        if (Actions.Count > 0) 
        {
            Actions[0].Update(elapsed);
            if (Actions[0].Finished)
                Actions.RemoveAt(0);
        }
        Finished = Actions.Count == 0;
    }
 }

이를 통해 구체적인 액션 구현을 만들고 ParallelSequence액션을 사용하여 실행 흐름을 제어하는 것만으로도 간단합니다 . 예를 들어 보겠습니다.

// Create a parallel action to work as an action manager
Parallel actionManager = new Parallel();

// Send character1 to destination
Sequence actionGroup1 = new Sequence();
actionGroup1.Add(new MoveAction(character1, destination));
actionGroup1.Add(new TalkAction(character1, "Arrived at destination!"));
actionManager.Add(actionGroup1);

// Make character2 use a potion on himself
Sequence actionGroup2 = new Sequence();
actionGroup2.Add(new RemoveItemAction(character2, ItemType.Potion));
actionGroup2.Add(new SetHealthAction(character2, character2.MaxHealth));
actionGroup2.Add(new TalkAction(character2, "I feel better now!"));
actionManager.Add(actionGroup2);

// Every frame update the action manager
actionManager.Update(elapsed);

나는이 시스템을 사용하여 그래픽 어드벤처에서 모든 게임 플레이를 이끌어 냈지만 아마도 거의 모든 것이 가능할 것입니다. 또한 실행 루프 및 조건을 생성하는 데 사용 된 다른 유형의 복합 작업을 추가 할 수있을 정도로 간단했습니다.


그것은 아주 좋은 해결책처럼 보입니다. 호기심에서 UI를 어떻게 그려야하는지 어떻게 알 수 있습니까? 게임 오브젝트 (캐릭터와 같은)에 렌더링 목적으로 어떤 일이 발생했는지 식별하는 데 사용되는 상태가 포함되어 있습니까?
Arkiliknam

1
일반적으로 내 작업 은 엔터티 의 상태 만 변경하며 렌더링 된 출력에 대한 변경 은 작업 자체가 아니라 해당 상태 변경 의 결과 로 발생 합니다. 예를 들어, 직접 모드 렌더러에서는 Draw메소드가 엔티티 상태 위에 이미 빌드되어 있으며 변경 사항이 자동으로 수행되므로 추가 단계가 필요하지 않습니다 . Flash와 같은 유지 모드 렌더러에서는 관찰 가능 패턴을 사용하여 엔티티 변경 사항을 표시 객체에 전파하거나 엔티티 자체 내부에서 수동으로 연결할 수 있습니다.
David Gouveia

1
첫 번째 상황에서는 Character클래스에 Position속성 이 있고 Draw현재 값이 무엇인지 읽고 Position올바른 이미지를 그리는 메소드 가 있다고 가정 해 봅시다 . 이 경우 Position결과가 화면에 자동으로 표시 되는 값만 업데이트하면 됩니다.
David Gouveia

1
당신이 때 두 번째 상황이다 CharacterPosition속성을하지만, 위임은 어떤 종류의 렌더링을 Sprite자동으로 장면 그래프 또는 무언가에 의해 렌더링되는 객체입니다. 이 상황에서 캐릭터의 위치와 스프라이트의 위치가 항상 동기화되어 있는지 확인해야합니다. 그럼에도 불구하고 액션 매니저가 왜 관련이 있는지 모르겠습니다. :)
David Gouveia

1
두 가지 방법 모두 장단점이 있습니다. 2D 게임을위한 두 번째 방법을 사용했는데 모든 것을 동기화하는 것이 훨씬 더 복잡하기 때문에 때때로 후회했습니다. 그러나 어떤 엔티티가 클릭되었는지 또는 어떤 항목이 그려 져야하는지 감지하려는 경우에도 이점이 있습니다. 렌더링 될 모든 항목이 N 엔티티 유형간에 흩어져 있지 않고 동일한 데이터 구조 내에 포함되기 때문입니다.
데이비드 구 베이 아
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.