Intro
개발 환경을 구축하고 사용자가 처음 접속하면 보여질 방과 관련된 기능들을 개발했다.
사용자가 방을 생성하고, 다른 사용자가 생성된 방에 참가하면 오목 경기를 시작시킬 것이다.
그 후에 들어오는 사용자들은 관전자로 놔둘 생각이다.
React를 처음 써봐서 기능을 개발하며 많이 헤맸지만, 생각보다 간단하고 강력한 기능을 제공해줘서 금방 이정도까지 만들 수 있었던것 같다.
방 생성

input에 방 이름을 입력하고 Enter를 치거나 '방 만들기' 버튼을 클릭하면 해당 이름으로 방이 생성된다.
아래의 경우 방이 생성되지 않도록 설정했다.
- 같은 이름의 방이 이미 존재하는 경우
- 사용자가 이미 다른 방에 참가중인 경우
- 방 이름에 아무것도 입력하지 않았을 경우
코드는 아래와 같다.
이벤트 발생 시 roomname이 공백인지 확인하고 서버에 'room_new' Event로 방 이름을 전달하도록 했다.
const NewRoom = () => {
const handleNewRoom = (event) => {
event.preventDefault();
const name = event.target.roomname.value;
event.target.roomname.value = "";
if (name.length == 0) return;
socket.emit("room_new", name);
};
return (
<div className="newroom">
<form className="newroom__form" onSubmit={handleNewRoom}>
<input
className="newroom__input"
type="text"
name="roomname"
placeholder="방 이름"
></input>
<button className="newroom__submit">방 만들기</button>
</form>
</div>
);
};
방 목록

사이트에 접속하면 소켓이 연결되며 방 목록을 조회하도록 설정했다.
서버에서 온 Object Array를 React Component Array로 바꾸는데 고생 좀 했다.
socket.on을 함수 밖으로 빼내고 싶었는데 roomList는 함수 밖으로 꺼내면 에러가 발생해서 어쩔 수 없이 socket.on을 함수 내부에 뒀다.
같은 socket event listener를 여러개 둘 수 있기 때문에 별 문제는 안되겠지만 나중에 해결방법이 떠오르면 고쳐야겠다.
const RoomItem = (room) => {
const handleEnterRoom = () => {
socket.emit("room_enter", room.name);
};
return (
<li key={room.name} className="room-list__item">
<p className="room-list__name">{room.name}</p>
<button className="room-list__enter" onClick={handleEnterRoom}>
입장하기
</button>
</li>
);
};
const RoomList = () => {
const [roomList, setRoomList] = React.useState([]);
socket.on("room_change", (list) => {
setRoomList(list);
});
return (
<div className="room-list">
<h3>방 목록</h3>
<ul className="room-list__container">{roomList.map(RoomItem)}</ul>
</div>
);
};
서버 코드는 아래와 같다.
wsServer.on("connection", (socket) => {
socket.onAny((event) => {
console.log(`Socket event: ${event}`);
});
//방 만들기
socket.on("room_new", (name) => {
name = name.trim();
console.log(`Socket ${socket.id} is creating room ${name}.`);
//Socket은 ID와 같은 Room을 Default로 갖고 있음
if (socket.rooms.size > 1) {
console.log(`socket ${socket.id} is already in room.`);
console.log(socket.rooms);
socket.emit("error", "이미 다른 방에 참가중입니다.");
return;
}
//동일한 방이 존재할 경우
if (!checkDuplicateRoomName(name)) {
console.log(`Room name ${name} already exists.`);
socket.emit("error", "동일한 방이 이미 존재합니다.");
return;
}
const roomInfo = {
name: "room",
blackPlayer: "",
whitePlayer: "",
takes: [],
};
roomInfo.name = name;
roomInfo.blackPlayer = socket.id;
publicRoom.push(roomInfo);
wsServer.sockets.emit("room_change", publicRoom);
socket.join(name);
socket.emit("room_enter", name);
console.log(publicRoom);
});
방 참가 / 퇴장

방 생성 / 참가 이후에 서버에서 'room_enter' 이벤트를 주면 오목 게임이 진행되는 방으로 화면이 전환된다.
게임 화면은 아직 구현되지 않았다.
방 나가기 버튼을 누르면 서버에 'room_leave' 이벤트를 주고, 서버에서 이벤트를 다시 주면 대기실 화면으로 전환된다.
'room_enter', 'room_leave' 이벤트가 들어오면 gaming state를 변경하고, state에 따라 화면을 다시 렌더링한다.
const WaitingRoom = () => {
return (
<>
<NewRoom />
<RoomList />
</>
);
};
const GamingRoom = () => {
return (
<>
<button
onClick={() => {
socket.emit("room_leave");
}}
>
방 나가기
</button>
</>
);
};
const App = () => {
const [gaming, setGaming] = React.useState(false);
socket.on("room_enter", () => {
setGaming(true);
});
socket.on("room_leave", () => {
setGaming(false);
});
return (
<>
<Header />
{gaming ? <GamingRoom /> : <WaitingRoom />}
</>
);
};
방 퇴장 시 자꾸 이런 에러가 뜨는데 나중에 수정해야겠다.

대기실 화면

다음엔 실제 오목 게임을 구현해야겠다.
'Projects > Socket Omok' 카테고리의 다른 글
[Socket Omok] 6. 착수 위치 미리보기 및 선택하기 (0) | 2022.06.13 |
---|---|
[Socket Omok] 5. 바둑판, 바둑알 표시하기 (0) | 2022.06.06 |
[Socket Omok] 4. 플레이어 참가 기능 개발 (0) | 2022.06.06 |
[Socket Omok] 2. 개발환경 구성하기 (0) | 2022.06.02 |
[Socket Omok] 1. 프로젝트 시작 (0) | 2022.05.31 |