ペアリングゲームの作成

26664 ワード

ゲームの説明(2022.04.07 ver)


ゲーム🎮

ペアリング



完了時



再起動時



悩み事项🤔


ランダムブレンドArray


このカードゲームで最も重要なのは、各ゲームのカードをランダムに混合することです.
最初は1対のデータからなるデータと考えられていたので、1対1でディレクトリデータとして格納し、次のように記述する必要があります.
しかし、この場合、鍵がねじれているという問題が発生し、再レンダリングのたびに新しいカードが追加されるエラーが発生します.最終的に、id値、index値、およびカードに表示する果物データを持つすべてのデータを含むディレクトリデータが作成されます.
これらのカードデータを混合するために、検索によって以下のサイトが得られました.リファレンスサイト
  const MixedCardList = [...GAMEDATA, ...GAMEDATA].sort(
    (a, b) => 0.5 - Math.random(),
  )
コードでは、Mathは0から1の間の値(sortで分類)をランダムに返します.ランダム()から0.5を減算し、ランダムに-1または1を生成します.このようにランダムなsortであるため,ランダムブレンドの結果値が現れる.


ランダムに混ざった値はゲーム中に再現されたまま維持され、ゲームが再開されたときに再現されると並べ替える必要があるので、useMemoで保存した結果値を使って、ゲーム終了時(完了した変更)に並べ替える.
const MixedCardList = useMemo(() => MixedFruit(), [finished])

札を翻す


トランプをめくるときは想像以上に制限があります.
  • ペアのカードが発生した場合は、他のカードをクリックしたときにメンテナンスする必要があります.
  • カードの番号が合わない場合は、自分でカードをめくる必要があります.
  • ペアのペアのカードは、再度クリックすると、ひっくり返すことができません.
  • 枚のカードしか残っていない場合、再度クリックした1枚をクリックした場合、エラーはないはずです.
  • 全体的な要求を体現するために,ユーザがクリックしたカードデータを格納する配列を確立した.
    // 유저가 클릭한 카드 데이터를 저장하는 state
     const [clicked, setClicked] = useState(Array.from([]))
    クリックされたカードのインデックスを受け取り、カードをクリックしたときにカードを反転させるHandleClickを作成しました.
    const handleClick = (idx) => {
      // 선택한 카드 뒤집기
      MixedCardList.some((e) => {
        if (e.idx === idx) {
          e.status = !e.status
          return true
        }
        return false
      })
      setClicked([...clicked, idx])
      handleCheck(idx)
    }
    const handleCheck = (idx) => {
      if (clicked.length === 2) {
        let a = MixedCardList.find((e) => e.idx === clicked[0]).id
        let b = MixedCardList.find((e) => e.idx === clicked[1]).id
        // 두 카드가 같지 않은 경우, 해당 카드만 다시 뒤집기
        if (a !== b) {
          MixedCardList.forEach((e) => {
            if (e.idx === clicked[0] || e.idx === clicked[1]) {
              e.status = false
            }
          })
        }
        // 두장이 클릭된 상태에서 이미 클릭된 카드를 클릭하는 경우, 클릭된 두장의 카드 뒤집기
        if (clicked.includes(idx)) {
          setClicked(Array.from([]))
        } else {
          setClicked(Array.from([idx]))
        }
      }
    }
    
    //모든 카드의 상태가 true면 게임 끝냄
    useEffect(() => {
      if (MixedCardList.every((e) => e.status === true)) {
        setFinished(true)
      }
    }, [clicked])
    2枚のカードがクリックされた後、結果をチェックしてから自分で再びカードをめくる必要がありますが、次のカードをクリックしてからカードをめくる問題が発生します.

    useEffectとsettimeoutを使用して、カードが完全に反転した後にカードが一致しているかどうかを確認します.
      useEffect(() => {
        setTimeout(() => {
          if (clicked.length === 2) {
            let a = MixedCardList.find((e) => e.idx === clicked[0]).id
            let b = MixedCardList.find((e) => e.idx === clicked[1]).id
            // 두 카드가 같지 않은 경우
            if (a !== b) {
              MixedCardList.forEach((e) => {
                if (e.idx === clicked[0] || e.idx === clicked[1]) {
                  e.status = false
                }
              })
            }
            setClicked(Array.from([]))
          }
        }, 500)
      }, [clicked])

    しかし、この場合、カードをすばやくクリックすると、スタックに3つ以上のカードが積み上げられ、カード値を相互にチェックする関数に問題が発生する.このため、クリック数が2つ以上であれば、カードのクリックを制限します.
    {MixedCardList.map((e, i) => (
              <Card
                data={e}
                key={`${e.idx}-${e.item}`}
                handleClick={clicked.length < 2 ? handleClick : null}
              />
            ))}
    実はこれが正しい方法かどうか分かりません.カードゲームに対する設定の制限により、他のカードが開いている場合に素早くカードをクリックすべきですが、現在のように他のカードが閉じている場合、ユーザーが待つ必要がある場合は時間制限が設定しにくい可能性があるので、回数制限を設定の方向に変更します.
    回数制限の場合、ゲーム開始前に、プレイヤー全体のディスプレイカードの正面を後にしてから開始することを提案されたため、この機能を追加することにした.

    3、4番のためにカードの状態がtrueの場合、clickイベントはキャンセルされます.
      return (
        <CardFrame onClick={() => status || handleCard(idx)}>
          <CardPiece checked={status}>
            <CardFront />
            <CardBack>{item}</CardBack>
          </CardPiece>
        </CardFrame>
      )

    createPortalを使用したモードの作成


    https://velog.io/@dfd1123/react-create-portal-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC
    createPortalは、親コンポーネントのDOM階層以外でサブコンポーネントをレンダリングする機能を提供します.
    外部に存在するDOMノードはReactApp DOM層のように接続のエントリ機能を提供するため,主にモード機能の生成に用いられる.
    実際、現在番組では複数のページに移動したり画面を切り替えたりする場合ではないので、あえて使う必要はありませんが、練習としてcreatePortalを使ってモードを実現することにしました.
    //Modal.jsx
    const ModalPortal = ({ children }) => {
      const modalElement = document.querySelector(".modal")
    
      return reactDom.createPortal(
        <Modal>
          <ModalBox>{children}</ModalBox>
        </Modal>,
        modalElement,
      )
    }
    このようにコードを記述する場合は、htmlドキュメントにmodelclassを持つノードを直接記述する必要があります.
    <body>
      <div class="modal"></div>
      <div id="root"></div>
    </body>