본문 바로가기

TIL

2025- 02- 05 공부 벡터에서 정규화를 사용하는 이유

언리얼이나 유니티를 사용하다보면 

Vector.GetSafeNormal();

과 같은 FVector에서 사용하는 함수가 있다 

 

float speed = 100.0f;

FVector normalizedDirection = direction.GetSafeNormal();

FVector movement = normalizedDirection * speed * DeltaTime;

 

같이 사용되는데 

이걸 왜 사용하는 지 드디어 알아 보게 되었다.

 

 

 

 

왜 사용하는가?

 

벡터의 방향을 유지하기 위해서가 가장 크다고 생각된다.

이것 말고도 계산 단수화 , 각도 계산 코사인값 등 아직은 넘어가야 될 내용이 많지만

가장 크게는 방향이라고 생각되었다.

 

 

#pragma

#include <iostream>
#include <cmath>

using namespace std;

struct FVector2D {

public:
	double x, y;

	FVector2D(double x = 0, double  y = 0) : x(x), y(y)
	{
	}

	const void SetVector(const double& x, const double& y)
	{
		this->x = x; 
		this->y = y;
	}

	FVector2D operator+ (const FVector2D& other) const {
		return FVector2D(x + other.x, y + other.y);
	}


	FVector2D operator- (const FVector2D& other) const {
		return FVector2D(x - other.x, y - other.y);
	}


	// 스칼라 곱
	FVector2D operator*(double scalar) const {
		return FVector2D(x * scalar, y * scalar);
	}

	//벡터의 크기를 계산하고
	double magnitude() const {
		return sqrt(x * x + y * y);
	}

	//여기서는 벡터의 방향을 계산한다.
	FVector2D Normalized() const {
		double mag = magnitude();
		return (mag == 0) ? FVector2D() : FVector2D(x / mag, y / mag);
	}

	void CaluateAvoidanceDirection(const FVector2D& currentDirection)
	{		
		/*x -= currentDirection.x;
		y -= currentDirection.y;*/
		x += 3;
	}
	       
	void ZeroVector(){
		x = 0; y = 0;
	}

	void SetLocation(FVector2D location)
	{
		x = location.x;

		y = location.y;
	}

	double Distance(const FVector2D& other) const
	{
		return sqrt(pow(x - other.x,2) + pow(y - other.y,2)); 
	}
};

bool IsOverlapBegin(const FVector2D& ThisVector, const FVector2D& target, double collisionDistance = 2.5) {
	
	double distance = (ThisVector - target).magnitude();

	return distance <= collisionDistance;
}


class Unit
{
protected :
	FVector2D Vector;

public:

	double speed;

	// 벡터 초기화
	Unit(double x = 0, double y = 0) {
		Vector.SetVector(x, y);
		speed = 3.0;
	}

	//아하 좋은 방식은아니겠지만 해당 값을 변경하려면 참조값을 주면된다
	FVector2D& GetPoint() {
		return Vector;
	}

	 FVector2D Move(const FVector2D& Distance) 
	{
		Vector = Vector + Distance;
		return Distance;
		//FVector2D(Vector.x + Distance.x, Vector.y + Distance.y);
	}

	const void Print(const string& text = "") {
		cout << text << "FVector (x = " << Vector.x << " y = " << Vector.y << " )" << endl;
	}
};

class EnemyUnit : public Unit
{
public:
	EnemyUnit(double x = 0, double y =0) : Unit(x,y)
	{		
		speed = 5.0;
	}

	void NextTurn()
	{
		speed += 3.0;
	}

	void Follow(Unit player, double deltitime)
	{
		FVector2D targetPoint = player.GetPoint();
		FVector2D currentPoint = GetPoint();

		// 플레이어를 향한 방향 벡터 계산
		FVector2D direction = (targetPoint - currentPoint).Normalized();

		FVector2D movement = (player.GetPoint() - GetPoint()).Normalized()  * (speed / deltitime);
		
		

		Move(movement);

		double distance = currentPoint.Distance(targetPoint);		

		if (IsOverlapBegin(currentPoint, targetPoint, distance))
		{
			if (Vector.x > player.GetPoint().x) 
			{

				Vector.SetLocation(FVector2D(targetPoint.x, Vector.y));
			}

			if (Vector.y > player.GetPoint().y)
			{
				Vector.SetLocation(FVector2D(Vector.x, targetPoint.y));
			}
		}
	}
};


int main() {
	
	Unit* Player = new Unit(5.0, 5.0);
	EnemyUnit* Enemy = new EnemyUnit(10, 10);

	FVector2D MoveDirection;
	FVector2D MovePoint = FVector2D(2, 2);
	
	double speed = 5.0;		//이동 속도
	double enemyspeed = 3.0;//적 이동속도
	double deltaTime = 1.5;	//이동 시간
	double Radius = 2.5;	//충돌 반경

	//10번 반복
	int turn = 10;
	
	while (turn > 0)
	{
		turn--;

		MoveDirection = Player->Move(MovePoint * (speed / deltaTime)); // 여기서 괄호로 한 이유를 생각중 예로들면 2 , 3 , 4 였다면 2* 3 * 4 = 24일테고 2 * (3* 4)면  6* 8 = 48값이 두배나 차이날텐데

		Player->Print("Player Point :");

		//cout << MoveDirection.x << " " << MoveDirection.y << endl;
		Enemy->Follow(*Player, deltaTime);
		Enemy->Print("Enemy Point :");

		if (IsOverlapBegin(Player->GetPoint(), Enemy->GetPoint(), Radius))
		{
			cout << "Collision hit!!"<< endl;

			//방향 전환
			Player->GetPoint().CaluateAvoidanceDirection(MoveDirection);
			Player->Print();

			cout << endl;
		}
				
		Enemy->NextTurn();
	}

	
	
	
}

 

 

방향으로 바꾸는 이유를 생각해보면

 

저 위치로 순간이동하는 거라면 정규화는 필요 없지만,
이동하는 과정에서는 특정 방향으로 일정한 속도로 움직여야 하고
그럴 때 계산을 쉽게 하기 위해 방향을 정규화하는 것이라고 생각된다.

 

만약 정규화를 하지않았다면 이동속도가 들쭉 날쭉 했을 것 같다.