Jitsi 라이어 게임

김재헌·2021년 8월 3일
0

Ydentity

목록 보기
3/3
post-thumbnail

라이어 게임 코드 정리

라이어 게임

react > fertures > toolbox > components > web > Toolbox.js

툴 박스에 라이어 게임 버튼 추가

className='toolbox-content-tiems'에 this._renderLiarGameButton() 추가

_renderLiarGameButton() {
        return this.props._shouldShowButton("liarVote") ? (
            <LiarVoteButton
                key="liarVote"
                onHandleClick={this._onRequestLiarGame}
                visible={true}
            />
        ) : null;
    }

라이어 게임 버튼을 누르면 this._onRequestLiarVote 실행

_onRequestLiarGame() {
  // 방이 생성 되었는지 한 번 더 확인해주는 과정
        if (!APP || !APP.conference || !APP.conference.isJoined()) {
            return;
        }
        this._onToolbarOpenLiarGame();
    }

_onToolbarOpenLiarGame() {
        sendAnalytics(createToolbarEvent("liar"));
  // 카테고리를 선택 중이라는 메시지를 모두에게 알림
        APP.store.dispatch(
            showNotification(
                {
                    descriptionKey: "잠시만 기다려주세요.",
                    titleKey: "카테고리를 선택 중 입니다.",
                },
                NOTIFICATION_TIMEOUT
            )
        );
  // 라이어 게임 컴포넌트를 모달 형태로 오픈
      this.props.dispatch(openDialog(LiarGame));
    }

react > features > liar-game > components > web > Themes.js

카테고리 정해서 제시어 뿌려주기

// 하드코딩 된 데이터를 가져와서 맵핑
    return (
        <div>
            <div>카테고리를 골라주세요.</div>
            {data.map((theme, idx) => {
                return (
                    <button
                        key={idx}
                        onClick={handleTitle}
                        value={JSON.stringify(theme)}
                    >
                        {theme.title}
                    </button>
                );
            })}
        </div>
    );
const handleTitle = (e) => {
        e.preventDefault();
        const title = JSON.parse(e.target.value).title;
        const words = JSON.parse(e.target.value).words;
  // store에 카테고리 타이틀 저장
        dispatch(addTitle(title));
        selectWord(words);
    };

 const selectWord = (words) => {
      // 카테고리에서 단어 랜덤 선택
        word.current = words[Math.floor(Math.random() * words.length)];
      // store에 제시어 저장
        dispatch(addWord(word.current));
      // 게임시작
        dispatch(openDialog(checkLiar));
    };

CheckLiar.js

    const membersId = useRef([]); // 방 참여자 모든 아이디
    membersId.current = shuffle([
        ...conference.listMembersIds(),
        conference.getMyUserId(),
    ]);

    return (
        <Dialog handleCancelButton={true} submitDisabled={true}>
            <div>누가 라이어일까요?</div>
            <button onClick={selectLiar}>게임시작</button>
        </Dialog>
    );

    const selectLiar = (e) => {
        const { conference } = APP.store.getState()["features/base/conference"];

        e.preventDefault();
      // 제시어 뿌려주기
        conference.sendCommandOnce("sendWord", {
            value: _word,
            attributes: { ids: membersId.current, title: _title },
        });
        resetIds();
    };

// conference.js
        room.addCommandListener("sendWord", async (data, id) => {
            const prompt = data.value; // 제시어
            const randomIds = data.attributes.ids.split(","); // 셔플 된 아이디 배열
            const title = data.attributes.title; // 카테고리 타이틀

            const category = $(`<div>카테고리: ${title}</div>`);
            const elem = $(`<div>${prompt}</div>`);
            const liar = $(`<div>라이어</div>`);

            // 제시어 모달 오픈
            await this._openPrompt();
            // 투표 초기값 설정
            APP.store.dispatch(gameStart(true));
            APP.store.dispatch(voteLiar([]));
            // 참가자 중 라이어를 랜덤으로 지정
            selectLiar(randomIds, category, elem, liar, APP.store);
            // 제시어 화면에 띄워주기
            APP.store.dispatch(
                showNotification({
                    descriptionKey: `제시어: ${prompt}`,
                    titleKey: `카테고리: ${title} `,
                })
            );
            setTimeout(() => {
                APP.store.dispatch(hideDialog(checkLiar));
            }, 5000);
        });

showNotification({})

라이어 투표

react > fertures > toolbox > components > web > Toolbox.js

툴 박스에 라이어 게임 투표 버튼 추가

this._renderLiarVoteButton() 추가

    _renderLiarVoteButton() {
        return this.props._shouldShowButton("liarVote") ? (
            <LiarVoteButton
                key="liarVote"
                onHandleClick={this._onRequestLiarVote}
                visible={true}
            />
        ) : null;
    }
    _onRequestLiarVote() {
        if (!APP || !APP.conference || !APP.conference.isJoined()) {
            return;
        }

        this._onToolbarOpenLiarVote();
    }
    _onToolbarOpenLiarVote() {
        const { conference } = APP.store.getState()["features/base/conference"];

        sendAnalytics(createToolbarEvent("liarVote"));

        // 예외처리
        // 라이어 게임을 시작하지 않고 투표를 누르거나
        // 투표를 하고 투표 모달을 끄고 다시 투표 버튼을 누루거나
        // 투표가 완료되고 라이어 게임을 시작하지 않고 투표를 누르는 경우 
        if (!this.props._start) {
            alert("라이어 게임을 먼저 시작해주세요.");
        } else if (this.props._liars.length === 0 && this.props._liars) {
          // 투표 모달 오픈
            conference.sendCommandOnce("openLiarVote", {
                value: true,
            });
        } else {
            alert("이미 투표했거나 라이어 게임을 다시 시작해 주세요.");
        }
    }
// conference.js
        // 투표 모달 열기
        room.addCommandListener("openLiarVote", (data) => {
            APP.store.dispatch(openDialog(LiarVote));
        });

LiarVote.js

    return (
        <Dialog
            hideCancelButton={true}
            submitDisabled={true}
            titleString="투표하기"
        >
            <div>라이어를 찾으셨나요? 투표해보세요!</div>
            {_exceptMyselfIds
                ? _exceptMyselfIds.map((id, idx) => {
                      const displayName =
                          conference.getParticipantDisplayName(id);
                      return (
                          <>
                              <label
                                  htmlFor="voteName"
                                  onChange={handleVote}
                                  key={idx}
                              >
                                  {displayName} // 본인 제외 투표할 유저 이름 표시
                              </label>
                              <input
                                  type="radio"
                                  name="voteName"
                                  id="voteName"
                                  value={id}
                                  onClick={handleVote}
                              />
                          </>
                      );
                  })
                : null}
            {isVoted && liar !== "" ? (
                <div>집계 중 입니다...</div>
            ) : (
                <button onClick={completeVote}>라이어 지목하기</button>
            )}
        </Dialog>
    );
// 체크박스를 클릭 할 때마다 liar 상태 변경
const handleVote = (e) => {
        setLiar(e.target.value);
    };
// 체크박스로 라이어를 선택하고 라이어 지목하기를 누르면 그때 스토어에 저장
    const completeVote = (e) => {
        e.preventDefault();
        // 라이어 선택 안 하고 라이어 지목하기 눌렀을 때 예외처리
        liar !== "" ? setIsVoted(true) : null;
        liar !== "" ? (liars.current = [..._liars, liar]) : null;

        const { conference } = APP.store.getState()["features/base/conference"];
      // 지목 된 라이어와 유저 수 전달
        conference.sendCommandOnce("sendLiar", {
            value: participantsId.current.length + 1,
            attributes: { liar },
        });
      // 투표 수와 유저수가 같아지면 결과창 오픈
        if (participantsId.current.length + 1 === liars.current.length) {
            openResult(liars.current);
        }
    };

// conference.js

        // 투표한 유저 아이디 수집
        room.addCommandListener("sendLiar", (data) => {
            const liar = data.attributes.liar;
            const numOfParticipants = data.value;
            liars.push(liar);

            // 유저 선택을 안 하고 라이어 지목하기 버튼을 눌렀을 때 예외처리
            noBlankLiars = liars.filter((liar) => liar !== "");
            // 유저 숫자보다 투표 수가 많아지면 리셋
            if (noBlankLiars.length > numOfParticipants) {
                liars = [liar];
                noBlankLiars = [liar];
            }

            APP.store.dispatch(voteLiar(noBlankLiars));
        });

// LiarVote.js

    const openResult = (liars) => {
        const { conference } = APP.store.getState()["features/base/conference"];
        let participantsIds = participantsId.current;
        let myIds = myId.current;
      // 결과창 오픈
        conference.sendCommandOnce("openResult", {
            value: liars,
            attributes: { participantsIds, myIds },
        });
    };

// conference.js

        room.addCommandListener("openResult", async (data) => {
            const liars = data.value.split(",");
            const participantsId = data.attributes.participantsIds.split(",");
            const myId = data.attributes.myIds;
            let resultObj = {};
            // 투표 집계
            resultObj = await countUpVote(resultObj, liars); 
            // 투표 받지 못한 사람 추가
            resultObj = await getNumOfVote(resultObj, [
                ...participantsId,
                myId,
            ]);
            APP.store.dispatch(addResult(resultObj)); // store에 투표 결과 저장
            APP.store.dispatch(openDialog(Result)); // 결과창 오픈
        });

Result.js

    return (
        <Dialog
            hideCancelButton={true}
            submitDisabled={true}
            titleString="투표 결과창"
        >
            {Object.keys(_result).map((id, idx) => {
                const displayName = conference.getParticipantDisplayName(id);

                return (
                    <>
                        <div key={idx}>
                            {check
                                ? `${displayName}: ${displayWhoIsLiar(id)}` // 득표 수 표시
                                : `${displayName}: ${_result[id]}`} // 플레이어 or 라이어 표시
                        </div>
                    </>
                );
            })}
            {check ? (
                <div>
                    라이어는 {conference.getParticipantDisplayName(_liar)}
                    입니다!
                </div>
            ) : (
            // 라이어 확인하기 버튼 (득표 수 -> 라이어 표시)
                <button onClick={findOutRealLiar}>라이어 확인하기</button>
            )}
            {whoWon && check ? (
                <div>라이어를 맞췄습니다! 라이어는 제시어를 맞춰주세요.</div>
            ) : null}
            // 득표 수가 같은 경우 재투표
            {highestVoter === "똑같아요" ? (
                <button onClick={openReVote}>재투표</button>
            ) : highestVoter === "똑같아요" && reVote ? (
                <div>라이어 승리</div>
            ) : whoWon === false && check ? (
                <div>
                    라이어는
                    {conference.getParticipantDisplayName(highestVoter)}가
                    아닙니다. 라이어 승리!
                </div>
            ) : null}
            <button onClick={gameOver}>게임종료</button>
            <button onClick={reStart}>다시하기</button>
        </Dialog>
    );

    const findOutRealLiar = () => {
        setCheck(true);
        if (highestVoter === _liar) { // 표를 가장 많이 받은 사람과 라이어 아이디가 같으면
            setWhoWon(true);
        } else {
            setWhoWon(false);
        }
    };

예외처리

        // 투표 버튼 예외처리
        if (!this.props._start) { // 라이어 게임을 시작하지고 투표를 누르면
            alert("라이어 게임을 먼저 시작해주세요.");
        } else if (this.props._liars.length === 0 && this.props._liars) { // 라이어 게임을 시작했고 투표를 하지 않았으면
            conference.sendCommandOnce("openLiarVote", {
                value: true,
            });
        } else {
            alert("이미 투표했거나 라이어 게임을 다시 시작해 주세요.");
        }

이슈

투표

투표를 진행할 때마다 store에 저장해서 바로 불러오는 방식으로 하려고 했으나 유저별로 업데이트 되지 않는 이슈 발생

liarVote 컴포넌트에서 sendCommandOnce() 사용해서 store에 저장하는 방식으로 이슈 해결

//LiarVote.js
const completeVote = (e) => {
        e.preventDefault();
        const { conference } = APP.store.getState()["features/base/conference"];
        conference.sendCommandOnce("sendLiar", {
            value: liar,
        });
    };

//conference.js
room.addCommandListener("sendLiar", (data) => {
            const liar = data.value;
            liars.push(liar);
            APP.store.dispatch(voteLiar(liars));
        });

참가자 id로 이름 가져오기

conference.getParticipantDisplayName(id)

profile
개발자되려고 맥북샀다

1개의 댓글

comment-user-thumbnail
2024년 9월 15일

As Samantha started getting into the rhythm of blackjack, she realized that it wasn’t just about luck—it required a blend of quick thinking and careful planning. Each hand became a mental challenge, and she found herself hooked https://yabbycasinoau1.com/ on perfecting her strategy. The thrill of winning, combined with the intellectual stimulation of the game, ignited a passion she hadn’t anticipated. Soon, blackjack was no longer just a game to pass the time—it became her go-to form of entertainment.

답글 달기