πŸ–Œ μΊ”λ²„μŠ€ μœ„μ—μ„œ 캐릭터λ₯Ό νšŒμ „μ‹œν‚€κ³  λ„€μ˜¨ 효과 μž…νžˆκΈ°

μ •ν˜œμΈΒ·2024λ…„ 12μ›” 1일
0

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” HTML Canvasλ₯Ό μ‚¬μš©ν•˜μ—¬ 지도 μœ„μ— μ‹€μ‹œκ°„ μœ„μΉ˜μ™€ λ°©ν–₯을 ν‘œμ‹œν•˜λŠ” 방법에 λŒ€ν•΄ κ³΅μœ ν•˜λ €κ³  ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, 지도 μœ„μ— μ‚¬μš©μž λ˜λŠ” 객체의 μœ„μΉ˜μ™€ κ·Έ λ°©ν–₯을 λ‚˜νƒ€λ‚Ό 수 μžˆλŠ” 방법을 κ΅¬ν˜„ν•΄λ΄€μŠ΅λ‹ˆλ‹€.

이 κ³Όμ •μ—μ„œ μ€‘μš”ν•œ 점은 μœ„μΉ˜ ν‘œμ‹œλΏλ§Œ μ•„λ‹ˆλΌ λ°©ν–₯ ν‘œμ‹œκΉŒμ§€ μΆ”κ°€ν•˜λŠ” κ²ƒμ΄μ—ˆμŠ΅λ‹ˆλ‹€.

🌈 1. λ„€μ˜¨ 효과둜 μœ„μΉ˜ ν‘œμ‹œν•˜κΈ°

λ¨Όμ €, μœ„μΉ˜λ₯Ό ν‘œμ‹œν•  λ•Œ λ„€μ˜¨ 효과λ₯Ό μ£ΌκΈ° μœ„ν•΄ 원을 κ·Έλ ΈμŠ΅λ‹ˆλ‹€.

이 원은 쀌 λ ˆλ²¨μ— 따라 크기가 μ‘°μ •λ˜λ„λ‘ μ„€μ •ν–ˆμœΌλ©°, μ›μ˜ 색상은 νŒŒλž€μƒ‰μœΌλ‘œ μ€μ€ν•˜κ²Œ λ‚˜νƒ€λ‚˜λ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€.

이λ₯Ό μœ„ν•΄ createRadialGradientλ₯Ό μ‚¬μš©ν•˜μ—¬ 원 μ•ˆμ—μ„œ 색상이 점점 투λͺ…해지도둝 λ§Œλ“€μ–΄μ€¬μŠ΅λ‹ˆλ‹€.

const radius = zoom * 3; // μ›μ˜ λ°˜μ§€λ¦„ (쀌 λ ˆλ²¨μ— 따라 크기 μ‘°μ •)
const gradient = ctx.createRadialGradient(point.x, point.y, 0, point.x, point.y, radius);
gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)'); // μ›μ˜ 쀑앙
gradient.addColorStop(1, 'rgba(0, 0, 255, 0)'); // μ›μ˜ λ°”κΉ₯μͺ½

ctx.beginPath();
ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI);
ctx.fillStyle = gradient;
ctx.fill();

🌟 2. λ°©ν–₯ ν‘œμ‹œν•˜κΈ° (νšŒμ „λœ 이미지)

이제 μ€‘μš”ν•œ 뢀뢄인 λ°©ν–₯ ν‘œμ‹œλ₯Ό μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€. λ°©ν–₯은 μ„Έλͺ¨ λͺ¨μ–‘μ˜ μ•„μ΄μ½˜μ„ μ‚¬μš©ν•˜κΈ°λ„ ν–ˆμ§€λ§Œ, 더 직관적인 이미지λ₯Ό μ‚¬μš©ν•˜κΈ° μœ„ν•΄ μ΄λ―Έμ§€λ‘œ λ°©ν–₯을 ν‘œμ‹œν•˜λŠ” 방법을 μ„ νƒν–ˆμŠ΅λ‹ˆλ‹€.

μ΄λ―Έμ§€λŠ” μ€‘μ‹¬μœΌλ‘œλΆ€ν„° offset만큼 떨어진 μœ„μΉ˜μ— 배치된 ν›„, μ‚¬μš©μžμ˜ λ°©ν–₯을 따라 νšŒμ „ν•©λ‹ˆλ‹€.

νšŒμ „λœ λ°©ν–₯을 μ œλŒ€λ‘œ λ‚˜νƒ€λ‚΄κΈ° μœ„ν•΄, direction 값에 맞좰 이미지λ₯Ό νšŒμ „μ‹œμΌ°μŠ΅λ‹ˆλ‹€. μ€‘μ‹¬μ—μ„œλΆ€ν„° 일정 거리만큼 떨어진 μœ„μΉ˜μ— 이미지λ₯Ό 놓고, κ·Έ μ΄λ―Έμ§€λŠ” 지도 μœ„μ—μ„œ μ‹€μ œ λ°©ν–₯에 맞게 νšŒμ „ν•˜λ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€.

const triangleSize = zoom * 2; // 이미지 크기 (쀌 λ ˆλ²¨μ— 따라 크기 μ‘°μ •)
const offset = zoom * 2; // 이미지가 μ€‘μ‹¬μ—μ„œ λ²—μ–΄λ‚˜λ„λ‘ ν•  거리

ctx.save();
ctx.translate(point.x, point.y); // 쀑심 μœ„μΉ˜λ‘œ 이동
ctx.rotate(direction); // λ°©ν–₯에 맞좰 νšŒμ „

const xOffset = 0; // 12μ‹œ λ°©ν–₯ (xμΆ•)
const yOffset = -offset; // 12μ‹œ λ°©ν–₯으둜 μœ„μͺ½μœΌλ‘œ 이동

ctx.beginPath();
ctx.drawImage(
  footStepsRef.current!, // 이미지 (둜컬 파일둜 λ‘œλ”©)
  xOffset - triangleSize / 2, // 이미지 μœ„μΉ˜
  yOffset - triangleSize / 2,
  triangleSize, // 이미지 크기
  triangleSize,
);
ctx.restore();

πŸŒ€ 3. νšŒμ „ 보정

이미지가 μ •ν™•νžˆ 12μ‹œ λ°©ν–₯μ—μ„œ 0λ„λ‘œ μ‹œμž‘ν•  수 μžˆλ„λ‘ νšŒμ „ 보정도 μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.

기본적으둜, direction 값이 320λ„μ—μ„œ μ‹œμž‘ν•˜λ„λ‘ μ„€μ •ν•˜μ˜€κ³ , 이 값을 λ³΄μ •ν•˜μ—¬ 이미지λ₯Ό μ •ν™•νžˆ 0도 λ°©ν–₯으둜 νšŒμ „ν•˜λ„λ‘ ν–ˆμŠ΅λ‹ˆλ‹€.

μ΄λ ‡κ²Œ ν•˜λ©΄ 이미지가 12μ‹œ λ°©ν–₯μ—μ„œ μ‹œμž‘ν•˜λ©°, 이후 νšŒμ „ν•  λ•Œ μžμ—°μŠ€λŸ½κ²Œ μ›€μ§μž…λ‹ˆλ‹€.

const correctedDirection = (direction - 320 + 360) % 360;  // λ°©ν–₯ 보정
const radian = (correctedDirection * Math.PI) / 180; // λΌλ””μ•ˆ κ°’μœΌλ‘œ λ³€ν™˜
ctx.rotate(radian); // λ³΄μ •λœ λ°©ν–₯으둜 νšŒμ „

πŸ“Œ 4. μ΅œμ’… μ½”λ“œ

μœ„ λ‚΄μš©μ„ μ’…ν•©ν•œ μ΅œμ’… μ½”λ“œλŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

이 μ½”λ“œλ₯Ό 톡해 지도 μœ„μ— μ‹€μ‹œκ°„μœΌλ‘œ μœ„μΉ˜μ™€ νšŒμ „ν•˜λŠ” λ°©ν–₯을 ν•¨κ»˜ ν‘œμ‹œν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

const drawNeonCircleAndDirection = (
  ctx: CanvasRenderingContext2D,
  point: { x: number; y: number } | null,
  zoom: number,
  direction: number,
) => {
  if (!point) return;

  // 원 그리기 (λ„€μ˜¨ 효과)
  const radius = zoom * 3;
  const gradient = ctx.createRadialGradient(point.x, point.y, 0, point.x, point.y, radius);
  gradient.addColorStop(0, 'rgba(0, 0, 255, 0.5)');
  gradient.addColorStop(1, 'rgba(0, 0, 255, 0)');

  ctx.beginPath();
  ctx.arc(point.x, point.y, radius, 0, 2 * Math.PI);
  ctx.fillStyle = gradient;
  ctx.fill();

  // λ°©ν–₯ ν‘œμ‹œ
  const triangleSize = zoom * 2;
  const offset = zoom * 2;

  ctx.save();
  ctx.translate(point.x, point.y);

  // λ°©ν–₯ 보정 (320도λ₯Ό κΈ°μ€€μœΌλ‘œ 0λ„λ‘œ 보정)
  const correctedDirection = (direction - 320 + 360) % 360;
  const radian = (correctedDirection * Math.PI) / 180;
  ctx.rotate(radian);

  const xOffset = 0;
  const yOffset = -offset;

  ctx.beginPath();
  ctx.drawImage(
    footStepsRef.current!,
    xOffset - triangleSize / 2,
    yOffset - triangleSize / 2,
    triangleSize,
    triangleSize,
  );

  ctx.restore();
};

πŸ–Œ 5. κ²°λ‘ ...?

이 방법을 톡해 μ‹€μ‹œκ°„μœΌλ‘œ 지도 μœ„μ— μœ„μΉ˜μ™€ λ°©ν–₯을 ν‘œμ‹œν•˜λŠ” κΈ°λŠ₯을 κ΅¬ν˜„ν•  수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

HTML Canvas와 이미지 νšŒμ „, λ„€μ˜¨ 효과 등을 ν™œμš©ν•˜μ—¬ 더 직관적이고 μ‹œκ°μ μΈ ν‘œμ‹œκ°€ κ°€λŠ₯ν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.

canvas에 λŒ€ν•΄ λ§Žμ€ μž‘μ—…μ„ ν•΄λ³Έ 적이 μ—†μ—ˆλŠ”λ°, μ΄λ ‡κ²Œ 예쁘게 μ™„μ„±λ˜λŠ” 것을 λ³΄λ‹ˆβ€¦β€¦ λ„ˆλ¬΄ μ˜ˆμ˜λ”λΌκ³ μš”β€¦.

ν™•μ‹€νžˆ μ €λŠ” ν”„μ—” κ°œλ°œμžμΈκ°€ λ΄…λ‹ˆλ‹€β€¦β€¦β€¦β€¦β€¦β€¦

0개의 λŒ“κΈ€