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


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.