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으로 생성된다.▼

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

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

// 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에는 그런 느낌이 없다.
● 사용 명령어를 적절히 사용하면 생각보다 직관적으로 표현되어 있어서 어디에 쓰는지 바로 알 수 있었다.