위치 동기화
-
현재 게임에 참여하면 핑을 주고 받기 시작한다
-
이제 게임에 참여한 인원들의 위치를 서버와 클라이언트끼리 동기화 해주어야한다
게임 내 위치 동기화
- Game class 에서 모든 유저 위치 정보를 알려주는 메서드를 생성한다
// Game class 메서드
getAllLocation (playerId) {
// 게임 내 전체 유저 위치 확인
const payload = Array.from(this.users).map(([id, user]) => {
{
return {
id: user.id,
playerId: user.playerId,
x: user.x,
y: user.y,
}
}
})
return { users: payload }
}
- 이제 이를 IntervalManger를 이용해 일정시간마다 동기화 해주기 위해 User class에 메서드를 만든다
//User class 메서드
updateAllLocation = () => {
const game = games.games.get(this.gameId)
const payload = game.getAllLocation()
this.socket.write(createLocation(payload))
}
- IntervalManger에 바인딩!
// Game에 유저가 추가되었을 시 0.2초마다 위치 동기화
addUser(user) {
user.updateGameId(this.id)
this.users.set(user.id, user)
// 핑 관리
this.intervals.addInterval(user.id, user.ping, 200)
// 위치 동기화 관리
this.intervals.addInterval(user.id, user.updateAllLocation, 200, location)
}
클라이언트 Location 관리
-
현재 위에선 서버에서 일방적으로 클라이언트에게 몇초마다 위치정보를 공유해준다!
-
하지만 클라이언트가 움직인 정보를 받아오는 핸들러가 없다..
-
이에 필요한 핸들러와 관련 user method를 사용해준다!
// 위치 업데이트 핸들러
export const locationUpdate = ({ socket, userId, payload }) => {
const user = users.getUser({userId})
// 유저의 위치를 받아온 값으로 지정해줌
user.updatePosition(payload.x, payload.y)
}
멀티플레이 실험
- Unity에서 멀티플레이를 실험해보기 위해 MPPM(MultiPlay Play Mode) Package를 사용하였다!
-
잘 보면 자신의 위치에 받아온 값으로 캐릭터를 생성하여 자신을 밀쳐내는… 버그가 있다!
-
그럼 받아온 값에서 자신을 제외하면 되나? 라고 생각을 했지만
-
서버에서 받아온 값의 우선순위가 높으므로 자신의 위치를 변경하는 것이 옮은 것 같다!
오류 해결
- 일단 서버에서 받아올 때 user의 id 값을 받아오기에 이를 클라이언트의 값과 비교해 다른 로직을 적용해주면 될 것 같다!
// 받아온 data 에서 users를 순회하며 spawn 하도록 해주는 곳
foreach(LocationUpdate.UserLocation user in data.users) {
// 만약 받아온 값중 id가 player id와 같으면
if (user.id == GameManager.instance.player.deviceId)
{
//player 의 위치를 받아온 값으로 이동시켜주기
GameManager.instance.player.UpdatePositionFromServer(user.x, user.y);
// 아닐 경우 기존 로직대로 생성
} else {
newUsers.Add(user.id);
GameObject player = GameManager.instance.pool.Get(user);
PlayerPrefab playerScript = player.GetComponent<PlayerPrefab>();
playerScript.UpdatePosition(user.x, user.y);
}
}
- 서버에서 Latency 계산식(추측항법)을 넣어주지 않아서 그런지 뚝뚝 끊긴다..
마지막 위치
-
일단 동기화로 플레이어들끼리 위치를 표시해줄 순 있었다!
-
앞으로 접속 종료 및, 오류로 튕긴 후 재접속 시 이전의 자리로 돌려주는 로직을 구현할 것이다!
연결 종료
-
일단 현재 Unity 시뮬레이션을 종료했음에도 TCP 연결이 끊어지지 않는다!
-
나가기 버튼을 클라이언트에 만들어 클라이언트에서 TCP 연결 및 게임을 종료할 수 있도록 해주어야 겠다
DB 연동
-
현재 플레이어의 device Id를 서버에 보내주며 접속을 하는데.. 이를 저장해두는 매체가 없다
-
플레이어들을 device Id로 구분하여 마지막 위치를 저장해줄 DB를 구성해 주어야겠다
import { config } from "../config/config.js";
import mysql from 'mysql2/promise'
const { database } = config;
const createPool = (dbConfig) => {
const pool = mysql.createPool({
host: dbConfig.host,
port: dbConfig.port,
user: dbConfig.user,
password: dbConfig.password,
database: dbConfig.name,
waitForConnections: true,
connectionLimit: 10,
queueLimit: 0
});
return pool;
}
const pools= {
USER_DB: createPool(database.USER_DB)
}
export default pools;
- 이제 연결확인을 해줄 함수도 만들어 init/index.js에 포함시켜준다
/* utils/db/testConnection.js */
const testDBConnection = async (pool, dbName) => {
try{
const [rows] = await pool.query('SELECT 1 + 1 AS solution')
console.log(`${dbName} 연결 확인결과 ${rows[0].solution}`)
}catch(e) {
console.error(dbName,"연결 실패")
}
}
export const testAllConnections = async (pools) => {
Object.entries(pools).forEach(async ([name, pool]) => {
await testDBConnection(pool, name)
})
}
/* init/index.js */
export const initServer = async () => {
try {
// 현재 서버에 게임 하나만 돌아가도록 설정
gameId = await games.createGame();
await loadProtobufs();
// db 연결 확인
await testAllConnections(pools);
} catch (e) {
console.error(e)
process.exit(1)
}
}
한줄 평 + 개선점
- 오늘 생각보다 진도가 나간 것 같아 좋지만! 전체적 진도는 조금 아쉽다.. 화이팅!