Plite
전자오락 공방
Plite
전체 방문자
오늘
어제
  • 분류 전체보기 (274)
    • 프로젝트 (18)
      • 완성 프로젝트 (3)
      • 프로젝트 진행 내역 (15)
    • 공부 및 정리 (241)
      • 백준 코드 (222)
      • C++ (8)
      • DirectX (2)
      • Unreal Engine (6)
      • 프로그래밍 패턴 (3)
    • 기타 (12)
      • 기타 주저리 (10)
    • 게임과 취미 (1)
    • 대문 (1)

블로그 메뉴

  • 홈
  • 프로젝트
  • 취미, 일상
  • 백준 프로필

공지사항

  • [Read Me]
  • 제 블로그에 방문하신 것을 환영합니다.

인기 글

태그

  • 백트래킹
  • 정수론
  • 백준
  • LCA
  • 세그먼트 트리
  • 동적계획법
  • 기하
  • 누적합
  • 구현
  • 큐
  • 문자열
  • 유니온 파인드
  • 트리
  • 스택
  • 그래프
  • 투포인터
  • 수학
  • 분할정복
  • KMP
  • 정렬
  • 위상 정렬
  • 브루트포스
  • 우선순위큐
  • 최소 스패닝 트리
  • 트라이
  • 이분탐색
  • SCC
  • C++
  • 조합론
  • UC++

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Plite

전자오락 공방

[C++]백준 - 16135번 문제
공부 및 정리/백준 코드

[C++]백준 - 16135번 문제

2022. 10. 14. 14:17

16135번: OBB(Oriented bounding box) (acmicpc.net)

 

16135번: OBB(Oriented bounding box)

안녕! 요즘 2차원 슈팅 게임을 만들고 있는데, 좀 어려운 부분이 생겼어. 플레이어가 적이 쏘는 총알에 맞으면 데미지를 입는 것을 구현하고 싶은데, 혹시 네가 도와줄 수 있니? 히트박스(실제

www.acmicpc.net

 

16135번 : OBB(Oriented bounding box)


안녕! 요즘 2차원 슈팅 게임을 만들고 있는데, 좀 어려운 부분이 생겼어. 플레이어가 적이 쏘는 총알에 맞으면 데미지를 입는 것을 구현하고 싶은데, 혹시 네가 도와줄 수 있니? 히트박스(실제로 두 물체의 충돌이 인식되는 공간)는 얼마든지 회전할 수 있는 직사각형 모양이야.

[분리축 이론]

두 볼록다각형이 겹쳐 있지 않으면, 반드시 두 도형을 분리하는 직선이 존재한다. 또한, 그 직선의 방향으로 투영하면 그림자가 겹치지 않을 것이다. 두 도형이 겹쳐 있다면 어떤 방향으로 투영하더라도 반드시 그림자가 겹친다.

 

입력


첫 줄에 두 직사각형 A와 B의 모든 꼭짓점의 좌표가 시계방향 또는 반시계방향으로 주어진다. 좌표의 절댓값은 2,000이하이다. 넓이가 0인 직사각형이 주어질 수도 있다.

 

출력


두 직사각형이 겹치면 1, 겹치지 않으면 0을 출력한다. 자세한 내용은 문제를 참고한다.

서브태스크 1 (15점)


직사각형의 변이 축과 평행하다.

 

 

서브태스크 2 (85점)


추가 제한 없음.

 


 

생각해 볼 점


기하 문제입니다.

 

함수를 하나씩 만들어가면서 풀면 생각보다 어렵지 않습니다.

 

 

우선, 핵심은 OBB 충돌 판정입니다.

 

OBB 충돌 판정이란 두 볼록 다각형의

 

모든 변에 대한 투영구간이 겹치는지 확인하여 충돌을 검사하는 방법입니다. 

 

 

위 그림과 같이 변에 평행한 기준 벡터를 구합니다.

 

원래라면 총 8개의 벡터가 나오겠지만, 직사각형이므로 총 4개의 기준 벡터만 구하면 됩니다.

 

그 중 하나인 빨간 벡터를 기준으로 OBB 과정을 진행하면

 


위 그림과 같이 기준 벡터에 대해 사각형을 투영하여

 

그림자가 서로 겹치지 않으면 충돌하지 않은 것으로 판단합니다. 

 

이 때, 이를 판단하는 근거로 사각형 두 중심점을 잇는 벡터 d를 구합니다.

 

d를 기준 벡터에 정사영하여 d'을 위 그림과 같이 구했습니다.

 

 

 

위 그림과 같이 사각형을 벡터에 투영하여 나온 그림자의 길이 중,

 

중심으로 부터의 길이 L1과 L2의 합이 d'보다 클경우 그림자가 겹쳤다고 판단합니다.

 

그리고 이 과정을 모든 기준 벡터에 대해 실행하여

 

모든 그림자가 겹치면 두 사각형은 충돌했다고 볼 수 있습니다.

 

그림자가 1회라도 겹치지 않으면 충돌하지 않았습니다.

 

 

* 정사영에 대하여

 

- 정사영은 본래 단위벡터(길이가 1)에 내려야 하는 것이 맞습니다.

 

하지만, 부동 소수점에서의 Normalize 과정은 오차를 만들게 됩니다.

 

따라서, 본 문제에서는 굳이 Normalize 과정을 거치지 않습니다.

 

왜냐하면, OBB 판정과정에서는 단순히 크기 비교만 하기 때문에 정확한 값을 구하지 않아도 되기 때문입니다.

 

 

코드


#include <iostream>
#include <cmath>
#define Point pair<double, double>
#define X first
#define Y second
using namespace std;

//사각형 중심을 구함
Point GetSquareCenter(Point const& A, Point const& B, Point const& C, Point const& D)
{
	return { (A.X + B.X + C.X + D.X) / 4, (A.Y + B.Y + C.Y + D.Y) / 4 };
}

//A->B 벡터를 구함
Point GetVectorAB(Point const& A, Point const& B)
{
	return { B.X - A.X, B.Y - A.Y };
}

//내적
double DotProduct(Point const& A, Point const& B)
{
	return A.X * B.X + A.Y * B.Y;
}

int main()
{
	Point a1, a2, a3, a4;
	Point b1, b2, b3, b4;

	scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &a1.X, &a1.Y, &a2.X, &a2.Y, &a3.X, &a3.Y, &a4.X, &a4.Y);
	scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &b1.X, &b1.Y, &b2.X, &b2.Y, &b3.X, &b3.Y, &b4.X, &b4.Y);

	Point a_Center = GetSquareCenter(a1, a2, a3, a4);
	Point b_Center = GetSquareCenter(b1, b2, b3, b4);
	Point unitVectors[4] = { GetVectorAB(a1, a2), GetVectorAB(a2, a3), GetVectorAB(b1, b2), GetVectorAB(b2, b3) };
	Point dVector = GetVectorAB(a_Center, b_Center);


	//유닛 벡터에 대한 정사영 후 크기 비교
	for (int i = 0; i < 4; i++)
	{
		float dotDU = abs(DotProduct(dVector, unitVectors[i]));
		float sumDotVectors = 0.0f;
		for (int j = 0; j < 4; j++)
			sumDotVectors += abs(DotProduct(unitVectors[i], unitVectors[j]));
		
		//그림자가 겹치지 않음
		if (dotDU >= (sumDotVectors / 2))
		{
			printf("0");
			return 0;
		}
	}
	printf("1");
	return 0;
}

 

그 외


 

저작자표시 (새창열림)

'공부 및 정리 > 백준 코드' 카테고리의 다른 글

[C++]백준 - 1918번 문제  (0) 2022.10.25
[C++]백준 - 1865번 문제  (0) 2022.10.21
[C++]백준 - 11659번 문제  (0) 2022.10.13
[C++]백준 - 2407번 문제  (0) 2022.10.08
[C++]백준 - 14500번 문제  (0) 2022.10.07
    '공부 및 정리/백준 코드' 카테고리의 다른 글
    • [C++]백준 - 1918번 문제
    • [C++]백준 - 1865번 문제
    • [C++]백준 - 11659번 문제
    • [C++]백준 - 2407번 문제
    Plite
    Plite
    개발 일지, 게임 이야기 등을 적어두는 공간입니다.

    티스토리툴바