프로그래밍/여러가지

자바스크립트 socket.io 채팅으로 초성게임 만들기 #2 게임기능

bonong 2021. 9. 28. 00:23
반응형

이번에 추가할 내용을 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

왼쪽은 사파리 오른쪽은 크롬에서 실행했습니다

왼쪽먼저 누르고

오른쪽을 누르면 랜덤함수로 나온 초성이 나옵니다

이렇게 한 유저가 여러개 단어를 막 입력 할 수 있고 중복단어가 됩니다
다음에는 이 부분을 추가 해보겠습니다

여기에 올리지는 않았지만 단어 자음확인코드는 구글링으로 찾아서 나온 코드를 조금 변형했습니다

반응형