결합 할 수있는 다양한 공격 유형을 어떻게 설계 할 수 있습니까?


17

하향식 2D 게임을 만들고 있으며 다양한 공격 유형을 원합니다. The Isaac of Binding이 작동하는 방식으로 공격을 매우 유연하고 결합 가능하게 만들고 싶습니다. 게임의 모든 수집품 목록은 다음과 같습니다 . 좋은 예를 찾으려면 Spoon Bender 항목을 살펴보십시오 .

숟가락 벤더는 이삭에게 귀환 눈물을 쏠 수있는 기능을 제공합니다.

"시너지 효과"섹션을 보면 흥미롭지 만 직관적 인 효과를 위해 다른 수집품과 결합 될 수 있습니다. 예를 들어, Inner Eye 와 결합 하면 "Isaac에서 여러 개의 원점 촬영 샷을 한 번에 발사 할 수 있습니다". 내면의 눈 때문에

아이작에게 트리플 샷 제공

이와 같은 것을 디자인하기에 좋은 아키텍처는 무엇입니까? 무차별 대입 솔루션은 다음과 같습니다.

if not spoon bender and not the inner eye then ...
if spoon bender and not the inner eye then ...
if not spoon bender and the inner eye then ...
if spoon bender and the inner eye then ...

그러나 그것은 매우 빨리 벗어날 것입니다. 이와 같은 시스템을 설계하는 더 좋은 방법은 무엇입니까?


개인적으로 나는 모든 장비를 목록에 보관하고 객체에서 객체로 변경하는 객체를 취하는 일종의 공통 인터페이스를 구현하게합니다. "각 아이템에 대해 계획된 공격 수정"을 통해 하나의 아이템이 발사체의 양을 복제 할 수 있고, 색조를 추가하고 피해를 변경할 수 있습니다. . 계획된 공격을 수정하는 방법을 결정하는 매개 변수가있는 하나의 일반 항목 클래스를 가질 수도 있습니다.
Benjamin Danger Johnson 22

2
나는 점을 지적하고 싶습니다 커비 (64) 이 행할 수 있도록 무차별 착수했습니다과 능력의 가능한 모든 조합에 대해 서로 다른 효과를 하드 프로그램.
Kevin

답변:


16

조합을 직접 코딩 할 필요는 없습니다. 대신 각 항목이 제공하는 속성에 집중할 수 있습니다. 예를 들어, 항목 A가 설정합니다 Projectile=Fireball,Targetting=Homing. 항목 B 세트 FireMode=ArcShot,Count=3. 그만큼ArcShot 논리는 아크에서 Count많은 수의 Projectile항목 을 전송합니다 .

이 두 항목은이 (또는 다른) 속성을 자유롭게 수정하는 다른 항목과 결합 할 수 있습니다. 새로운 유형의 발사체를 추가하면 자동으로 만 작동 ArcShot하고 새로운 발사 모드를 추가하면 자동으로 Fireball발사체 와 함께 작동 합니다. 마찬가지로, Targetting발사체를위한 컨트롤러를 설정하는 동시에 발사체를 FireMode생성 하는 속성 이므로 이해하기 쉬운 조합으로 쉽고 간단하게 결합 할 수 있습니다.

속성 종속성 등을 설정할 수도 있습니다. 예를 들어 ArcShot공급자가 Projectile있어야합니다 (기본값 일 수 있음). Projectile코드를 제공 하는 두 개의 활성 항목이있는 경우 사용할 항목을 알 수 있도록 우선 순위를 설정할 수 있습니다 . 또는 UI를 제공하여 사용자가 사용할 발사체 유형을 선택하거나 플레이어가 원하지 않는 우선 순위가 높은 항목을 해제하거나 가장 최근 항목을 사용하도록 요구할 수 있습니다. 비 호환성 시스템을 추가로 허용 할 수 있습니다 예를 들어 둘 다 수정하는 두 항목을 Projectile동시에 장착 할 수 없습니다.

일반적으로 가능한 경우 게임과 같은 오브젝트와 관련하여 절차 적 접근 방식 (큰 경우 혼잡 한 방식 )보다 데이터 중심 접근 방식 (또는 선언적 )을 선호합니다 . 간단한 데이터로 구성 할 수있는 더 높은 수준의 일반 논리가 하드 코딩 된 특수 사례 규칙 목록보다 훨씬 좋습니다.


작은 니트이지만 사용중인 예제에 올바른 속성이없는 것 같습니다. "Spoon Bender"는 원점 복귀를 추가하고 "Inner Eye"는 트리플 샷을 추가합니다. 호를 추가하거나 둘 다 눈물이 아닙니다. 예제에서 임의의 속성을 사용하여 디자인을 추상화하는 경우 잘못된 이름으로 이름이 지정되지 않은 경우 읽기가 더 쉽습니다. "Item A"와 "Item B"를 선호합니다.
Daniel Kaplan

1
@tieTYT : 나는 이름을 일반화하고 발사체 유형과 발사 모드 외에도 타겟팅 모드를 포함하도록 예제를 확장했습니다. 몇 분 이상 BoI를 연주 한 적이 없으므로 다른 사람들처럼 내면화 된 이름이 없습니다. :)
Sean Middleditch 2013 년

까다로운 부분은 속성 범주를 식별하는 것 같습니다. 예 : 타겟팅은 하나, FireMode는 다른 것, 개수는 3 일 수도 있고 그렇지 않을 수도 있습니다. 어쩌면 3 발의 발사체는 화염 구가 될 수 있고 5 발은 수류탄이 될 수 있습니다.
Daniel Kaplan

@tieTYT : 물론입니다. 특별한 조합이나 논리를 허용하도록 시스템을 추가로 확장 할 수 있지만 규칙보다는 예외 여야합니다. 코너 케이스가 아닌 일반적인 케이스에 맞게 최적화하십시오.
Sean Middleditch

다음은 절차 적 프로그래밍 youtu.be/QM1iUe6IofM 과 관련하여 왜 틀린지에 대한 훌륭한 비디오입니다 . 또한 설명하는 데이터 기반 방식은 if / else 블록을 개별 데이터 세트에 매핑하여 본질적으로 필요한 특수 시나리오 수를 줄이기 위해 아무것도 수행하지 않습니다. 프로그램, 당신은 ... 그들 모두를 프로그램 가지고
RenaissanceProgrammer

8

OOP 언어를 사용하는 경우 Decorator Pattern 을 사용하는 것이 좋습니다 . 공격이 발생하는 방식을 수정하려면 적절한 기능으로 공격을 꾸미십시오.

조잡한 C ++ 예 :

class AttackBehaviour
{
    /* other code */
    virtual void Attack(double angle);
};

class TearAttack: public AttackBehaviour
{
    /* other code */
    void Attack(double angle);
};

class TripleAttack: public AttackBehaviour
{
    /* other code */
    AttackBehaviour* baseAttackBehaviour;
    void Attack(double angle);
};

void TripleAttack::Attack(angle)
{
    baseAttackBehaviour->Attack(angle-30);
    baseAttackBehaviour->Attack(angle);
    baseAttackBehaviour->Attack(angle+30);
}

이 방법은 매우 많은 수의 공격이 있고 모두 같은 방식으로 공격을 수행해야하는 경우에 가장 좋습니다. 수정자가 공격을하는 방식 (예 : 수정자가있는 새로운 애니메이션)을 크게 바꾸려면이 방법이 적합하지 않습니다.


애니메이션을 바꾸고 싶은 이유는 무엇입니까? 더 기능적인 언어로 작업하고 있다면 어떻게해야합니까? 자신에게 적합한 디자인 패턴을 알고 있습니까?
Daniel Kaplan

수정자는 항상 Attack집계하는 객체 의 메소드를 호출하기 때문에 더욱 엄격합니다 . TripleAttack클래스에 대해 알고 안 TearAttack클래스입니다. 이것이 사실이라면 그것은 else-if블록 만큼 많은 두통으로 이어질 것 입니다. 이것은 모든 눈물 애니메이션이 TearAttackBehaviour객체 안에 있어야 함을 의미 합니다. 이 객체는 객체로 장식되었다는 것을 알지 못합니다 TripleAttack. 그 결과 독립적 인 3 개의 인열 애니메이션 독립적으로 진행 됩니다.
NauticalMile

다른 사람이 찌르기를 원한다면 내 손님이 되십시오.
NauticalMile

더 기능적인 언어로 이것을 구현하는 것에 관해서는, 나는 잠시 동안 그것에 대해 생각하고 준비가되면 대답을 수정합니다.
NauticalMile

1

아이작 바인딩의 팬으로서, 나도 이와 같은 일을 어떻게해야하는지 궁금했습니다. 게임의 시스템은 효과의 조합에서 나오는 비발 한 행동이 발생할 때 충분히 견고합니다 (내 마음에 오는 것은 거울, 숟가락 벤더 및 일부 범위 부스터로 인해 Isaac, Magneto 스타일 주위에 소용돌이 치는 홈 찢는 벽이 생깁니다. ). 그들 중 다수는 "if"블록을 비실용적으로 만들 것입니다.

나의 결론은 Isaac과 그의 눈물이 방대한 구성 요소-체 프레임 워크 의 중심에있는 두 개체라는 것이다 . 엔티티에는 몇 가지 기본 통계 (이동 속도, 수명, 범위, 손상, 스프라이트 등)가 있으며 각 구성 요소는 통계 수정 자와 동사를 가져옵니다.

코드에서 이삭과 그의 눈물은 각각 인터페이스의 내용을 포함하는 목록을 갖습니다. Isaac은 IsaacMutator 인터페이스에 가입 한 것들과 tearMutator의 목록을 가지고있을 것입니다. IsaacMutator는 Isaacs의 건강, 속도, 범위, 외모 및 특수 동사를 수정하는 기능을 갖습니다. TearMutator도 비슷합니다. 게임 루프마다 한 번, Isaac은 가지고있는 모든 IsaacMutator를 반복하고 모든 살아있는 눈물도 반복합니다. 영어 예를 들어 보면 다음과 같습니다.

Isaac has IsaacMutators:
--spoonbender which gives no stat change and: Tears are made homing
--MeatEater which give +1 health, +1 damage and: nothing
--MagicMirror which gives no stat change and: Tears are made reflecting

Tears have tearMutators:
--(depends on MeatEater) +1 damage and: nothing
--(depends on MagicMirror) no stat change and: +1 vector towards isaac
--(depnds on spoonbender) no stat change and: +1 vector towards enemytype

등등. 유형은 부가 적이므로 하트 컨텐츠를 쌓아 추가하고 제거 할 수 있습니다.


-5

나는 당신의 방법이 가장 효과적이라고 생각합니다. 이러한 종류의 항목은 각각 조건을 제공하며, 함께 사용될 경우 서로 다른 조건을 생성하면 3 가지 가능한 조건을 효과적으로 정의해야합니다.

두 항목이 모두있을 때 새로운 유형의 정의를 작성하여 문제를 해결할 수도 있지만 실제로는 회선에 추가됩니다.

if spoon bender and the inner eye then new spoon bender inner eye

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