버전 관리를 사용하여 유사한 게임의 게임 코드에서 게임 엔진 분리


15

다른 버전에서는 거절하고 싶은 게임이 완성되었습니다. 이것들은 비슷한 종류의 디자인을 가진 비슷한 게임이지만, 항상 그런 것은 아니지만 기본적으로 상황이 조금씩, 때로는 큰 경우도 있습니다.

핵심 코드를 게임과 별도로 버전 화하고 싶습니다. 따라서 게임 A에서 발견 된 버그를 수정하면 게임 B에 수정 사항이 표시됩니다.

나는 그것을 관리하는 가장 좋은 방법을 찾으려고 노력하고 있습니다. 내 초기 아이디어는 다음과 같습니다.

  • engine일반화 할 수 있고 나머지 게임과 100 % 독립적 인 모든 것을 포함 하는 모듈 / 폴더 / 무엇을 만듭니다 . 여기에는 일부 코드가 포함되지만 게임간에 공유되는 일반 자산도 포함됩니다.
  • 이 엔진을 자체 git저장소 에 넣으면 게임에 포함됩니다.git submodule

내가 고투하고있는 부분은 나머지 코드를 관리하는 방법입니다. 메뉴 장면이 있다고 가정 해 봅시다.이 코드는 게임마다 다르지만 대부분은 일반적이며 다른 게임에서 재사용 할 수 있습니다. 에 넣을 수는 engine없지만 각 게임마다 다시 코딩하는 것은 비효율적입니다.

어쩌면 일종의 자식 분기 변형을 사용하는 것이 효과적 일 수는 있지만 이것이 최선의 방법이라고 생각하지 않습니다.

누구든지 아이디어 나 경험이 있거나 그것에 대해 뭔가가 있습니까?


엔진에 어떤 언어가 있습니까? 일부 언어에는 git 하위 모듈을 사용하는 것보다 더 적합한 전용 패키지 관리자가 있습니다. 예를 들어 NodeJS에는 npm이 있습니다 (Git 저장소를 소스로 지정할 수 있음).
Dan Pantry

일반 코드를 구성하는 가장 좋은 방법이나 "반-일반"코드를 구성하는 방법 또는 코드를 구성하는 방법, 코드를 디자인하는 방법 또는 무엇에 대한 질문이 있습니까?
덩크

이는 각 프로그래밍 언어 환경에 따라 다를 수 있지만 제어 버전 소프트웨어뿐만 아니라 게임 엔진에서 게임 코드 (패키지, 폴더 및 API 등)를 분리하는 방법부터 시작하는 방법을 알고 있어야합니다. 제어 버전을 적용하십시오.
umlcat

하나의 브랜치에서 한 폴더의 클린 히스토리를 만드는 방법 : 별도의 (미래) 리포지토리가 별도의 폴더에 있도록 엔진을 리팩터링하여 마지막 커밋입니다. 그런 다음 새 분기를 만들고 해당 폴더 외부의 모든 항목을 삭제하고 커밋하십시오. 그런 다음 리포지토리의 첫 번째 커밋으로 이동하여 새 분기와 병합하십시오. 이제 해당 폴더 만있는 브랜치가 있습니다. 다른 프로젝트에서 가져 오거나 기존 프로젝트와 다시 병합하십시오. 코드가 이미 분리 된 경우 분기에서 엔진을 분리하는 데 많은 도움이되었습니다. 자식 모듈이 필요하지 않습니다.
Barry Staes

답변:


13

일반화 할 수 있고 나머지 게임과 100 % 독립적 인 엔진 모듈 / 폴더 / 무엇이든 생성하십시오. 여기에는 일부 코드가 포함되지만 게임간에 공유되는 일반 자산도 포함됩니다.

이 엔진을 자체 자식 저장소에 넣습니다. 자식 저장소는 게임에 자식 하위 모듈로 포함됩니다.

그것이 바로 내가하는 일이며 매우 잘 작동합니다. 나는 응용 프로그램 프레임 워크와 렌더링 라이브러리를 가지고 있으며, 각각은 내 프로젝트의 하위 모듈로 취급됩니다. SourceTree를 찾습니다 는 서브 모듈에 관해서는 잘 관리하고 아무것도 잊어 버리지 않기 때문에 서브 모듈에 유용하다는 습니다.

경험이 있으면 엔진에 어떤 코드가 있어야하는지, 프로젝트마다 무엇이 있어야하는지에 대한 지식이옵니다. 약간 확실하지 않다면 지금 당장 각 프로젝트에 보관하는 것이 좋습니다. 시간이 지남에 따라 다양한 프로젝트 중에서 동일한 것이 무엇인지 알 수 있으며 점차 엔진 코드에 반영 할 수 있습니다. 다시 말해, 프로젝트마다 개별적으로 변경되지 않을 것으로 100 %에이를 때까지 코드를 복제 한 다음 일반화하십시오.

소스 제어 및 이진에 대한 참고 사항

바이너리 자산이 자주 변경 될 것으로 예상되는 경우 git과 같은 텍스트 기반 소스 제어에 넣지 않을 수 있습니다. 이진에 대한 더 나은 솔루션이 있습니다. "engine-source"리포지토리를 깨끗하고 성능있게 유지하기 위해 지금 할 수있는 가장 간단한 일은 바이너리 만 포함하는 별도의 "engine-binaries"리포지토리를 갖는 것입니다.이 바이너리는 프로젝트의 하위 모듈로 포함됩니다. 이렇게하면 "엔진 소스"리포지토리에 대한 성능 손상을 완화 할 수 있습니다.이 변경은 항상 변경되어 커밋, 푸시, 풀 등의 빠른 반복이 필요합니다. git와 같은 소스 제어 관리 시스템은 텍스트 델타에서 작동합니다. 바이너리를 도입하자마자 텍스트 관점에서 막대한 델타를 도입하여 시간이 많이 걸립니다.GitLab Annex . Google 친구입니다.


그들은 자주 바뀌지 않지만, 나는 그것에 관심이 있습니다. 이진 버전 관리에 대해서는 아무것도 모른다. 어떤 솔루션이 있습니까?
Malharhak

@Malharhak 귀하의 의견에 답변을 편집했습니다.
엔지니어

@Malharak 다음은 이 주제에 대한 유용한 정보 입니다.
엔지니어

1
프로젝트 내에서 가능한 한 오래 유지하기 위해 +1 공통 코드는 더 높은 복잡성을 부여합니다. 절대적으로 필요할 때까지 피해야합니다.
Gusdor

1
@Malharhak 아니요, 특히 귀하의 목표는 해당 코드가 변경 불가능하고 일반적인 것으로 간주 될 수있을 때까지 "사본"을 유지하는 것입니다. Gusdor는 이것을 반복해서 경고했다-너무 일찍 물건을 계산하여 쉽게 많은 시간을 낭비한 다음, 코드를 일반적으로 유지하면서도 다양한 프로젝트에 맞출 수있을 정도로 적응력을 유지할 수있는 방법을 찾으려고 노력했다. 전체 매개 변수와 스위치의 많은 그것은 아직도 당신이 새로운 프로젝트 당을 변경 한 내용 때문에 당신이 필요 아니라고 못생긴 엉망으로 변 어쨌든 . 너무 일찍 고려하지 마십시오 . 인내심을 가지십시오.
엔지니어

6

어떤 시점에서 엔진은 게임에 대한 전문 지식과 지식을 가져야합니다. 나는 여기서 접선을 떠날 것이다.

RTS에서 자원을 가져 가십시오. 하나 개의 게임이있을 수 있습니다 CreditsCrystal다른 MetalPotatoes

OO 개념을 올바르게 사용하고 최대한 활용해야합니다. 코드 재사용. Resource여기에 개념이 존재 한다는 것이 분명합니다 .

따라서 우리는 자원이 다음과 같이 결정합니다.

  1. 스스로 증가 / 감소시키는 메인 루프의 고리
  2. 현재 금액을 얻는 방법 (을 반환 int)
  3. 임의로 빼거나 추가하는 방법 (리소스를 이동하는 플레이어, 구매 ....)

이 개념은 Resource게임에서 킬이나 포인트를 나타낼 수 있습니다! 매우 강력하지 않습니다.

이제 게임에 대해 생각해 봅시다. 동전을 처리하고 출력에 소수점을 추가하여 일종의 통화를 할 수 있습니다. 우리가 할 수없는 것은 "순간적인"자원입니다. "전력망 생성"과 같이

InstantResource비슷한 방법 으로 클래스 를 추가한다고 가정 해 봅시다 . 이제 리소스로 엔진을 오염시키고 있습니다.


문제

RTS 예제를 다시 보자. 플레이어 Crystal가 다른 플레이어에게 어떤 것을 기부한다고 가정하십시오 . 당신은 다음과 같은 것을하고 싶습니다 :

if(transfer.target == engine.getPlayerId()) {
    engine.hud.addIncoming("You got "+transfer.quantity+" of "+
        engine.resourceDictionary.getNameOf(transfer.resourceId)+
        " from "+engine.getPlayer(transfer.source).name);
}
engine.getPlayer(transfer.target).getResourceById(transfer.resourceId).add(transfer.quantity)
engine.getPlayer(transfer.source).getResourceById(transfer.resourceId).add(-transfer.quantity)

그러나 이것은 정말 지저분합니다. 일반적인 목적이지만 지저분합니다. 이미 a resourceDictionary를 부과하지만 이제는 리소스에 이름이 있어야 함을 의미합니다! 그리고 그것은 플레이어 당이므로 더 이상 팀 리소스를 가질 수 없습니다.

이것은 "너무 많은"추상화 (내가 인정할 훌륭한 예가 아님) 대신 게임에 플레이어와 크리스탈이 있다는 점을 받아 들여야한다 (예를 들어).

engine.getPlayer(transfer.target).crystal().receiveDonation(transfer)
engine.getPlayer(transfer.source).crystal().sendDonation(transfer)

의 객체가 기부금의 이체 / 송금을 위해 HUD에 물건을 자동으로 표시 하는 클래스 Player및 클래스가 CurrentPlayer있는 경우 .CurrentPlayercrystal

이것은 크리스탈, 크리스탈 기부, 현재 플레이어를위한 HUD 메시지 등으로 엔진을 오염시킵니다. 더 빠르고 읽기 / 쓰기 / 유지 관리가 더 빠릅니다 (훨씬 빠르지 않기 때문에 더 중요합니다)


최종 비고

리소스 사례는 훌륭하지 않습니다. 그래도 요점을 볼 수 있기를 바랍니다. 어떤 경우에 나는 것을 증명하고있다 "자원 엔진에 속하지 않는" 특정 게임의 요구와 어떤 자원의 모든 개념에 적용이 매우 다른 것을 무엇으로. 일반적으로 3 (또는 4) 개의 "레이어"가 있습니다.

  1. "핵심"-엔진의 교과서 정의, 이벤트 후크가 포함 된 장면 그래프, 쉐이더 및 네트워크 패킷 및 플레이어의 추상 개념을 다룹니다.
  2. "GameCore"-RTS의 리소스 또는 FPS의 탄약과 같은 게임 유형에 일반적이지만 모든 게임에 해당되는 것은 아닙니다. 게임 로직이 여기에 스며 들기 시작합니다. 이것은 우리의 초기 자원 개념이있는 곳입니다. 대부분의 RTS 리소스에 적합한 내용을 추가했습니다.
  3. "GameLogic"실제 게임에 따라 다릅니다. 이름이 creatureor ship또는 같은 변수가 있습니다 squad. 사용 상속 3 층에 걸쳐 수업거야 당신이 (예를 들어 것은 Crystal A는 Resource 어떤 A는 GameLoopEventListener 말)
  4. "자산"은 다른 게임에는 쓸모가 없습니다. 반감기 2의 AI 스크립트 결합을 예로 들어, 동일한 엔진을 가진 RTS에서는 사용되지 않습니다.

오래된 엔진에서 새로운 게임 만들기

이것은 매우 일반적입니다. 1 단계는 레이어 3과 4를 제거하는 것입니다 (게임이 완전히 다른 유형 인 경우 2). 이전 RTS에서 RTS를 만들고 있다고 가정합니다. 우리는 여전히 크리스탈과 재료가 아닌 리소스를 가지고 있습니다. 따라서 레이어 2와 1의 기본 클래스는 여전히 의미가 있습니다 .3과 4에서 참조 된 크리스탈은 모두 버릴 수 있습니다. 우리는 그렇게합니다. 그러나 우리는 그것을 우리가하고 싶은 것에 대한 참조로 확인할 수 있습니다.


층 1의 오염

이런 일이 일어날 수 있습니다. 추상화와 성능은 적입니다. 예를 들어 UE4는 최적화 된 구성 사례를 많이 제공합니다 (따라서 X와 Y를 원한다면 누군가가 X와 Y를 함께 빠르게 처리하는 코드를 작성했습니다. 두 가지를 모두 수행한다는 것을 알고 있습니다). 이것은 나쁘지 않지만 시간이 많이 걸립니다. 레이어 1은 "데이터를 셰이더에 전달하는 방법"및 사물을 애니메이션하는 방법과 같은 것을 결정합니다. 프로젝트에 가장 적합한 방법은 항상 좋습니다. 미래를 위해 노력하고 계획하십시오. 코드를 재사용하는 것이 친구입니다.


레이어 분류

마지막으로 (나는 약속한다) 레이어를 너무 두려워하지 마십시오. 엔진은 예전의 고정 기능 파이프 라인의 오래된 용어로, 엔진은 그래픽 방식으로 거의 같은 방식으로 작동했으며 (결과적으로 많은 공통점이 있음) 프로그래밍 가능한 파이프 라인이이를 머리에서 돌리고 "레이어 1"이 오염되었습니다. 개발자가 원하는 효과를 AI는 엔진의 차별화 된 기능 (수많은 접근법 때문에)이었으며 이제는 AI와 그래픽입니다.

이 레이어에 코드를 제출해서는 안됩니다. 유명한 언리얼 엔진조차도 게임마다 다른 많은 버전이 있습니다. 변경되지 않은 파일 구조 (데이터 구조가 아닌 것 등)는 거의 없습니다. 이건 괜찮아! 다른 게임에서 새 게임을 만들려면 30 분 이상 걸립니다. 핵심은 계획, 복사 및 붙여 넣을 비트 및 남겨 둘 비트를 아는 것입니다.


1

일반 콘텐츠와 특정 콘텐츠가 혼합 된 콘텐츠를 처리하는 방법에 대한 개인적인 제안은 콘텐츠를 동적으로 만드는 것입니다. 메뉴 화면을 예로 들어 보겠습니다. 내가 원하는 것을 잘못 이해했다면 알고 싶은 것이 무엇인지 알려 주시면 답변을 수정하겠습니다.

메뉴 장면에는 배경, 게임 로고 및 메뉴 자체의 3 가지가 있습니다. 이것들은 보통 게임에 따라 다릅니다. 이 콘텐츠를 위해 할 수있는 일은 엔진에 MenuScreenGenerator를 만드는 것입니다. BackScreen, Logo 및 Menu의 3 가지 개체 매개 변수를 사용합니다. 이 세 부분의 기본 구조는 엔진의 일부이지만 엔진은 실제로 이러한 부분이 어떻게 생성되는지 말하지 않고 매개 변수를 지정해야합니다.

그런 다음 실제 게임 코드에서 BackGround, 로고 및 메뉴에 대한 개체를 만들고이를 MenuScreenGenerator에 전달합니다. 다시 말하지만, 게임 자체는 메뉴가 생성되는 방식을 처리하지 않습니다. 그것은 엔진을위한 것입니다. 게임은 엔진에게 모양과 위치를 알려 주면됩니다.

기본적으로 엔진은 게임이 표시 할 내용을 알려주는 API 여야합니다. 올바르게 수행하면 엔진이 열심히해야하며 게임 자체는 엔진에 사용할 자산, 취해야 할 조치 및 세상 모습 만 알려야합니다.

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