컴퓨터 그래픽스 : 수학/게임 수학

[게임 프로그래머 입문 올인원] 게임수학 : 역삼각함수 (98강)

순정법사 2024.04.11

A. 역삼각함수 

1. 역삼각함수 기초 

a. 함수와 역함수

함수의 기초 모양

 

위와 동일하게 y를 넣으면 x가 나와야함

 

역함수는 항상 존재하지 않고, 1:1 대응이여야지만 존재한다 

 

b. 삼각함수와 역삼각함수

이게 삼각함수인데 이걸 반대로 생각하는게 역삼각함수

 

아크 + 를 붙여서 읽음, 거꾸로 각도를 구할 때 사용한다

 

근데 cos값이 1이라면 0, 2파이 4파이일때 등 무한으로 나옴

 

이렇게 동일한 값이 무한으로 나와서 역함수가 어렵지만

범위를 강제로 지정해서 사용할 수 있음

 

즉, cos의 val가 -1~1이라고 하면 각도는 0~180

 

그럼 아크코사인은 이런 모양이 나옴, 초록 상자 내에서만 활용

 

동일하게 sin, tan의 val가 -1~1이라고 하면 각도는 -90~90

 

아크사인, 아크탄젠트는 이 모양으로 사용됨

 

두개를 합치면 이런 모양이 된다

 

원하는 벨류를 넣어줘도 원하는 값이 튀어나온다는 보장이 없음

🌟 역삼각함수에서 튀어나온 각도의 범위는 0~180 / -90~90라는 점을 꼭 기억해야 함

 

이렇게 응용할 수 있음

 

 

2. 게임에 역삼각함수 더하기

백스텝 : 뒤에서 타격하면 가산점수처럼 각도계산을 해서 다른 점수를 줘야 할 때

 

a. 몬스터 방향 정보 추가하기

몬스터의 방향과 계산할 방향을 추가해주고

 

위에서 추가해준 정보를 초기화해준다

 

ㅇㅕ기서 지정해주던 몬스터의 포지션은 삭제 (주석부분)

 

b. 몬스터 생성 및 방향 만들기

몬스터를 다시 등장시키고 바라보는 방향을 빨간 선으로 그려주기

 

그럼 이렇게 위를 바라보고 있음

 

여기서 마우스 위치에 따라 몬스터를 공격하는 각도를 계산할 것임 

기준은 마음대로 설정!! 

 

c. 전략 세우기

마우스 위치(monsterToMouseDir) 에서 몬스터의 방향 (lookDir)의 각도를 구하면 됨

 

v1, v2를 내적하면 둘다 값이 1이니까 cos만 튀어나옴

 

여기에 아크코사인을 때려주면 각도가 나온다!! 

 

d. 각도 구하기

c.에서 공략한대로 v1,v2를 정규화, 내적 후 아크코사인으로 각도를 구해주고 찍어주면

 

아크코사인이기 때문에 180 내부 각도로 값이 나옴 (마우스가 돌아가고 있음)

 

e. 각도 보정하기

만약에 180도 이후의 각도를 얻고싶으면 외적하거나 왼쪽/오른쪽 처리로 보정할 수 있음 (다양한 방법) 

 

1) 좌표를 통한 판별하기 - X

 

이렇게되면 보정이되긴 하지만 문제점이 있음

 

💥 몬스터가 다른쪽을 바라보고 있으면 좌표가 틀어져버림 (하드코딩으로 인한)

 

2) 내적을 이용한 우측 판별 방법

 

 

3) 외적을 이용한 우측 판별 방법 - O

 

시계방향, 반시계방향으로 판별하는 방법

 

 

f. 각도 출력하기

외적을 이용한 판별방법을 이용해 마우스 좌표도 찍고, 각도도 찍어주면

 

이렇게 잘 나온다!!

 

◽◽◽ Monster.cpp

#include "pch.h"
#include "Monster.h"
#include "InputManager.h"

Monster::Monster() : Object(ObjectType::Monster)
{

}

Monster::~Monster()
{

}

void Monster::Init()
{
	_stat.hp = 100;
	_stat.maxHp = 100;
	_stat.speed = 10;

	_pos = Pos{ 400, 300 };	//먼저 세팅해주고

	_lookPos = Pos{ 530, 70 };	//다른 위치를 바라보게 
	_lookDir = _lookPos - _pos;	//바라보는 위치 - 현재 위치 
	_lookDir.Normalize();	//단위 벡터로 관리
}

void Monster::Update()
{

}

void Monster::Render(HDC hdc)
{
	// 몬스터 등장
	Utils::DrawCircle(hdc, _pos, 100);

	// Front Dir : 몬스터가 바라보는 방향
	HPEN pen = ::CreatePen(PS_SOLID, 1, RGB(255, 0, 0));
	HPEN oldPen = (HPEN)::SelectObject(hdc, (HGDIOBJ)pen);
	{
		Utils::DrawLine(hdc, _pos, _lookPos);
	}
	::SelectObject(hdc, oldPen);
	::DeleteObject(pen);

	//////////////////////

	Vector mousePos = GET_SINGLE(InputManager)->GetMousePos();

	//몬스터 방향 v2
	Vector dir = _lookDir;
	dir.Normalize();

	//마우스 - 몬스터방향 v1
	Vector monsterToMouseDir = mousePos - _pos;
	monsterToMouseDir.Normalize();

	//float dot = dir.Dot(monsterToMouseDir);
	float dot = monsterToMouseDir.Dot(dir);	//두개 방향 내적하고
	float rad = ::acos(dot);	//아크코사인 하면 각도만 나옴
	float angle = rad * 180 / 3.14;	//각도로 변환해주기

	// 0) 좌표를 통한 판별 방법
	//if (monsterToMouseDir.x < 0)
	//	angle = 360 - angle;

	// 1) 내적을 이용한 우측 판별 방법
	/*Vector rightDir = {};
	{
		float rotateAngle = 3.14f / 2;
		rightDir.x = _lookDir.x * cos(rotateAngle) - _lookDir.y * sin(rotateAngle);
		rightDir.y = _lookDir.x * sin(rotateAngle) + _lookDir.y * cos(rotateAngle);
		Utils::DrawLine(hdc, _pos, _pos + rightDir * 50);

		float rightDot = rightDir.Dot(monsterToMouseDir);
		if (rightDot < 0)
			angle = 360 - angle;
	}*/

	// 2) 외적을 이용한 우측 판별 방법
	float cross = _lookDir.Cross(monsterToMouseDir);
	if (cross < 0)
		angle = 360 - angle;

	{
		//마우스 좌표 찍기
		Utils::DrawLine(hdc, _pos, mousePos);
	}

	{
		//각도 찍어주기
		wstring str = std::format(L"angle({0})", angle);
		Utils::DrawTextW(hdc, { 20, 50 }, str);
	}
}

 

 

 


출처 :https://www.inflearn.com/course/%EA%B2%8C%EC%9E%84-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8-%EC%9E%85%EB%AC%B8-%EC%98%AC%EC%9D%B8%EC%9B%90-rookiss#curriculum

 

[게임 프로그래머 입문 올인원] C++ & 자료구조/알고리즘 & STL & 게임 수학 & Windows API & 게임 서버 -

어디부터 시작할지 막막한 게임 프로그래밍 입문자를 위한 All-In-One 커리큘럼입니다. C++, 자료구조/알고리즘, STL, 게임 수학, Windows API, 게임 서버 입문으로 이어지는 알찬 커리큘럼으로 게임 프

www.inflearn.com