카테고리 보관물: 게임개발

게임개발

Minecraft의 제작 그리드와 같은 것을 어떻게 구현할 수 있습니까? 다이아몬드 보석을 사용할 수 있습니다. 패턴 내에서의 상대적

Minecraft제작 시스템은 2×2 또는 3×3 그리드를 사용합니다. 그리드에 재료를 놓고 올바른 재료를 올바른 패턴에 넣으면 레시피가 활성화됩니다.

디자인에 대한 몇 가지 흥미로운 점 :

  • 일부 레시피는 특정 재료를 다른 재료와 교환 할 수 있습니다. 예를 들어, 은 손잡이에 막대기를 사용하고 머리에는 나무 판자, 조약돌, 철 주괴, 금 주괴 또는 다이아몬드 보석을 사용할 수 있습니다.
  • 패턴 내에서의 상대적 위치는 그리드의 절대 위치가 아니라 중요합니다. 즉, 스틱과 석탄 (또는 숯)을 3×3 그리드의 6 개 위치 중 올바른 패턴으로 배치하여 토치 를 만들 수 있습니다 .
  • 패턴이 가로로 뒤집힐 수 있습니다.

나는 그것을 너무나 생각할지도 모르지만 이것은 흥미로운 검색 / 설정 감소 문제처럼 보입니다. 그렇다면 알고리즘 적으로 말하면 어떻게 작동합니까?



답변

또 다른 해결책은 다소 복잡한 트리를 사용하는 것입니다. 트리에서 브랜치 노드는 레시피를 반복하여 생성합니다 (다시 한번 사용 for (y) { for (x) }). 이것은 재고 표준 책별 트리 구조입니다. 최종 노드에는 치수를 레시피에 매핑 하는 추가 구조 ( Dictionary/ HashMap)가 포함됩니다.

본질적으로 당신이하려고하는 것은 이것입니다 :

레시피 트리

검은 색 노드는 항목 유형을 나타내는 브랜치입니다. 빨간색 노드는 크기 / 방향을 구별 할 수있는 나뭇잎 (터미네이터)입니다.

이 트리를 검색하려면 먼저 경계 상자를 찾은 다음 ( 첫 번째 답변에 설명 된 대로) 이동하는 동안 트리를 통과하는 순서와 동일한 순서로 노드를 반복합니다. 마지막으로 단순히 치수를 찾 Dictionary거나 HashMap레시피 결과를 얻습니다.

발차기를 위해 나는 이것을 가서 구현했습니다 . 아마도 내 대답을 분명히 할 것입니다. 또한 : 나는 이것이 다른 대답이라는 것을 알고 있습니다. 정확히 다릅니다 : 그것은 다른 해결책입니다.


답변

Minecraft는 매우 작은 가능한 레시피 세트 만 사용하므로 그 어떤 것도 필요하지 않습니다.

그것은 내가 할 일은 맞는 가장 작은 격자를 찾는 것입니다 (즉, 빈 행과 열을 무시하여 2×2 또는 3×3 또는 2×3 (문)인지 확인하십시오). 그런 다음 해당 크기의 레시피 목록을 반복하여 항목 유형이 같은지 확인하십시오 (즉, 항목 및 블록에 정수 유형 ID를 사용하므로 minecraft에서 최악의 9 개의 정수 비교). 일치를 찾으면 중지하십시오.

이 방법은 또한 아이템의 상대적 위치를 무의미하게 만듭니다 (크래프팅 그리드의 어느 곳에 나 토치를 넣을 수 있으며 대부분 비어있는 3×3 상자가 아닌 1×2 상자로 보이므로 작동합니다).

가능한 일치 항목을 통해 선형 검색을 수행하는 데 많은 양의 레시피가있는 경우 목록을 정렬하고 이진 검색 (O (log (N)) 대 O (N))을 수행 할 수 있습니다. 이로 인해 목록을 작성하는 데 약간의 추가 작업이 발생하지만 시작시 한 번 수행하고 나중에 메모리에 유지할 수 있습니다.

또한 레시피를 가장 간단하게 뒤집을 수있게하는 마지막 한 가지 방법은 미러 버전을 목록에 추가하는 것입니다.

두 번째 레시피를 추가하지 않고 입력 레시피를 입력하려는 경우 입력 레시피에 [0,2]보다 ID가 높은 [0,0]의 항목이 있는지 (2×2의 경우 [0,1]인지 확인하지 않아도 됨) 확인할 수 있습니다. 1×2의 경우, 만약 그렇다면, 다음 행을 계속 확인하지 않으면 끝까지 도달 할 수 있습니다.이를 사용하여 레시피가 올바른 회전으로 추가되었는지 확인해야합니다.


답변

3×3 그리드를 문자열로 인코딩하고 정규식 일치를 사용 하면 특정 그리드 구성이 특정 레시피와 일치하는지 확인하는 것이 간단합니다 . 조회 속도를 높이는 것은 다른 문제이며 결국 이야기하겠습니다. 자세한 내용은 계속 읽으십시오.

1 단계) 그리드를 문자열로 인코딩

각 셀 유형에 문자 ID를 지정하고 다음 순서대로 모든 항목을 나란히 연결하십시오.

123
456 => 123456789
789

보다 구체적인 예로, W는 나무를 나타내고 E는 빈 셀입니다 (빈 문자 ”를 사용할 수 있음).

EEE
WEE => EEEWEEWEE
WEE

2 단계) 정규 표현식 (또는 문자열을 사용하여 레시피 일치) 데이터에 약간의 처리가 포함되어 있습니다.

위의 예에서 계속해서, 우리가 포메이션을 움직여도 문자열에는 여전히 패턴이 있습니다 (양쪽에 E로 채워진 WEEW).

EEW
EEW => EEWEEWEEE
EEE

따라서 스틱을 어디에서 움직여도 여전히 다음 정규식과 일치합니다. /^E*WEEWE*$/

정규식을 사용하면 언급 한 조건부 동작을 수행 할 수도 있습니다. 예를 들어 (레시피 구성) 철 이나 석재로 만든 곡괭이가 같은 결과 를 원할 경우 :

III    SSS
EWE or EWE
EWE    EWE

정규식으로 두 가지를 결합 할 수 있습니다. /^(III)|(SSS)EWEEWE$/

수평 플립도 마찬가지로 쉽게 추가 할 수 있습니다 (연산자를 사용하여).

편집 : 어쨌든 정규 표현식 부분이 꼭 필요한 것은 아닙니다. 단일 식으로 문제를 캡슐화하는 한 가지 방법 일뿐입니다. 그러나 가변 위치 문제의 경우 모든 패딩 공간 (또는이 예제에서 E)의 그리드 문자열을 자르고 String.Contains ()를 수행 할 수 있습니다. 그리고 다중 성분 문제 또는 미러 된 레시피의 경우, 동일한 출력을 가진 모든 (즉, 별도의) 레시피로 모든 것을 처리 할 수 ​​있습니다.

3 단계) 조회 속도 향상

검색을 줄이려면 레시피를 그룹화하고 조회에 도움이되는 일부 데이터 구조를 작성해야합니다. 그리드를 문자열로 취급하면 여기에도 몇 가지 장점이 있습니다 .

  1. 비어 있지 않은 첫 번째 문자와 비어 있지 않은 마지막 문자 사이의 거리로 레시피의 “길이”를 정의 할 수 있습니다. 간단한 Trim().Length()정보 만 제공하면됩니다. 레시피는 길이별로 그룹화하여 사전에 저장할 수 있습니다.

    또는

    “길이”의 다른 정의는 비어 있지 않은 문자 수입니다. 다른 것은 변하지 않습니다. 이 기준에 따라 레시피를 그룹화 할 수도 있습니다.

  2. 포인트 번호 1이 충분하지 않은 경우 레시피는 레시피에 나타나는 첫 번째 재료의 유형별로 그룹화 될 수 있습니다. 이것은 수행하는 것만 큼 간단합니다 Trim().CharAt(0)(그리고 트림을 방지하여 빈 문자열을 생성 함).

예를 들어 레시피는

Dictionary<int, Dictionary<char, List<string>>> _recipes;

그리고 다음과 같이 조회를 수행하십시오.

// A string encode of your current grid configuration 
string grid;

// Get length and first char in our grid
string trim = grid.Trim();
int length = trim.Length();
char firstChar = length==0 ? ' ' : trim[0];

foreach(string recipe in _recipes[length][firstChar])
{
    // Check for a match with the recipe
    if(Regex.Match(grid, recipe))
    {
        // We found a matching recipe, do something with it
    }
}


답변

Minecraft가 어떻게 작동하는지 말할 수는 없지만 MCP (법적 사본이 Minecraft가있는 경우)를 보더라도 확실하게 알 수 있습니다.

나는 이것을 다음과 같이 구현할 것이다.

  1. 디스크 기반 사전 / 해시 맵 ( B + Tree / SQL-Light )이 있어야합니다. 값은 레시피 결과의 항목 ID입니다.
  2. 사용자가 뭔가 공예되면 단순히 항목을 가지고있는 첫 번째 행 / 열 찾을 독립적를 ; 그것들을 오프셋으로 결합하십시오.
  3. 항목이있는 마지막 행 / 열을 다시 독립적으로 찾으십시오.
  4. 항목에서 너비와 높이를 계산하여 키에 추가하십시오.
  5. 방금 계산 한 경계 상자 범위를 반복하고 각 항목의 ID를 추가하십시오 (일반적인 사용 for (y) { for (x) }).
  6. 데이터베이스에서 키를 찾으십시오.

예를 들어 두 가지 성분이 있다고 가정하겠습니다. X 및 Y 및 공백은 *입니다. 다음 레시피를 사용하십시오.

**X
**Y
**Y

먼저 경계 상자를 해결하여을 산출 (2,0)-(2,2)합니다. 따라서 키는 다음과 같습니다 [1][3](1 너비, 3 높이). 다음으로 우리는 경계 상자 내의 각 항목을 반복하고 ID를 추가하여 키가됩니다 [1][3][X][Y][Y]-그런 다음 사전 / DB에서 이것을 조회하면 해당 레시피의 결과를 얻습니다.

2 단계의 독립성을보다 명확하게 설명하려면 다음 레시피를 고려하십시오.

*XX
XXX
XX*

상단 / 왼쪽은 분명히 0,0입니다. 그러나 일반적으로 나타나는 첫 번째 항목은 0,1 또는 1,0입니다 (루프에 따라 다름). 그러나 비어 있지 않은 첫 번째 열과 비어 있지 않은 첫 번째 행을 찾아 해당 좌표를 결합하면 0,0이됩니다. 동일한 주체가 경계 상자의 맨 아래 / 오른쪽에 적용됩니다.


답변


답변