많은 사각형에 대한 효율적인 타일 기반 충돌 탐지?


9

현재 나는 타일 기반 게임 (테라 리아를 생각하지만 환상적이지는 않다고 생각합니다)입니다.

어쨌든, 나는 현재 충돌 감지 작업을 수행하고 있습니다 (코너 케이스조차도!). 스프라이트가 블록을 통과하지 않는 것을 보는 것은 매우 만족스러운 일입니다. 그러나 벤치마킹 아이디어가있었습니다. 나쁜 생각.

1,000 제곱, 문제 없습니다. 10,000 자, 3 자에 대해서는 일종의 게으르다. 3 명의 캐릭터에 대해 10 만 제곱 (실제로 큰 맵)을 재생할 수 없었습니다.

플레이어, 캐릭터, 아이템 등에서 너무 멀리 떨어진 블록을 고려하고 싶지 않지만 메모리에 블록을 지속적으로로드하고 싶지 않은 문제가 있습니다.

지금까지 내 알고리즘은 다음과 같습니다.

foreach (Block in level)
{
    if (distance from block to player > a specified amount)
        ignore this block;
    else
    {
        get the intersection depth between the two bounding boxes
        if (depth of intersection != Zero-vector)
        {
            check y size vs x size
            resolve on smallest axis
        }
    }
}

알다시피, 레벨 크기가 커지면이 알고리즘의 차수는 N 블록 씩 커집니다. 나는 플레이어 근처에 있지 않은 블록도 고려하고 싶지 않습니다.

목록 대신 (0,0) ~ (mapWidth, mapHeight) 이중 배열 블록을 사용하여 사람의 위치에 따라 위험 영역을 계산합니다 (예 : 플레이어의 위치가 (10, 20) 인 경우) (0, 10)에서 (20, 30) 등으로 보입니다.

모든 생각과 고려 사항은 훌륭합니다. 감사합니다.


1
그리고 스택 교환에 오신 것을 환영합니다! :-) 전체 QA 및 평판 시스템의 작동 방식을 모르는 경우 FAQ를 반드시 읽어보십시오.
David Gouveia

분명히이 타일은 16 x 16 픽셀보다 크며 1920 x 1080에서 8,100 타일입니다. 확실히 당신은 움직일 수있는 엔티티가 어디 있는지 알고 있으며 범위에있을 수있는 그리드의 타일 만 검사 할 수 있습니다 (160 * 160이고 중앙이 타일 (12,12) 인 경우 타일 사이에서만 확인하면됩니다 (6) , 6) 및 (18,18)은 총 ~ 150 개의 가능한 타일입니다.). 중력이 가해진 타일은 떨어지기 때문에 아래 타일 만 찾으면됩니다.
DampeS8N

16x16이 너무 작다고 생각하십니까? tilewidth / height를 참조하는 것은 정적 상수이므로 타일의 크기를 변경하는 것은 어렵지 않습니다. 내가해야 할 일은 Paint.NET에서 확대하는 것입니다. 세부 사항을 더 추가하기 때문에 좋습니다.
Ross

충돌 코드를 공유 하시겠습니까? : /
ashes999

답변:


7

예, 당신은 올바르게 생각하고 있습니다. 위치별로 타일을 색인 할 수 있으므로 2D 타일 배열을 사용해야합니다.

Block[,] level = new Block[width, height];

플레이어는 주변 타일과 만 충돌 할 수 있으므로 수행해야하는 충돌 확인 횟수는 매우 적습니다. 이것은 물론 플레이어의 크기에 달려 있습니다. 플랫 포머 샘플 이런 식으로 작업을 수행합니다

int leftTile = (int)Math.Floor((float)characterBounds.Left / tileWidth);
int rightTile = (int)Math.Ceiling(((float)characterBounds.Right / tileWidth)) - 1;
int topTile = (int)Math.Floor((float)characterBounds.Top / tileHeight);
int bottomTile = (int)Math.Ceiling(((float)characterBounds.Bottom / tileHeight)) - 1;

for (int y = topTile; y <= bottomTile; ++y)
{
    for (int x = leftTile; x <= rightTile; ++x)
    {
        // Handle collisions with the tile level[x,y] just like you were doing!
    }
}

여전히 문제가 있으면 샘플을 확인하십시오.


이것은 매우 멋진 작은 알고리즘으로, Platformer 샘플에 대해 들어 본 적이 없습니다 (필자는 있어야하지만 무지를 주장합니다). 감사합니다!
Ross

@ 로스 정말? 솔루션이 샘플과 얼마나 유사한 지 놀랄 것입니다. :-) 목록 부분을 빼면 다른 모든 것은 거의 동일합니다 (경계 상자를 교차하고 교차 깊이를 얻고 가장 작은 축에서 확인).
David Gouveia

1
오, 방금 봤어 >. <이틀 전에 알고 있었으면 좋겠다 !! 글쎄, 나는 XNA를 처음 사용하지만 2D 그래픽 (OpenGL, 게임 프로그래밍은별로 중요하지 않음)을 탐구했습니다. 코딩을 시작하기 전에 더 많은 리소스를 먼저 확인해야한다고 생각합니다.
Ross

1

내 대답은 네 대답이 될 것 같아! ;-)

플레이어 위치와 크기가 있다면 주변 타일의 인덱스를 계산할 수 있습니다. 이런 식으로 맵의 크기와 관련이 없어야합니다. 플레이어의 실제 크기에 따라 달라지기 때문에 더 많은 타일을 확인할 수 있습니다.

riemers.net에서 충돌에 대한 튜토리얼 을 아직 확인하지 않은 경우 확인하십시오 .


나는 Riemer 's에 대해 들어 보았지만 찾아 보지 못했습니다. 감사합니다!
Ross

1

많은 수의 충돌을 처리 할 때 일반적으로 Quadtree 또는 Hashmap과 같은 고급 구조 를 사용하여 해당 충돌을 확인하려고합니다.

타일은 정적이므로 Quadtree를 사용하는 것이 좋습니다 . 쿼드 트리는 쿼드로 구성됩니다. 각 사각형은 네 개의 사각형으로 구성되며 각 사각형은 사각형입니다. 지정된 크기까지 재귀 적으로 계속됩니다. 각 쿼드에는 화면의 해당 영역에 서식하는 타일 목록이 포함될 수 있습니다. 그렇게하면 충돌을 확인할 때

  1. 수표를 바로 근처에있는 수표로 제한
  2. 움직이는 물체로만 검사 제한

화면에서 타일을보고 싶지 않다면 다음과 같은 작업을 수행 할 수 있습니다.

public bool CheckCollision(myPosition) {
    if(quadNodes.Count > 0) {
        // This is not a leaf, keep checking
        foreach(Quad node in quadNodes) {
            if(node.Position is insideViewport && nearPlayer)
                // Continue recursion
            }
        }
    }
    else {
        // This is a leaf, do checks
        foreach(Tile tile in tileList) {
            if(collision)
                return true;
        }
        return false;
    }
}

흠, 3D 충돌 감지에서 Octrees에 대해 들었지만 2D 충돌 감지에 고급 데이터 구조가 사용되는 것을 본 적이 없습니다. 대단히 감사합니다!
Ross

1
그의 게임 (테라 리아를 가정)은 균일 한 간격의 타일로 구성되므로 그리드를 사용하는 것이 쿼드 트리보다 훨씬 쉽고 빠릅니다. 쿼드 트리는 그리드를 맞추기가 어렵고 모든 크기가 임의 인 복잡한 세계에서 더 잘 작동합니다.
David Gouveia

1
순전히 그리드 기반 게임이라면 캐릭터 크기에 이르기까지 옳습니다. Terraria에는 그리드 형식에 쉽게 맞지 않는 몬스터도 있습니다. 나는 기본 세계가 타일로 만들어 졌다는 가정하에 실행되었지만 다른 객체는 다를 수 있으며 다른 객체를 만들지 않도록 비슷한 구조로 저장할 수 있습니다. 타일에 그리드를 사용하고 다른 임의의 객체에 대해 다른 구조 (필요한 경우)를 사용할 수 있다고 가정합니다.
Mike Cluck

1
그것이 내가 제안하려고했던 것입니다 :) 격자는 지형과의 충돌을 처리하는 데 사용해야하며 쿼드 트리는 객체 간 충돌을 처리하는 데 사용될 수 있습니다.
David Gouveia

진실. 현재 모든 경계 상자의 크기는 2 ^ power입니다. 이렇게하면 충돌 감지가 훨씬 쉬워집니다. 그리드는 지금 내 요구에 맞을 것입니다.
Ross
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.