Project_xxx

[Project_] TD - Final

wakelight23 2025. 1. 2. 20:58

Socket 통신을 사용한 Tower Defense 프로젝트 마무리

● 최고 기록(HighScore)을 구현

// src/handlers/game-handler.js
// 게임이 종료될 때 저장되는 점수
let finalScore = serverScore;
  let message = "";
  if (status === "clear") {
    finalScore += serverGold; // 게임 클리어 시 서버 골드와 클라이언트의 남은 골드를 더함
    message = `클리어로 추가 점수 ${serverGold}점을 얻어 최종 점수 ${finalScore}점 입니다!`;
  } else if (status === "gameOver") {
    finalScore; // 게임 오버 시 골드를 더하지 않음
    message = `게임오버로 최종 점수 ${finalScore}점 입니다!`;
  }

 - 게임 오버일 때 처리가 없으면 목표가 정해지지 않아 게임이 지루해질 것이다.

 - 목표를 추가함으로써 게임을 끝까지 하도록 유도하거나 경쟁을 유도할 수 있다.

 

● Redis에 저장!

// Redis에 사용자 이메일과 최종 점수 저장
    const email = await getUserEmail(userId);

    // Redis에서 현재 사용자 점수를 조회
    const currentScore = await redisClient.zScore("leaderboard", email);

    if (!currentScore || finalScore > parseInt(currentScore, 10)) {
      // 새로운 점수가 기존 점수보다 높을 경우에만 업데이트
      await redisClient.zAdd("leaderboard", {
        score: finalScore,
        value: email,
      });

      // 상위 순위만 유지 (10개 초과 시 하위 순위 제거)
      const totalRankings = await redisClient.zCard("leaderboard"); // 전체 랭킹 개수 확인
      if (totalRankings > 10) {
        await redisClient.zRemRangeByRank(
          "leaderboard",
          -1,
          -(totalRankings - 10),
        );
      }

      console.log(`스코어 보드 업데이트 완료: ${email} - ${finalScore}`);
    } else {
      console.log(
        `기존 점수가 더 높거나 동일합니다. 업데이트 생략: ${email} - ${currentScore}`,
      );
    }

 - Redis에 zAdd, zCard, zScore, zRemRangeByRank 명령어가 존재하여 스코어 보드를 구현하기 적합한 명령어가 존재함

 - zAdd로 데이터를 생성하게 되면 Sorted Set으로 생성된다.▼

Sorted Set

 - 위의 코드대로 생성된 데이터는 아래와 같다. ▼

vscode에서 Redis 확장 툴로 확인해보면 표 형태로 생성된다

 

 

어디서 랭킹 업데이트를 표시해줄까?

프론트엔드에서 표시될 때

 

// public/src/index.html
// 스코어보드 업데이트 함수
      const fetchLeaderboard = async () => {
        try {
          // 랭킹 데이터 요청
          const response = await fetch("/api/ranking"); // ranking-router.js에 구현된 API 호출
          if (!response.ok)
            throw new Error("랭킹 데이터를 가져오는 데 실패했습니다.");

          const data = await response.json();
          updateScoreboard(data.leaderboard); // 스코어보드 업데이트 함수 호출

          console.log("랭킹 데이터 갱신 완료:", data.leaderboard);
        } catch (err) {
          console.error("스코어보드 데이터를 가져오는 중 오류 발생:", err);
        }
      };

 - 랭킹 구현은 웹 서버 통신으로 구현하였고, 새로고침 할 때마다 갱신

 

// src/routes/ranking-router.js
const leaderboardData = await redisClient.sendCommand([
      'ZREVRANGE',
      'leaderboard',
      '0',
      '9',
      'WITHSCORES',
    ]);

 - 최대한 Redis를 사용해서 구현해 보았다.
 - 위 코드는 redisClient에 zAdd 이런 명령어처럼 즉각 처리하는 것이 아닌 redisClient 자체에 명령어를 전달해서 처리하는
   코드이다. → redisClient.sendCommand()

 


Redis를 쓰면서 느낀 점 

● mySQL을 쓸 때는 불러올 때 local 환경에서도 약간의 딜레이가 있었는데 Redis에는 그런 느낌이 없다.

● 사용 명령어를 적절히 사용하면 생각보다 직관적으로 표현되어 있어서 어디에 쓰는지 바로 알 수 있었다.