웹어셈블리 #1 Emscripten 시작하기
React+Redux+Canvas로 간단한 게임 구조 구성하기
2018-11-25
Explanation
얼마 전에 Canvas를 이용해서 간단한 게임을 만들어 봤는데요, 그 내용을 모두 적기엔 글이 너무 길어질 것 같아서 간단하게 제가 생각해본 구조?? 에 대해 정리해보려 합니다.
대략 Webpack, Babel, React, Redux, Canvas를 사용하고요, 크게 React로 컴포넌트를 나누어 구성하고 Redux로 현재 게임의 상태를 저장하고 Canvas로 화면을 그립니다. Babel로 ES6+ 문법을 사용하고 Webpack은 이 모든 구성을 쉽게 모아서 사용할 수 있고 hot-loader로 일일이 새로고침을 할 필요가 없어서 편해요. 그리고 polyfill을 설치하면 Async/Await도 사용할 수 있습니다.
예제 소스를 설치하면 대략적으로 시작할 수 있는 밑바탕 정도로 사용할 수 있을 거 같아요.
예제 : https://github.com/falsy/blog-post-example/tree/master/react-redux-canvas
간략하게 코드에 대해 이야기해보면,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/views/dashboard.js ... render() { return ( <div> <canvas id={'sample'} width={'500'} height={'500'}></canvas> <p onClick={this.startAnimation.bind(this)}>애니메이션</p> </div> ); } } const mstp = (state) => { return { canvas: state.canvas }; }; export default connect(mstp)(Dashboard) |
우선 id값으로 sample을 가지고 있는 canvas를 추가했고요,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// src/views/dashboard.js import React, { Component } from 'react'; import { connect } from 'react-redux'; import { setCanvas } from '../actions/canvas'; import { printMarble, animationMarble } from '../actions/marble'; class Dashboard extends Component { constructor(props) { super(props); } componentDidMount() { const { dispatch } = this.props; const canvas = document.getElementById('sample'); dispatch(setCanvas(canvas)); printMarble(canvas); } ... |
canvas가 랜더링되고 나면, 나중에 컴포넌트가 많아져도 Redux로 해당 canvas에 그림을 제어하기 위해서 Redux에 canvas를 기억해 두었습니다. 그리고 초기 그림?을 ‘printMarble’ 라는 함수를 통해 canvas에 그립니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
// src/actions/marble.js export function printMarble(canvas) { const ctx = canvas.getContext('2d'); const x = 100; const y = 240; const r = 10; ctx.beginPath(); ctx.arc(x, y, r, 0, Math.PI * 2, true); ctx.fillStyle = 'blue'; ctx.fill(); } ... |
파라미터로 canvas 엘리먼트를 받아오고 반지름 10px의 파란색 원을 x축 100px, y축 240px에 그립니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// src/views/dashboard ... startAnimation() { animationMarble(this.props.canvas.element); } render() { return ( <div> <canvas id={'sample'} width={'500'} height={'500'}></canvas> <p onClick={this.startAnimation.bind(this)}>애니메이션</p> </div> ); } } |
그리고 ‘애니메이션’이라는 텍스트를 클릭하면 animationMarble 라는 함수를, 그리고 redux에 기억해 놓은 canvas를 파라미터로 실행합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
// src/actions/marble.js ... export function animationMarble(canvas) { const ctx = canvas.getContext('2d'); const x = 100; const y = 240; const r = 10; let moveSize = 0; const animate = setInterval(() => { ctx.clearRect(x - r + moveSize, y - r, 20, 20); moveSize += 5; const moveX = x + moveSize; ctx.beginPath(); ctx.arc(moveX, y, r, 0, Math.PI * 2, true); ctx.fillStyle = 'blue'; ctx.fill(); if(moveX >= 400) { clearInterval(animate); ctx.clearRect(x - r + moveSize, y - r, 20, 20); } }, 10); } |
animationMarble 함수는 실행되면 setInterval 메서드로 함수를 반복 실행시켜 애니메이션을 구현합니다. .clearRect()로 이전 위치에 파란 원을 지우고 X축으로 += 5; 씩 추가된 X값으로 파란 원을 새로 그립니다. 그리고 X축으로 400px이상으로 이동하게되면 반복을 멈추고 파란 원을 지우는 것으로 애니메이션이 끝납니다.
그리고 끝으로 제가 간단하게 만들어본 게임은 아래의 링크를 통해서 확인해 볼 수 있습니다.
http://game.tenqube.kr/
제가 Canvas를 제대로 사용해 본 적이 없어서 캔버스를 사용했는데요, 위와 같은 게임은 그냥 canvas를 사용하지 않고 html, javascript로 만드는 게 더 좋을 거 같아요ㅎ