이번에 추가할 내용을 server.js랑 App.js를 나눠서 정리해보면
server.js
Map → mdn
const userSocketIdMap = new Map();
const wordMap = new Map();
배열말고 map을 사용해서 데이터를 저장해줄겁니다
데이터베이스에다가 하면 더 편하고 쉬울텐데 너무 커질까바 서버에서만 데이터 저장합니다
socket
io.on("connection", (socket) => {
socket.on("join", (userId) => {
if (userSocketIdMap.size === 0) {
userSocketIdMap.set("user1", userId);
io.emit("join", `hi user1 ${userId}`);
} else {
userSocketIdMap.set("user2", userId);
io.emit("join", `hi user2 ${userId}`);
}
console.log(userSocketIdMap.keys(), userId);
});
socket.on("start", () => {
if (userSocketIdMap.size === 2) {
const randomWord = randomChosung();
wordMap.set("word", randomWord);
io.emit("start", randomWord);
}
});
socket.on("message", ({ fromId, message }) => {
io.emit("message", { fromId, message });
});
join → 서버에서 join은 map을 이용해 size가 0이면 user1을 저장하고 아니면 user2로 저장 (아직 삭제기능이 없지만 실행가능)
start → 서버에서 start는 user map을 이용행 size가 2이면 랜덤초성을 만들고 초성을 map에 저장하고 emit으로 cilent로 보냄
message→ 서버에서 message는 서버에 들어온 메세지를 각 클라이언트로 보냄(fromId는 턴을 정할때 사용)
randomChosung 함수 → 랜덤으로 초성을 뽑는 함수
const word = [
"ㄱ",
"ㄴ",
"ㄷ",
"ㄹ",
"ㅁ",
"ㅂ",
"ㅅ",
"ㅇ",
"ㅈ",
"ㅊ",
"ㅋ",
"ㅌ",
"ㅍ",
"ㅎ",
];
function randomChosung() {
const chosung = [
word[Math.ceil(Math.random() * word.length) - 1],
word[Math.ceil(Math.random() * word.length) - 1],
];
return chosung.join("");
}
랜덤으로 자음을 뽑는다 Math.ceil 소수점 Math.random() * (뽑고싶은 숫자제한 ex. 0~10까지 이면 10) -1을 안하면 0이 안나옵니다
App.js
state
const [connect, setConnect] = useState(false);
const [word, setWord] = useState("");
const [list, setList] = useState([]);
connect 는 연결확인용
word는 서버로부터 받은 word를 화면에 표시
list는 유저들이 썻던 단어를 받아 화면에 배열
socket
useEffect(() => {
socket.on(EVENTS.JOIN, (text) => {
console.log(text);
});
socket.on(EVENTS.START, (word) => {
setWord(word);
});
socket.on(EVENTS.MESSAGE, ({ fromId, message }) => {
setList((prev) => [...prev, message]);
setValue("wordInput", "");
});
socket.on(EVENTS.END, (winner) => {});
}, [setValue]);
return (
...
{connect ? (
<form onSubmit={handleSubmit(onValid)}>
...
</form>
) : (
<Button
onClick={() => {
socket.emit(EVENTS.JOIN, socket.id);
socket.emit(EVENTS.START);
setConnect(true);
}}
>
Join Game
</Button>
)}
...
)
useEffect → React
join → 클라이언트에서 join은 초기화면에 button을 누르면 연결 emit하고 useEffect에서 text를 출력합니다
start → start도 button을 누르면 스타트하고 useEffect에서 word를 받아서 word를 바꿔줍니다
message → 메세지는 인풋에 알맞는 단어를 입력시 서버에 보내고 받을 때는 받아서 list에 넣어줍니다
react-hook-form → input 설정을 도와준다
...
const { register, handleSubmit, getValues, setValue } = useForm({
mode: "onSubmit",
});
const onValid = () => {
const { wordInput } = getValues();
const checkedWord = checkWord(wordInput); //인풋에 입력된 단어를 자음형식으로 바꾼다
if (checkedWord === word) {
// 자음형식으로 바뀐 인풋단어를 문제와 비교
socket.emit(EVENTS.MESSAGE, { fromId: socket.id, message: wordInput }); //비교해서 같으면 보낸다
}
return;
};
...
return(
...
<form onSubmit={handleSubmit(onValid)}>
<input {...register("wordInput", { required: "빈칸이 있습니다" })}
autoComplete={false} />
</form>
...
)
공통적인 부분은 당연히 게임에 해당하는 join, start, message 입니다
소켓을 이해하기 쉽게 해본다면
ex) 'fried' 이벤트에 potato를 보내서 chip으로 바꾸는 작업을 해본다고 하면
클라이언트 socket.emit('fried','potato') →
서버 socket.on('fried',text=>{ io.emit('fried',`${text} chip`) }) →
클라이언트 socket.on('fried',text=>{console.log(text)}) //potato chip
![](https://blog.kakaocdn.net/dn/bwrKI8/btrf5jSjYWq/EgBSc9o3FohMEQRVhq94D0/img.png)
왼쪽은 사파리 오른쪽은 크롬에서 실행했습니다
![](https://blog.kakaocdn.net/dn/AtDb5/btrf7BSIGfL/fcRoovl64zqQLRZEsac6Dk/img.png)
왼쪽먼저 누르고
![](https://blog.kakaocdn.net/dn/ds2WdL/btrf5jZdnuZ/M86QgV1VBUDOtaF5gT0YkK/img.png)
오른쪽을 누르면 랜덤함수로 나온 초성이 나옵니다
![](https://blog.kakaocdn.net/dn/vbcIn/btrgczTE39q/kGIBhN2GDOMFj6xe8JTQOk/img.png)
이렇게 한 유저가 여러개 단어를 막 입력 할 수 있고 중복단어가 됩니다
다음에는 이 부분을 추가 해보겠습니다
여기에 올리지는 않았지만 단어 자음확인코드는 구글링으로 찾아서 나온 코드를 조금 변형했습니다
'프로그래밍 > 여러가지' 카테고리의 다른 글
자바스크립트 socket.io 채팅으로 초성게임 만들기 #3 중복과 턴 (1) | 2021.10.06 |
---|---|
자바스크립트 socket.io 채팅으로 초성게임 만들기 #1 설정하기 (0) | 2021.05.27 |
[React/GraphQL/Prisma] 로그인 만들기 #6.마무리 (0) | 2020.04.01 |
[React/GraphQL/Prisma] 로그인 만들기 #5.FrontEnd 로그인,회원가입 화면 (0) | 2020.02.24 |
[React/GraphQL/Prisma] 로그인 만들기 #4.FrontEnd React에GraphQl,Apollo 설정 (0) | 2020.02.18 |