간단한 어드벤처 게임에서 행동 구현


11

나는 간단한 텍스트 기반 어드벤처 게임을 프로그래밍하여 최근에 나 자신을 즐겁게 해왔으며, 매우 단순한 디자인 문제처럼 보입니다.

간단한 개요 : 게임은 여러 Room개체 로 나뉩니다 . 각 객실 Room에는 Entity해당 방 에있는 객체 목록 이 있습니다. 각각 Entity은 간단한 문자열-> 부울 맵인 이벤트 상태와 문자열-> 함수 맵인 조치 목록을 가지고 있습니다.

사용자 입력은 형식을 취합니다 [action] [entity]. 는 Room적절한 반환 단체명을 사용하여 Entity다음 올바른 기능을 찾는 작업 이름을 사용하여 오브젝트를, 그것을 실행한다.

회의실 설명을 생성하기 위해 각 Room객체는 고유 한 설명 문자열을 표시 한 다음 every의 설명 문자열을 추가합니다 Entity. Entity설명은 그 상태에 따라 달라질 수있다 ( 「도어 개방」등, "도어가 잠겨 있습니다」 「도어 폐쇄」).

여기에 문제가 있습니다.이 방법을 사용하면 구현해야하는 설명 및 동작 함수의 수가 빨리 사라집니다. 내 시작 방에만 5 개의 엔티티 사이에 약 20 개의 기능이 있습니다.

모든 작업을 단일 함수로 결합하고 if-else / switch를 통해 전환 할 수 있지만 엔터티 당 여전히 두 가지 기능입니다. Entity문과 열쇠와 같은 공통 / 일반 객체에 대한 특정 하위 클래스를 만들 수도 있지만 지금까지만 가능합니다.

편집 1 : 요청에 따라 이러한 액션 함수의 의사 코드 예제.

string outsideDungeonBushesSearch(currentRoom, thisEntity, player)
    if thisEntity["is_searched"] then
        return "There was nothing more in the bushes."
    else
        thisEntity["is_searched"] := true
        currentRoom.setEntity("dungeonDoorKey")
        return "You found a key in the bushes."
    end if

string dungeonDoorKeyUse(currentRoom, thisEntity, player)
    if getEntity("outsideDungeonDoor")["is_locked"] then
        getEntity("outsideDungeonDoor")["is_locked"] := false
        return "You unlocked the door."
    else
        return "The door is already unlocked."
    end if

설명 함수는 상태를 확인하고 적절한 문자열을 반환하는 것과 거의 같은 방식으로 작동합니다.

편집 2 : 내 질문 문구를 수정했습니다. 다른 행동과 공통 행동 (특정 행동에 대한 상태 기반 반응)을 공유하지 않는 게임 내 객체가 상당수 있다고 가정합니다. 각 엔터티 별 작업에 대해 사용자 지정 함수를 작성하는 것보다 이러한 고유 한 동작을보다 명확하고 유지 관리 가능한 방식으로 정의 할 수있는 방법이 있습니까?


1
이 "액션 함수"의 기능을 설명하고 코드를 게시 할 필요가 있다고 생각합니다.
— jhocking

코드를 추가했습니다.
— Eric

답변:


5

명사와 동사의 모든 조합에 대해 별도의 기능을 만드는 대신 게임의 모든 개체가 구현하는 공통 인터페이스가 하나있는 아키텍처를 설정해야합니다.

내 머리 꼭대기에서 접근하는 한 가지 방법은 게임의 모든 특정 객체가 확장하는 Entity 객체를 정의하는 것입니다. 각 엔티티에는 다른 조치를 다른 결과와 연관시키는 테이블 (언어가 연관 배열에 사용하는 데이터 구조)이 있습니다. 테이블의 동작은 문자열 (예 : "열기") 일 수 있지만 언어가 일급 함수를 지원하는 경우 연결된 결과가 개체의 전용 함수일 수도 있습니다.

마찬가지로 객체의 상태는 객체의 다양한 필드에 저장됩니다. 예를 들어, 부시에 물건 배열을 가질 수 있으며, "검색"과 관련된 함수는 해당 배열에 작용하여 찾은 객체를 반환하거나 "덤불에는 더 이상 아무것도 없었습니다"라는 문자열을 반환합니다.

한편, 공개 메소드 중 하나는 Entity.actOn (String action)과 같습니다. 그런 다음 해당 메소드에서 전달 된 조치를 해당 오브젝트의 조치 테이블과 비교하십시오. 해당 조치가 테이블에 있으면 결과를 리턴하십시오.

이제 각 객체에 필요한 모든 다른 기능이 객체 내에 포함되어 다른 방에서 해당 객체를 쉽게 반복 할 수 있습니다 (예 : 문이있는 모든 방에서 Door 객체를 인스턴스화)

마지막으로 모든 방을 XML 또는 JSON 등으로 정의하면 모든 방마다 별도의 코드를 작성하지 않고도 고유 한 방을 많이 가질 수 있습니다. 게임이 시작될 때이 데이터 파일을로드하고 데이터를 구문 분석하여 게임을 채우는 오브젝트를 인스턴스화하십시오. 다음과 같은 것 :

<rooms>
  <room id="room1">
    <description>Outside the dungeon you see some bushes and a heavy door over the entrance.</description>
    <entities>
      <bush>
        <description>The bushes are thick and leafy.</description>
        <contains>
          <key />
        </contains>
      </bush>
      <door connection="room2" isLocked="true">
        <description>It's an oak door with stout iron clasps.</description>
      </door>
    </entities>
  </room>

  <room id="room2">
    etc.

추가 : 아하, 나는 FxIII의 대답을 읽었으며 끝 부분 근처 에서이 비트가 나에게 튀어 나왔습니다.

(no things like <item triggerFlamesOnPicking="true"> that you will use just once)

불꽃 트랩이 트리거되는 것은 한 번만 발생한다는 것에 동의하지 않지만 (이 트랩이 많은 다른 객체에 재사용되는 것을 볼 수 있습니다) 마침내 사용자 입력에 고유하게 반응하는 엔티티에 대한 의미를 얻습니다. 나는 아마도 당신의 던전에서 하나의 문을 구성 요소 아키텍처 (다른 곳에서 자세히 설명)로 모든 엔티티를 구축하여 불 덩어리 함정을 만드는 것과 같은 문제를 해결할 것입니다.

이런 식으로 각 Door 엔터티는 구성 요소 번들로 구성되며 다른 엔터티간에 구성 요소를 유연하게 혼합 및 일치시킬 수 있습니다. 예를 들어, 대부분의 문은 다음과 같은 구성을 갖습니다.

<entity name="door">
  <description>It's an oak door with stout iron clasps.</description>
  <components>
    <lock isLocked="true" />
    <portal connection="room2" />
  </components>
</entity>

불 덩어리 함정이있는 문은

<entity name="door">
  <description>There are strange runes etched into the wood.</description>
  <components>
    <lock isLocked="true" />
    <portal connection="room7" />
    <fireballTrap />
  </components>
</entity>

그 문을 위해 작성해야 할 유일한 고유 코드는 FireballTrap 구성 요소입니다. 다른 모든 문과 동일한 잠금 및 포털 구성 요소를 사용하고 나중에 보물 상자 또는 FireballTrap 구성 요소를 해당 상자에 추가하는 것만 큼 간단한 방법으로 FireballTrap을 사용하기로 결정한 경우.

컴파일 된 코드 또는 별도의 스크립팅 언어로 모든 구성 요소를 정의하는지 여부는 내 마음에 큰 차이가 없지만 ( 어딘가 에서 코드를 작성하게 될 것입니다) 중요한 것은 크게 줄일 수 있다는 것입니다 작성해야 할 고유 코드의 양. 레벨 디자이너 / 모듈러의 유연성에 대해 걱정하지 않는다면 (이 게임을 직접 작성하는 경우) 모든 엔티티를 엔티티에서 상속하고 구성 파일이나 스크립트가 아닌 생성자에 구성 요소를 추가 할 수도 있습니다. 도대체 무엇이:

Door extends Entity {
  public Door() {
    addComponent(new LockComponent());
    addComponent(new PortalComponent());
  }
}

TrappedDoor extends Entity {
  public TrappedDoor() {
    addComponent(new LockComponent());
    addComponent(new PortalComponent());
    addComponent(new FireballTrap());
  }
}

1
반복 가능한 공통 항목에 적용됩니다. 그러나 사용자 입력에 고유하게 응답하는 엔터티는 어떻습니까? Entity단일 객체에 대한 하위 클래스를 만들면 코드가 함께 그룹화되지만 작성해야하는 코드의 양이 줄어들지는 않습니다. 아니면이 점에서 피할 수없는 함정입니까?
— Eric

1
나는 당신이 제시 한 예를 다루었습니다. 나는 당신의 마음을 읽을 수 없습니다; 어떤 객체와 입력을 원하십니까?
— jhocking 2012 년

내 의도를 더 잘 설명하기 위해 게시물을 수정했습니다. 예제를 올바르게 이해하면 각 엔티티 태그가 일부 하위 클래스에 해당 Entity하고 속성이 초기 상태를 정의 하는 것처럼 보입니다 . 엔터티의 자식 태그가 해당 태그와 관련된 모든 작업에 대한 매개 변수 역할을한다고 생각합니다.
— Eric

그렇습니다, 그것은 아이디어입니다.
— jhocking 2012 년

구성 요소가 솔루션의 일부가 될 것이라고 생각했습니다. 도와 주셔서 감사합니다.
— Eric

1

해결해야 할 치수 문제는 매우 정상이며 거의 피할 수 없습니다. 당신은 일치 하고 유연한 엔티티를 표현하는 방법을 찾고 싶습니다 .

"컨테이너"(점프 답변의 덤불)는 우연한 방법이지만 유연 하지는 않습니다. 충분히 않습니다.

당신은 항상 것 때문에, 일반적인 인터페이스를 찾은 다음 동작을 지정하는 구성 파일을 사용하려고 할하지 않는 것이 좋습니다 불쾌한 감각 이 될 바위 사이 (표준 및 보링 실체는 쉽게 설명하기 위해) 와 힘든 곳을 ( 독창적 인 환상적인 실체이지만 구현하기에는 너무 길다).

내 제안은 통역 언어 를 사용 하는 것 입니다 를 행동을 코딩하는 것입니다.

부시 예를 생각해보십시오. 컨테이너이지만 컨테이너 안에 특정 품목이 있어야합니다. 컨테이너 객체는 다음을 가질 수 있습니다.

  • 스토리 텔러가 아이템을 추가하는 방법
  • 엔진이 포함하는 항목을 표시하는 방법
  • 플레이어가 아이템을 고르는 방법.

이 품목들 중 하나에는 밧줄로 묶여 덤불을 태우는 화염을 발사 할 수있는 밧줄이 있습니다 ...

누군가가 항목을 선택할 때마다 기본 프로그램에서 실행 하는 후크 에 관련 추가 코드를 넣는 구성 파일 대신 스크립트를 사용 하여이 부시를 설명 할 수 있습니다. 컨테이너에서 을 .

코드 아키텍처 또는 스크립팅 언어 (컨테이너, 도어 등)를 사용하여 행동 도구를 기본 클래스로 정의 할 수 있습니다. 목적 theese 것들을 당신이 할 수 있도록하는 것입니다 엔티티 easely 간단한 동작을 집계 설명 과 스크립트 언어에 바인딩을 사용하여 구성을 .

모든 엔터티는 스크립트에 액세스 할 수 있어야합니다. 식별자를 각 엔터티에 연결하고 스크립팅 언어 스크립트의 확장으로 내보내는 컨테이너에 넣을 수 있습니다.

스크립팅 전략을 사용하면 구성을 단순하게 유지 <item triggerFlamesOnPicking="true">하면서 (한 번만 사용하면 안 됨) 코드 행을 추가하는 이상한 행동 (재미있는 행동)을 표현할 수 있습니다

간단히 말해서 : 코드를 실행할 수있는 구성 파일로서의 스크립트.

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