LGTM Devlog 27: 분기 퀘스트
16277 단어 pythondevjournalgamedev
단계 실행 루프
이제 스테이지에 실행할 미리 정의된 함수가 있으며 실행은 다음과 같습니다.
prepare()
메서드. 이는 스테이지에서 필요한 데이터를 가져오기 위해 작업을 수행해야 하는 경우를 위한 것입니다condition()
를 실행하여 단계가 실행되어야 하는지 확인합니다. 이 메서드는 스테이지를 실행할 준비가 되었는지 여부를 결정해야 합니다execute()
작업을 수행하기 위해 실행할 수 있습니다is_done()
확인하여 퀘스트 완료 여부를 판단합니다. 몇 가지 에지 조건을 추가로 처리하는 실제 코드입니다.
while self.graph.is_active():
ready_nodes = self.graph.get_ready()
if not ready_nodes:
log.info("No more ready nodes, stopping execution")
break
log.info("Got Ready nodes", ready_nodes=ready_nodes)
for node in ready_nodes:
# skip if completed, avoids triggering two final stages
if self.complete:
log.info("Done flag set, skipping the rest")
return
# completed node: TODO: just not put completed nodes into the graph?
if node in self.completed_stages:
self.graph.done(node)
log.info(
"Node is already complete, skipping",
node=node,
complete=self.completed_stages,
)
continue
log_node = log.bind(node=node)
log_node.info("Begin processing stage")
# instantiate stage and execute
StageClass = self.stages[node]
stage = StageClass(self)
stage.prepare()
if stage.condition():
log_node.info("Condition check passed, executing")
stage.execute()
if stage.is_done():
log_node.info("Stage reports done")
self.completed_stages.append(node)
self.graph.done(node)
log.info("Done processing node")
이 루프를 실행하면 이전 노드가 완료된 후에만 사용할 수 있는 노드를 포함하여 퀘스트 트리의 모든 처리 가능한 부분을 순환합니다.
Stage
추상 기본 클래스는 이제 다음과 같습니다.class Stage(ABC):
@property
@abstractmethod
def children(cls) -> List[str]:
""" List of children nodes of this stage """
return NotImplemented
def prepare(self) -> None:
""" Any preparation for the stage """
return
def condition(self) -> bool:
""" Function that will decide whether to execute """
return True
def execute(self) -> None:
""" Run the stage """
return
def is_done(self) -> bool:
""" Returns whether quest was completed """
return True
def __init__(self, quest: Quest):
self.quest = quest
def __repr__(self):
return f"{self.__class__.__name__}(quest={repr(self.quest)})"
볼 수 있듯이
children
속성만 구현하면 됩니다. 기본적으로 condition()
및 is_done()
재정의되지 않으면 True를 반환합니다.condition()
와 is_done()
가 모두 있는 이유는 다음과 같은 퀘스트를 예로 들 수 있습니다.condition()
이 퀘스트 단계에서 주석을 가져와야 하는지 여부를 결정합니다(일부 알림 트리거에서?). execute()
데이터를 가져오고 값을 확인한 다음 "예, 그랬습니다."또는 "아니요, 옳지 않습니다. 다시 시도하십시오"라는 응답을 보냅니다.is_done()
는 False를 반환하고 플레이어는 진행하지 않으며 다른 시도를 할 수 있습니다. 전자의 경우 is_done()
는 True를 반환하고 플레이어는 다음 단계정황
단계의 조건부 실행을 처리할 수 있는 ConditionStage
라는 새로운 종류의 단계를 추가했습니다. 이것이 없으면 퀘스트를 분기할 수 있지만 분기가 실행되는지 여부는 제어할 수 없습니다. 기본 클래스의 condition()
메서드를 재정의하고 퀘스트 정의가 확인할 퀘스트 데이터 구조의 데이터를 지정할 수 있습니다.
class ConditionStage(Stage):
""" For conditional branch execution """
@property
@abstractmethod
def variable(cls) -> str:
""" Name of the variable to check """
return NotImplemented
# the variable to check against
compare_variable: ClassVar[Optional[str]] = None
# the value to check against, if compare_variable is None
compare_value: ClassVar[Any] = None
# the operator to use comparison on
operator: ClassVar[Callable[..., bool]] = operator.eq
def condition(self) -> bool:
value_left = getattr(self.quest.quest_data, self.variable)
if self.compare_variable is not None:
value_right = getattr(self.quest.quest_data, self.compare_variable)
else:
value_right = self.compare_value
return self.operator(value_left, value_right)
클래스의 구체적인 구현은 다음과 같습니다.
class TestQuestBranching(Quest):
class QuestDataModel(QuestBaseModel):
value_a: int = 1
value_b: int = 2
version = VersionInfo.parse("1.0.0")
difficulty = Difficulty.RESERVED
description = "This is a quest to test branching"
class Start(DebugStage):
children = ["BranchA", "BranchB"]
class BranchA(ConditionStage):
children = ["EndingA"]
variable = "value_a"
compare_variable = "value_b"
class BranchB(ConditionStage):
children = ["EndingB"]
variable = "value_a"
operator = operator.gt
compare_value = 10
class EndingA(FinalStage):
children = []
class EndingB(FinalStage):
children = []
여기에 두 개의 별도 엔딩이 있는 두 개로 분기되는 퀘스트가 있습니다. 첫 번째 분기의 조건은 value_a
== value_b
이고 두 번째 분기의 조건은 value_a
> 10이며, 파이썬의 내장 operator
라이브러리를 사용하여 operator.gt(a, b)
와 같은 비교 방법을 제공합니다.
마지막 스테이지
마지막으로 퀘스트를 완료로 표시하는 방법이 필요합니다. children
가 없는 노드는 단순히 다음 단계를 트리거하지 않지만 퀘스트의 끝을 의미하지 않을 수 있습니다(막다른 지점일 수 있음). 따라서 FinalStage
Stage
의 구체적인 구현은 단순히 퀘스트의 complete
부울을 True로 설정합니다. (퀘스트 데이터 모델의 일부로 이것을 포함하도록 퀘스트 저장소를 리팩토링했습니다.
class FinalStage(Stage):
""" For ending the quest """
def __init_subclass__(cls):
cls.children = []
def execute(self) -> None:
self.quest.complete = True
다양한 루프의 이러한 구체적인 구현을 통해 이제 조건을 충족하고 완료로 표시해야 하는 퀘스트를 수행할 수 있습니다.
Reference
이 문제에 관하여(LGTM Devlog 27: 분기 퀘스트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/meseta/lgtm-devlog-27-branching-quests-kae
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
class ConditionStage(Stage):
""" For conditional branch execution """
@property
@abstractmethod
def variable(cls) -> str:
""" Name of the variable to check """
return NotImplemented
# the variable to check against
compare_variable: ClassVar[Optional[str]] = None
# the value to check against, if compare_variable is None
compare_value: ClassVar[Any] = None
# the operator to use comparison on
operator: ClassVar[Callable[..., bool]] = operator.eq
def condition(self) -> bool:
value_left = getattr(self.quest.quest_data, self.variable)
if self.compare_variable is not None:
value_right = getattr(self.quest.quest_data, self.compare_variable)
else:
value_right = self.compare_value
return self.operator(value_left, value_right)
class TestQuestBranching(Quest):
class QuestDataModel(QuestBaseModel):
value_a: int = 1
value_b: int = 2
version = VersionInfo.parse("1.0.0")
difficulty = Difficulty.RESERVED
description = "This is a quest to test branching"
class Start(DebugStage):
children = ["BranchA", "BranchB"]
class BranchA(ConditionStage):
children = ["EndingA"]
variable = "value_a"
compare_variable = "value_b"
class BranchB(ConditionStage):
children = ["EndingB"]
variable = "value_a"
operator = operator.gt
compare_value = 10
class EndingA(FinalStage):
children = []
class EndingB(FinalStage):
children = []
마지막으로 퀘스트를 완료로 표시하는 방법이 필요합니다.
children
가 없는 노드는 단순히 다음 단계를 트리거하지 않지만 퀘스트의 끝을 의미하지 않을 수 있습니다(막다른 지점일 수 있음). 따라서 FinalStage
Stage
의 구체적인 구현은 단순히 퀘스트의 complete
부울을 True로 설정합니다. (퀘스트 데이터 모델의 일부로 이것을 포함하도록 퀘스트 저장소를 리팩토링했습니다.class FinalStage(Stage):
""" For ending the quest """
def __init_subclass__(cls):
cls.children = []
def execute(self) -> None:
self.quest.complete = True
다양한 루프의 이러한 구체적인 구현을 통해 이제 조건을 충족하고 완료로 표시해야 하는 퀘스트를 수행할 수 있습니다.
Reference
이 문제에 관하여(LGTM Devlog 27: 분기 퀘스트), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/meseta/lgtm-devlog-27-branching-quests-kae텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)