본문 바로가기
회사 TIL

[TIL] 22.12.16 / 금고 1단계 이동/회전 구현하기 + 제한 주기

by imagineer_jinny 2022. 12. 18.

TIL (Today I Learned)

 

오늘 해야할 것

  • Move 구현
  • Rotate 구현
  • Move 코드 비교 & 분석 -> 왜 다르고 뭐가 다르고 대표님은 왜 저렇게 짰을까?
  • ProjectVectorOnToPlane, ProjectVectorOnToVector, ProjectOnTo

 

오늘 한 것

  • World 좌표계 기준으로 Move 구현 
  • 코드는 내가 짰지만 왜 되는지 잘 모르겠다 -> 함수에 대한 이해가 부족한 것 같다. 아직 그림 맞추기를 하고 있는 것 같다. 
	if (_grabbed == false)
		return;

	FVector handPos = _handSocketRef->GetComponentLocation();//world


	FVector handMoveDir = handPos - _lastHandSocketPos; //world

	FVector _forward = _meshKeyLocker->GetForwardVector(); //world
	_forward.Normalize();

	handMoveDir = handMoveDir.ProjectOnTo(_forward); //world

	_meshKeyLocker->AddWorldOffset(handMoveDir); //world로 움직이겠다(Offset = location)

	FVector location = _meshKeyLocker->GetComponentLocation(); 
	_meshKeyLocker->SetWorldLocation(location);

 

  • Rotate 구현 계획

 

1. 레버를 잡는다. 

2. 잡고 있는 상태면 forward축 기준으로 시계방향으로 돌리면 시계 방향으로 돌아가고, 반시계 방향으로 돌리면 반시계 방향으로 돌아간다.


- 레버를 잡았다

  • 손 위치가 생긴다. 

 

- 레버를 시계방향으로 돌린다.

  • 손 위치가 바뀐다. 
  • 돌렸으니까 변화값(각)이 생긴다. 
  • 축은 레버의 forward
  • 각과 축을 이용해서 회전 시켜준다.

- 레버를 잡았다

  • 손 위치가 생긴다. 
    • 손 위치를 변수로 가져온다. 손 위치는 FVector handPos = _handSocketRef->GetComponentLocation(); //world

 

- 레버를 시계방향으로 돌린다.

  • 손 위치가 바뀐다. 
    • 잡은 채로 돌리는거니까 손의 위치가 바뀐다기보다는 컨트롤러의 위치가 바뀌는 것
    • v1= prevHandPos -lever의 중심 
    • v2= HandPos - lever의 중심

 

- 축은 레버의 forward

  • FVector _forward = _meshKeyLocker->GetForwardVector(); //world

 

- 각과 축을 이용해서 회전 시켜준다

  • _forward의 ProjectVectorOnToPlane
  • v1, v2가 평면에 Projection 된 상태여야 함
  • Projection 시킨 후에 v1과 v2 사이의 각 구하기.  FVector angle;
  • 각만큼 회전 시켜주는데 (SetRelativeAngle) 이 때 시계방향으로 돌리는지 반시계로 돌리는지 알려면 외적도 구해야함
  • 외적은 v1, v2로 구해서 나온 v라는 것.
  • 각 판별
  • _forward.Dot(v) > 0 : 예각 - 시계방향 -> 각은 -
  • _forward.Dot(v) < 0 : 둔각 - 반시계방향 -> 각은 +

 

- 성공!

	// Rotation
	FVector v1 = _lastHandSocketPos - _meshKeyLocker->GetComponentLocation();
	FVector v2 = handPos - _meshKeyLocker->GetComponentLocation();

	//중심축
	FVector _forward = _meshKeyLocker->GetForwardVector();

	//Projection
	v1 = UKismetMathLibrary::ProjectVectorOnToPlane(v1, _forward);
	v2 = UKismetMathLibrary::ProjectVectorOnToPlane(v2, _forward);

	//Projection 시킨 v1, v2의 각 구해주기
	double angle = UKismetMathLibrary::Abs(R1Math::GetAngleBetweenTwoVectors(v1, v2));

	//v1, v2 외적해주기
	FVector v = UKismetMathLibrary::Cross_VectorVector(v1, v2);

	if (_forward.Dot(v) > 0)
	{
		_meshKeyLocker->AddRelativeRotation(FRotator(0, 0, -angle));
	}
	else
	{
		_meshKeyLocker->AddRelativeRotation(FRotator(0, 0, angle));
	}

	_lastHandSocketPos = handPos;

 

 

  • Rotate 각 제한 계획

1. forward 축이 0도에서 180사이일 때만 회전할 수 있다.

 


- (레버의)forward의 회전 값(Roll)을 가져온다.

FRotator lockerRotateValue = _meshKeyLocker->GetRelativeRotation();

 

- forward의 회전 값이 0보다 작으면 forward의 회전값을 0으로 만들고

 forward의 회전 값이 180보다 크면 forward의 회전 값을 180으로 만든다.

if (lockerRotateValue.Roll < 0.f)
{
    lockerRotateValue.Roll = 0.f;
    _meshKeyLocker->SetRelativeRotation(lockerRotateValue);
}

if (lockerRotateValue.Roll > 180.f)
{
    lockerRotateValue.Roll = 180.f;
    _meshKeyLocker->SetRelativeRotation(lockerRotateValue);
}

 

 

 

  • Move 이동범위 제한 계획

1. 키를 좌우로 왔다갔다 할 수 있다  -> OK

2. 키의 상태(모양)에 따라서 이동 범위를 다르게 주고 싶다.

 


- 키의 상태를 정의하자

 

1) 튀어나온 부분이 나를 향하고 있는 상태

 

2) 그렇지 않은 상태 

 

- 키의 상태를 정의하면 각각 상태에 따라 키의 왼쪽 손잡이 기준으로 최대 최소 이동 가능 거리를 구해준다.

 

- 키의 상태에 따라 키를 움직이면 각각 상태에 따라 최대, 최소 이동 가능거리만큼 이동한다.

 

 


- 키의 상태를 정의하자

 

1) 튀어나온 부분이 나를 향하고 있는 상태

-  _meshKeyLocker의 Roll이 75도 ~ 105도 

 

2) 그렇지 않은 상태 

-  _meshKeyLocker의 Roll이 75도 ~ 105도가 아닌 상태

 

 

- 키의 상태를 정의하면 각각 상태에 따라 키의 왼쪽 손잡이 기준으로 최대 최소 이동 가능 범위를 구해준다.

 

  • 누가 이동하는가? 
    • 기준점을 구해준다.

왼쪽 끝으로 기준을 잡으려 했더니 계산하기 어려울 것 같아서 그냥 기준점은 물체의 중심. 따로 계산 더 안해주고 중심 좌표만 받아오면 되니깐.

 

  • 이동 가능한 부분과 가능하지 않은 부분을 알려면?
    • 영역을 나눠주는게 좋겠다.
    • 영역을 나눠줬는데 이동 가능 범위는 어떻게 구할까?

 

1) 튀어나온 부분이 나를 향하고 있는 상태

이동 가능 범위: _meshKeyLocker의 중심축위치에서 

x축끼리 계산하면(5.f)--------->(25.f)

 

 

2) 그렇지 않은 상태 

이동 가능 범위: _meshKeyLocker의 중심 축 위치에서

x축끼리 계산하면

(5.f)--------->(12.f)

 

 

- 키의 상태에 따라 키를 움직이면 각각 상태에 따라 최대, 최소 이동 가능거리만큼 이동한다.

 

  • 이동 거리만큼 이동해보자!
    • 만약 _meshKeyLocker.X <5.f이면 _meshKeyLocker.X=5.f 

- 키의 상태를 정의하자

 

1) 튀어나온 부분이 나를 향하고 있는 상태

-  _meshKeyLocker의 Roll이 75도 ~ 105도 

 

2) 그렇지 않은 상태 

-  _meshKeyLocker의 Roll이 75도 ~ 105도가 아닌 상태

 

// KeyLockerRotateState 설정하는 함수
EKeyLockerRotateState AR1Level1StrongBox::GetKeyLockerRotateState()
{
	float x = _meshKeyLocker->GetRelativeRotation().Roll;

	if ((x >= 75.f)&&(x<=105.f))
		return EKeyLockerRotateState::State1_UpState;

	return EKeyLockerRotateState::State2_FrontState;

}

 

 

 

- 키의 상태를 정의했으니 어디서 키의 상태를 어디서 바꿔줄 것인가?

  • Tick 함수!
  • 어떻게 바꿔줄 것인가?  ---> 여기서 막힘

 

 

각각 상태에 따라 키의 왼쪽 손잡이 기준으로 최대 최소 이동 가능 범위를 구해준다.

1) 튀어나온 부분이 나를 향하고 있는 상태

이동 가능 범위: _meshKeyLocker의 중심축위치에서 

x축끼리 계산하면

(5.f)--------->(25.f)

 

 

2) 그렇지 않은 상태 

이동 가능 범위: _meshKeyLocker의 중심 축 위치에서

x축끼리 계산하면

(5.f)--------->(12.f)

 

 

- 키의 상태에 따라 키를 움직이면 각각 상태에 따라 최대, 최소 이동 가능거리만큼 이동한다.

 

  • 이동 거리만큼 이동해보자!
    • 만약 _meshKeyLocker.X <-12.f이면 _meshKeyLocker.X=12.f 

 

 

 

오늘 배운 것

  • 구현할 때 어떻게 시작하고 왜 글로 먼저 써봐야 하는지 이해했다. 
  • 글로 명확히 쓰고 시작하니까 정확히 뭘 필요로 하는지, 순서는 어떻게 되는지, 어떤 결과가 나와야 하는지 다시 한번 정리되었다.

 

내일 진행할 것

  • 삼각함수 문제 풀기

 

 

다음주에 진행할 것

  • 금고 이어 하기

 

앞으로 진행할 것

  • 오큘러스 내 빌드 해결
  • SCP 914 찾아보기

https://www.youtube.com/watch?v=-9rbYP0cDjU
https://www.youtube.com/watch?v=V2Ps5bM4TwE

 

	if (CanLockerMove())
	{
		FVector dir = handPos - _lastHandSocketPos;
		FVector front = _meshKeyLocker->GetForwardVector();

		// Projected Location
		dir = UKismetMathLibrary::ProjectVectorOnToVector(dir, front);

		// World -> Local
		dir = _meshKeyLocker->GetComponentTransform().InverseTransformVector(dir);

		_meshKeyLocker->AddLocalOffset(dir);

		FVector location = _meshKeyLocker->GetRelativeLocation();
		if (location.X < LOCKER_MIN_X)
		{
			location.X = LOCKER_MIN_X;
			_meshKeyLocker->SetRelativeLocation(location);
		}

		if (location.X > LOCKER_MAX_X)
		{
			location.X = LOCKER_MAX_X;
			_meshKeyLocker->SetRelativeLocation(location);
		}
	}
{
		float roll = _meshKeyLocker->GetRelativeRotation().Roll;
		FVector v1 = _lastHandSocketPos - _meshKeyLocker->GetComponentLocation();
		FVector v2 = handPos - _meshKeyLocker->GetComponentLocation();

		FVector front = _meshKeyLocker->GetForwardVector();

		// Projected Location
		v1 = UKismetMathLibrary::ProjectVectorOnToPlane(v1, front);
		v2 = UKismetMathLibrary::ProjectVectorOnToPlane(v2, front);

		// 외적으로 방향 구하기
		FVector v = UKismetMathLibrary::Cross_VectorVector(v1, v2);
		// 내적으로 각도 구하기
		double angle = UKismetMathLibrary::Abs(R1Math::GetAngleBetweenTwoVectors(v1, v2));

		if (front.Dot(v) < 0)
			_meshKeyLocker->AddRelativeRotation(FRotator(0, 0, angle));
		else
			_meshKeyLocker->AddRelativeRotation(FRotator(0, 0, -angle));

		FRotator rotation = _meshKeyLocker->GetRelativeRotation();
		if (rotation.Roll < LOCKER_MIN_X)
		{
			rotation.Roll = LOCKER_MIN_X;
			_meshKeyLocker->SetRelativeRotation(rotation);
		}

		if (rotation.Roll > LOCKER_MAX_ROLL)
		{
			rotation.Roll = LOCKER_MAX_ROLL;
			_meshKeyLocker->SetRelativeRotation(rotation);
		}
	}

댓글