캔버스 위 사람 이미지의 발자국을 휴대폰 방향과 실시간으로 맞추기

정혜인·2025년 1월 20일
0

진행했던 프로젝트에서 지도를 기반으로 사용자의 위치를 나타내는 캐릭터 이미지를 캔버스 위에 표시하고,

휴대폰의 방향에 따라 캐릭터의 발자국 방향도 실시간으로 맞춰야 했습니다.

이미지는 사람 모양의 캐릭터였고, 발이 휴대폰의 진행 방향(휴대폰이 가리키는 방향)을 향해야 했습니다.

그런데 모두 다 잘 구현한 줄 알고 다른 QA들을 쳐내고 있었지만,, 실제 테스트를 해보며 이미지의 발의 방향이 아닌 이미지의 위쪽이 디바이스의 방향을 가리키고 있다는 것을 알게 되었답니다......

🧐 문제 상황

이미지는 머리가 위로 가있는 서있는 형태였기 때문에, 캐릭터의 발 (이미지의 아래쪽)이 현재 휴대폰의 방향(동서남북)을 나타내야 했습니다.

예를 들어, 동쪽(90도)을 가리킬 때 이미지의 발 부분이 동쪽을 향하고, 서쪽(270도)을 가리킬 때 발 부분이 서쪽을 향하도록 설정해야 했습니다.

아래 gif와 같이, 디바이스의 방향이 바뀔 때 실시간으로 캐릭터의 발도 그 방향을 가리켜야 하는 것이었는데요...

GPS 데이터를 통해 휴대폰 방향(α 값)을 받아와, 해당 방향에 맞춰 이미지를 실시간으로 회전시키는 기능을 구현해야 했습니다.

사실 회전하는 것은 이전 포스팅에서도 올려뒀듯, 문제가 없었는데,

실제로 휴대폰으로 밖에 나가서 테스트를 해보니 초기의 방향이 캐릭터의 발의 방향이 아니라는 것을 알게 되었고,

급하게 수정과 보정을 거치게 되었습니다….ㅎㅎ,,

(이 기능은 저의 욕심 때문에 마지막에 촉박하게 구현했던 거라 발의 방향과 맞지 않을 거라는 고려까지 하지 못했고,,,,, 최종 발표 전전날….. 밖에 나가서 테스트를 해보며……. 발의 방향과 맞지 않다는 것을……. 알게 되었습니다…….ㅠㅠㅠㅠㅠ 폭설에 계엄령 이슈로…. 진작 밖에 나가서 테스트를 해보지 못했고,,,,,, 그래서 마지막 날까지 밤을 샜던 문제의 기능…………)


⚙️ 기존 코드의 문제점

어쨌든, 기존의 코드에서는 휴대폰의 방향(α 값, 0~360도 범위)을 다음과 같은 방식으로 캔버스 위 캐릭터 이미지의 rotate 값에 변환했습니다:

(alpha * Math.PI) / 180

위 코드는 단순히 각도를 라디안 값으로 변환한 것이었지만, 이미지의 실제 방향과 휴대폰 방향이 맞지 않았습니다.

물론 회전은 잘 했기 때문에 문제가 없었지만,,,,,, 발이 방향을 가리키고 있지 않다는 게 문제였죠……..

  • 북쪽(0도)을 가리킬 때, 이미지의 방향은 0도로 회전해야 하지만 원하는 대로 보이지 않았습니다.
  • 동쪽(90도)과 서쪽(270도) 방향에서도 이미지가 예상과 다르게 회전했습니다.

문제를 확인한 결과, 이미지의 기본 방향이 북쪽이 아닌 아래(남쪽)을 향하고 있어 기존 로직으로는 올바른 각도를 계산할 수 없었습니다.


🤔 해결하기 위한 고민

방향 보정 로직

  1. 이미지의 기본 방향

    이미지의 기본 상태가 남쪽(270도)을 향하고 있음을 고려해 각도를 보정해야 했습니다.

    • 북쪽(0도)을 가리킬 때 이미지가 180도 회전(뒤집힘)해야 했습니다.
    • 동쪽(90도)과 서쪽(270도) 방향에서도 이를 기준으로 회전 방향을 조정해야 했습니다.
  2. 라디안 변환 및 보정

    • α 값(휴대폰 방향)의 기본 범위는 0~360도입니다. 이를 회전 계산에 활용하기 위해 0~2π 라디안 값으로 변환해야 했습니다.
    • 북쪽을 기준으로 0도로 맞추고, 이미지가 기본 방향에서 180도 회전해야 하는 것을 반영하기 위해 추가적인 보정을 적용했습니다.

계산식 설계

  • 북쪽 (0도): 180도(π 라디안)로 회전.
  • 동쪽 (90도): 0도로 회전.
  • 서쪽 (270도): 90도(π/2 라디안)로 회전.

이를 반영한 최종 식은 다음과 같습니다:

correctedAlpha = (((alpha - 90) + 180) % 360) * (Math.PI / 180);

✨ 해결했을 때 코드와 결과

최종 코드

아래는 보정된 α 값을 적용해 캐릭터 이미지를 회전시키는 최종 코드입니다:

let previousAlpha = null;

function smoothAlpha(alpha, previousAlpha, smoothingFactor = 0.1) {
  if (previousAlpha === null) return alpha;
  return previousAlpha + (alpha - previousAlpha) * smoothingFactor;
}

const normalizedAlpha = (alpha + 360) % 360; // 0~360도 정규화
const smoothedAlpha = smoothAlpha(normalizedAlpha, previousAlpha);
const correctedAlpha = (((smoothedAlpha - 90) + 180) % 360) * (Math.PI / 180);

previousAlpha = smoothedAlpha; // 이전 값을 업데이트

drawMarker(
  ctx,
  currentLocation,
  character1Ref.current,
  zoom,
  correctedAlpha, // 보정된 alpha 값 전달
  guests![0]?.markerStyle.color,
  MARKER_TYPE.CHARACTER,
);

결과

  1. 북쪽 (0도): 이미지가 180도 회전하여 발자국이 북쪽을 가리킴.
  2. 동쪽 (90도): 이미지가 회전 없이 발자국이 동쪽을 가리킴.
  3. 서쪽 (270도): 이미지가 90도 회전하여 발자국이 서쪽을 가리킴.

🛠️ 결론

결국 이 로직을 통해 캔버스 위의 캐릭터가 사용자의 휴대폰 방향과 일치하도록 수정할 수 있었습니다.

이번 경험을 통해… 마지막에 촉박하게 밤을 새지 않으려면,,, 생각하지 못한 부분이 없나 계속해서 확인하고 생각해야 한다는 점….. 그리고 물론 폭설과 계엄령 이슈 때문에 실 테스트를 미리 해보지 못했지만,,, 테스트는 미리미리 해둬야 한다는 점…… 을 절실하게 또 한 번 느낄 수 있었습니다,,,

0개의 댓글