[오늘의 코딩테스트]
추후 추가 예정
[오늘의 한일]
● 팀 매칭 기능 추가
● 상점 가챠 랜덤 로직 구현
● 랭킹 시스템 구현
● 팀 매칭 기능 추가
기존 매칭 시스템의 경우 따로 상대방을 파라미터 값으로 받아와 로그인한 유저와 경기를 붙는 시스템을 구현하였다. 이렇게 할 경우 너무 게임성이 단조로워져서 레이팅(점수)가 비슷한 상대 중 랜덤 5명중 한명을 골라서 매칭을 하게끔 구현해 주었다. 우선 그러기 위해서 데이터베이스를 추가해주었다.
위와 같이 매치큐라는 모델을 만들어주었고, 팀이 다 완성이 된 유저를 기준으로 유저가 팀을 다완성 시킬 때 매치큐에 유저를 넣어줘서 매치에 참여할 조건(팀이 완성)을 모두 채운 유저들을 기준으로 매칭을 잡아주게끔 구현하였다.
const matchMaking = async (myUserId) => {
const me = await ec.userChecker(myUserId);
const opponent = await userPrisma.$queryRaw`
SELECT *
FROM MatchQueue mq
INNER JOIN User u
ON mq.user_id=u.user_id
ORDER BY ABS(u.rating - ${me.rating})
LIMIT 10
`;
if (opponent.length < 2) throw new Error("상대를 찾을 수 없습니다.");
const index = Math.trunc(Math.random() * (opponent.length - 1)) + 1;
return opponent[index];
};
게임 부분을 뺀 매치메이킹 시스템을 나타내는 함수이다. 함수에 자신의 userId를 받아오고, MatchQueue에서 유저아이디를 가져오고 비슷한 레이팅을 기준으로 userId를 나열한다음 길이가 2이상(1이면 스스로만 존재) 할 경우에만 로직이 돌아가게끔 하고, 그 길이중 랜덤으로 한명을 골라 0을 뺀 나머지 수중에 랜덤으로 나오게끔 하여 매치큐의 아이디를 가져와 해당 아이디를 기준으로 게임을 하게끔 하였다. Rawqueue를 사용하여 바로 데이터베이스를 가져오게끔 하였다.
● 상점 가챠 랜덤 로직 구현
상점 가챠 시스템의 로직을 바꿔주었다. 우리의 가챠 확률의 티어는 0~4티어가 존재하고 각각 0티어 : 5%, 1티어 : 10%, 2티어 : 20%, 3티어 : 30%, 4티어 : 35%로 구현하였다. 그리고 상점에서 뽑기를 진행할 때 같은 플레이어 아이디 값을 가지고 있을 경우 같은 플레이어 이므로, 수량이 겹쳐져서 count가 1이 늘어나도록 구현하였다.
const GACHA_STANDARD_PACK_PRICE = 1000;
const GACHA_STANDARD_PACK_RATES = [5, 10, 20, 30, 35];
// const GACHA_MAX = 5; // 0~4, 5 is converted to 4
const gacha = async () => {
// implement gacha logic, returns player
const gachaTier = Math.floor(Math.random() * 99 + 1);
let acc = 0;
for (let i = 0; i < GACHA_STANDARD_PACK_RATES.length; i++) {
if ((acc += GACHA_STANDARD_PACK_RATES[i]) >= gachaTier) {
acc = i;
break;
}
}
const players = await playerPrisma.player.findMany({
where: { TierName: acc },
});
const gachaPlayer = Math.trunc(Math.random() * players.length);
if (gachaPlayer == players.length) gachaPlayer--;
return players[gachaPlayer];
};
● 랭킹 시스템 구현
랭킹 시스템을 구현하였다.
req.query로 userId를 입력받으면 해당 유저의 랭킹이 나오도록 하였고, 아닐 경우 pageNumber와 loadcount로 페이지네이션이 존재하는 랭킹 시스템을 구현하였다. 랭킹 시스템은 rawquery로 작업하였고, rank()라는 로우쿼리 함수가 존재하여서 해당함수를 사용하였다.
const userRanking = async (userId) => {
return await userPrisma.$queryRaw`
SELECT *
FROM (
SELECT CONVERT(RANK()OVER(ORDER BY rating DESC), CHAR) as ranking,
user_id as userId,
username,
rating,
CONCAT(wins,'/',draws,'/',loses) as 'W/D/L'
FROM User
) a
WHERE userId=${userId}
`;
};
const allRankings = async (pageNumber, loadCount) => {
const start = (pageNumber - 1) * loadCount;
return await userPrisma.$queryRaw`
SELECT *
FROM (
SELECT CONVERT(RANK()OVER(ORDER BY rating DESC), CHAR) as ranking,
user_id as userId,
username,
rating,
CONCAT(wins,'/',draws,'/',loses) as 'W/D/L'
FROM User
) a
WHERE ranking > ${start}
LIMIT ${loadCount}
`;
};
[오늘의 어려웠던 점]
- 매칭 기능에서 매칭이 돌아갔지만 계속 점수가 안바뀌는 경우
사실 이 경우는 가장 비슷한 점수를 가진 상대를 찾았을 때, 상대 opponent[0]를 받아서 그렇다. 자기와 가장 비슷한 점수는 본인 스스로이기 때문에 0가 아닌 다른 수를 적용시켜야지 매치가 정상적으로 돌아간다.
- 랭킹 시스템 랭크 함수를 rawquery로 사용하려하려하였을 때 Big INT 에러가 나옴
이것은 랭크라는 함수를 사용한 결과 값이 너무 큰 수로 나올 수 있기 때문에 나온 것이다. INT를 CONVERT함수를 통해 CHAR로 바꿔주어 해결하였다.
[한줄평]
전체적으로 팀원과 프로젝트를 잘 마무리하면서, 기능들을 대부분 다 구현한것 같다! 다음번에도 열심히 해야겠다.
'코딩 > TIL' 카테고리의 다른 글
[TIL/29일차] 테스트 코드(JEST), 게임서버의 이해 (1) | 2024.06.11 |
---|---|
[TIL/28일차] 객체지향, 아키텍쳐 패턴 (0) | 2024.06.10 |
[TIL/26일차] 팀 프로젝트 진행 - 2 (1) | 2024.06.03 |
[TIL/25일차] 새로운 팀 프로젝트 시작 (0) | 2024.06.03 |
[TIL/24일차] EC2서버에 프로젝트 배포 (0) | 2024.05.28 |