게임개발

[ 졸업작품 개발 기록 ] 로프 스윙과 벡터 내적

vcs 2025. 3. 26. 19:47

졸업작품은 돌고 돌아 누구나 개발하기를 꿈꾸는 2D 플랫포머 액션 게임을 만들게 되었다.

 

그중에서도 레퍼런스 게임은 2D 플랫포머액션 개발의 진입장벽을 무자비하게 올려버린

바로 산나비라는 게임이다.

 

이 게임은 로프액션이라는 신박한 이동방식과 이를 이용한 속도감 있고

타격감 있는 전투를 진행하는 게임이다. 

정말 재미있게 플레이한 게임이고 그렇다 보니 비슷한 메커니즘의 게임을 너무나 만들고 싶었다.

 

그를 위해 필요했던 여러 시스템중 고민이 되던 부분이 있다.

그것은 로프 체공 중에 스윙방향을 연산하여 그 방향으로 가속을 하는 시스템이다.

옛날 개발본

이런 연산을 해주지 않으면

옆으론 비교적 빠르게 스윙하는데 위로는 속도가 엄청 안 나오는 그냥 구린 조작감이 탄생한다.

그리고 특정 위치에서 스윙을 사용할 때 의도되지 않은 이동을 하는 경우가 있다.

 

그래서 이를 수학으로 해결할 것이다.

결론적으로 이번 글의 주된 내용은 수학이다.

 


 

현재 주어진 정보는 두 가지.

로프에 매달린 방향의 벡터, 현재 들어온 키 인풋에 대한 방향벡터이다.

추가로 다른 정보들을 받아올 순 있으나 매개변수가 셋 이상 늘어나는 건 별로 좋지 않은 데다

내부적으로 약간 귀찮아진다.

 

어쨌든 이 두 벡터로 구해야 할 방향이 현재 매달린 방향에서 가속할 방향이다

그림으로 나타내면 이러하다.

각 점에 대해서 빨강, 파랑이 Input으로 주어지는 방향. Input이 빨강일 때 초록, 파랑일 때 보라색 벡터가

산출되어야 한다. 그리고 이는 매달린 앵커 벡터에 수직 이어야 한다.

 

이렇게 해야만 매달린 시점에서 조작에 따른 정확한 스윙 가속을 할 수 있다.

이를 어떻게 해결할 수 있을까?

 

 

전체적인 과정을 간략하게 설명하면

매달린 방향의 수직인 벡터를 찾고. 인풋과의 내적을 통해 이를 반전시킬지 말지를 정하게 된다.

 

우선 수직 벡터를 구하기 위한 공식은

(x, y) 일 때 수직 벡터는 (-y, x)이다.

그럼 대충 초록색에 해당하는 벡터가 나오게 된다.

이제 내적을 해야 하는데 왜 째서 내적을 하는가.

 

벡터의 내적은 두 벡터의 유사성을 나타낸다. 벡터 내적은 스칼라값(그냥 숫자라 보면 됨)을 반환하는데.

이 스칼라값이 양수라면 두 벡터는 비슷한 방향을 보고 있는 것이고.

음수라면 반대방향을 보고 있다는 것이다.

 

예를 들어 C 포인트의 파란 인풋과 초록벡터를 내적 하면

음수 스칼라 값이 나오게 된다. 그런데 음수가 나오면

어떤 걸 할 수 있는가. 

놀랍게도 벡터 방향을 반전시킬 수 있다!

 

단 정확한 판정을 위해 단위벡터 (정규화된 벡터)를

사용해야만 한다.

 

남은 건 간단하다. 이를 적용하면 된다.

 

public void UseTurbo(Vector2 hangingDirection)
{
    hangingDirection.Normalize();
    Debug.DrawLine(_player.transform.position, _player.transform.position + (Vector3)hangingDirection * 10, Color.magenta, 2f);

    Vector2 rotatedDirection = new Vector2(-hangingDirection.y, hangingDirection.x);
    rotatedDirection.Normalize();
    Vector2 inputDirection = _player.PlayerInput.InputDirection;
    if (inputDirection.magnitude < 0.1f)
    	inputDirection = Velocity.normalized;
    inputDirection.y = 0f;

    Vector2 result = rotatedDirection * Vector2.Dot(inputDirection, rotatedDirection);
    result.Normalize();
    
    SetVelocity(result * _turboPower);
}

 

완성된 코드는 이러하다

 

그리고 이 코드를 적용한 스윙

개선된 개발본

스윙이 이상한 방향으로 튀지 않고 인풋에 따라 올바른 방향으로 가속된다.