본문 바로가기
Web/React

[React🌀] React로 2048 게임 만들기 ! 🎮 / 5️⃣ - 키 입력받기

by 서상혁 2020. 9. 6.

키 입력💥

이제 키를 입력받아서 구현해뒀던 함수들을 쓸 수 있게 만들어봅시다. 방향키를 누르면 그에 따라 게임판이 바뀌고, 아래 사진처럼 게임판 양쪽에 있는 전광판에 무슨 키를 눌렀는지도 나오게 해볼거에요!

 

  

Arrow 스타일링

 

const ArrowContainer = styled.div`
  display: inline-block;
  position: absolute;
  top: 50%;
  right: 30px;
  background: #ea5455;
  width: 50px;
  height: 50px;
  text-align: center;
  border-radius: 5px 5px 5px 5px;
  -moz-border-radius: 5px 5px 5px 5px;
  -webkit-border-radius: 5px 5px 5px 5px;
  border: 5px solid #d2dae2;
`

const Arrow = styled(H2)`
  position: relative;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

Arrow 전광판 부분을 어떻게 꾸밀지 커스텀해주세요!

H2 는 styled-component로 제 상황에 맞게 커스텀한 h2 입니다.

 

- 엘리먼트 부분

<ArrowContainer>
	<Arrow>{arrow}</Arrow>
</ArrowContainer>
<ArrowContainer style={{ left: "30px" }}>
	<Arrow>{arrow}</Arrow>
</ArrowContainer>

 가운데 화면 Col 이면 아무데나 넣으셔도 됩니다.

 

 

 


React 키보드 입력받기 - onKeyDown, onKeyUp

React 에서는 엘리먼트에 onKeyDown 과 onKeyUp 의 props를 추가함으로 키보드 입력을 쉽게 받을 수 있습니다. onKeyDown 은 키보드를 눌렀을때 실행할 함수를 넣어주고, onKeyUp 은 키보드를 눌렀다가 위로 올렸을 때 실행할 함수를 넣어주면 됩니다. 꾹 누르고있을때는onKeyUp은 실행이 되지 않겠죠?

 

대략적인 방법

 

0. 게임 시작 버튼을 누르면 키보드를 입력받는 엘리먼트로 focus가 가게끔 만든다. 

1. 이벤트를 넣어줄 엘리먼트의 onKeyDown 혹은 onKeyUp 속성에 내가 지정한 함수를 넣어준다. (함수 인자는 KeyboardEvent가 된다)

2. event.keyCode 로 누른 키가 뭐인지 구별하며, 실행할 코드를 함수 내용으로 넣어준다.

 

그래도 역시 예시로 보는게 쉽겠죠!

 

* 사용한 State들

- 필요에 따라 바꿔가며 넣으세요!

const [gameBoard, setGameBoard] = useState<number[][]>(init_gameBoard(version))
const [text, setText] = useState<string>("PRESS START!")
const [arrow, setArrow] = useState<string>("")
const [theme, setTheme] = useState<number>(1)
const [score, setScore] = useState<number>(0)
const [playing, setPlaying] = useState<boolean>(false)
const [pressAvail, setPressAvail] = useState<boolean>(true)

 

0. 게임 시작 버튼을 누르면 키보드를 입력받는 엘리먼트로 focus가 가게끔 만든다. 

- 게임판을 감싸는 div 에 gameFocus 함수를 넣어주고  input으로 ref가 가게끔 만듭니다.

 

<div onClick={gameFocus} style={{ margin: "10px auto" }}>
	<input
    	style= 스타일링
        ref={gameDoing}
        value={text}
        readOnly
        ></input>
        {게임판 코드}
  </div>

gameFocus 함수 와 gameDoing ref

const gameDoing = useRef(null)

const gameFocus = useCallback(
    (e: React.MouseEvent) => {
      if (playing === false) return
      const { current }: any = gameDoing
      current?.focus()
      setText("PLAYING!")
    },
    [version, theme, playing],
  )

gameDoinng 이라는 ref 를 통해 input 으로 focus가 이동하게됩니다.

 


 

게임 시작 버튼 트리거 함수 onClickStart와 게임 초기화 함수 Initialize_Game

 // 게임 시작
  const onClickStart = useCallback(
    (e: React.MouseEvent) => {
      const { current }: any = gameDoing
      current?.focus()
      Initialize_Game()
    },
    [version, theme, playing],
  )

// 게임 초기화
  const Initialize_Game = useCallback(() => {
    setGameBoard(init_gameBoard(version))
    setText("START!")
    setScore(0)
    setScoreDiff(0)
    setDiff(false)
    setDiffCheck(true)
    setPlaying(true)
  }, [version, theme, playing, serverData])

 


1. 이벤트를 넣어줄 엘리먼트의 onKeyDown 혹은 onKeyUp 속성에 내가 지정한 함수를 넣어준다. (함수 인자는 KeyboardEvent가 된다)

 

넣어준 최종 모습

 <div onClick={gameFocus} style={{ margin: "10px auto" }}>
          <input
            style={{
              border: "none",
              cursor: "default",
              textAlign: "center",
              fontSize: "2.5vw",
              margin: "10px 0",
              color: "#4b4b4b",
            }}
            onKeyDown={handleKeyPress}
            onKeyUp={handleKeyUp}
            ref={gameDoing}
            value={text}
            readOnly
          ></input>
          {gameBoard.map((row, r) => (
            <FlexDiv width='55%' key={`FlexDiv__${r}`} style={{ margin: "0 auto" }}>
              {row.map((num, c) => (
                <Cell version={version} value={num} customTheme={theme} key={`Cell__${r}_${c}`}>
                  <InnerH2 color={GAME_BG_COLOR} key={`H2__${r}_${c}`}>
                    {num !== 0 ? num : " "}
                  </InnerH2>
                </Cell>
              ))}
            </FlexDiv>
          ))}
        </div>

 

 

 


2. event.keyCode 로 누른 키가 뭐인지 구별하며, 실행할 코드를 함수 내용으로 넣어준다.

 

키보드 눌렀을 때

// 키보드 눌렀을 때
  const handleKeyPress = (e: React.KeyboardEvent) => {
    e.preventDefault()
    if (!pressAvail) return
    // Ctrl + R 게임 초기화 (치트키)
    if (e.keyCode === 82 && e.ctrlKey) {
      Initialize_Game()
      return
    }
    if (playing === false) return // 게임 중인지 체크
    if (isMovingKey(e.keyCode) === false) return // 상하좌우 키 인지 체크
    let prevBoard = Array.from(gameBoard)
    let nextBoard = gameBoard
    if (e.keyCode === 39) nextBoard = moveRight(gameBoard)
    else if (e.keyCode === 37) nextBoard = moveLeft(gameBoard)
    else if (e.keyCode === 38) nextBoard = moveTop(gameBoard)
    else if (e.keyCode === 40) nextBoard = moveBottom(gameBoard)
    setGameBoard(Array.from(nextBoard))
    const gettingScore = calScore(prevBoard, nextBoard)
    setScore(score + gettingScore)
    setScoreDiff(gettingScore)
    // 움직인 결과일 때 diff 애니메이션 작동
    if (isMovingKey(e.keyCode) && gettingScore !== 0) {
      setDiff(!diff)
      setDiffCheck(true)
    }
    // 게임 끝!
    if (isGameOver(gameBoard)) {
      message.error(`게임 종료! 점수 : ${score}`)
      setText("Game Over!!")
      setPlaying(false)
    }
    setPressAvail(false)
    setTimeout(() => {
      setPressAvail(true)
    }, 10)
  }

 

키보드에 손 뗐을 때

const handleKeyUp = (e: React.KeyboardEvent) => {
    e.preventDefault()
    if (e.keyCode === 39) setArrow("➡")
    if (e.keyCode === 37) setArrow("⬅")
    if (e.keyCode === 38) setArrow("⬆")
    if (e.keyCode === 40) setArrow("⬇")
  }

- 화살표 전광판을 바꿔줍니다.

 

 


최종 구현 모습

 


| 리액트로 2048 게임 만들기🎮 |

 

2020/08/17 - [웹 개발/React] - [React🌀] React로 2048 게임 만들기 ! / 1️⃣ - 기본 세팅 및 소개 / Clone Coding

2020/08/29 - [웹 개발/React] - [React🌀] React로 2048 게임 만들기 ! 🎮 / 2️⃣ - 화면 레이아웃 잡기

2020/08/31 - [웹 개발/React] - [React🌀] React로 2048 게임 만들기 ! 🎮 / 3️⃣ - 알고리즘 구현

2020/09/02 - [분류 전체보기] - [React🌀] React로 2048 게임 만들기 ! 🎮 / 4️⃣ - 테마 설정하기

 

 

 

 

 

* 전체 코드는 제 깃허브에서 확인 가능합니다.

* 제가 직접 읽고 느낀 생각을 글로 쓰는 것이기에, 잘못된 내용이 있을 수 있습니다. 피드백과 지적은 언제나 환영합니다!

 

728x90

댓글