2+ React Snake Game Examples

This post contains a total of 2+ React Snake Game Examples with Source Code. All these Snake Games are made using React.

You can use the source code of these examples with credits to the original owner.

Related Posts

React Snake Game Examples

1. simple react snake clone

Made by Pontus Oscarsson. Source

<!DOCTYPE html>
<html lang="en" >
<head>
  <title></title>
</head>
<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js'></script>
      <script>
class Canvas extends React.Component {
  shouldComponentUpdate() {
    return false;
  }
  render() {
    return /*#__PURE__*/(
      React.createElement("canvas", {
        width: "300",
        height: "300",
        ref: node => node ? this.props.context(node.getContext('2d')) : null }));


  }}


class Context extends React.Component {
  constructor(props) {
    super(props);
    this.saveContext = this.saveContext.bind(this);
  }

  componentDidMount() {
    this.ctx.fillRect(0, 0, 300, 300);
  }

  componentDidUpdate() {
    const { snake } = this.props;

    this.ctx.clearRect(0, 0, 300, 300);

    this.ctx.fillStyle = 'black';
    this.ctx.fillRect(0, 0, 300, 300);

    this.ctx.fillStyle = 'green';
    this.ctx.fillRect(snake.apple.x * 10, snake.apple.y * 10, 10, 10);

    this.ctx.fillStyle = 'red';

    for (const part of snake.body) {
      this.ctx.fillRect(part.x * 10, part.y * 10, 10, 10);
    }

    this.ctx.fillRect(snake.head.x * 10, snake.head.y * 10, 10, 10);

    if (snake.gameover) {
      this.ctx.textAlign = "center";
      this.ctx.fillStyle = 'white';
      this.ctx.fillText('Game Over', 150, 150);
    }
  }

  saveContext(ctx) {
    this.ctx = ctx;
    this.ctx.font = '30px serif';
  }

  render() {
    return /*#__PURE__*/React.createElement(Canvas, { context: this.saveContext });
  }}


class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      direction: 0,
      head: {
        x: 14,
        y: 14 },

      body: [{ x: 14, y: 15 }, { x: 14, y: 16 }],
      apple: {
        x: 10,
        y: 10 },

      gameover: false };

    this.current = {
      x: 14,
      y: 14 };

    this.last = {};


    this.move = false;
    this.timer = null;
    this.start = false;

    this.loop = this.loop.bind(this);
    this.init = this.init.bind(this);
    this.restart = this.restart.bind(this);
  }

  componentWillUnmount() {
    clearInterval(this.timer);
  }

  eat(body) {
    let apple = {},
    unique = false,
    new_body = body;

    do {
      unique = true;

      apple = {
        x: Math.floor(Math.random() * Math.floor(30)),
        y: Math.floor(Math.random() * Math.floor(30)) };


      if (this.state.head.x === apple.x &&
      this.state.head.y === apple.y) unique = false;

      for (let i = 0; i < this.state.body.length; i++) {
        if (this.state.body[i].x === apple.x &&
        this.state.body[i].y === apple.y) unique = false;
      }
    } while (!unique);

    new_body.push({
      x: new_body[new_body.length - 1].x,
      y: new_body[new_body.length - 1].y });


    return {
      body: new_body,
      apple: apple };

  }

  collision() {
    switch (this.state.direction) {
      case 0:
        if (this.state.head.y - 1 < 0) return true;
        break;
      case 1:
        if (this.state.head.x - 1 < 0) return true;
        break;
      case 2:
        if (this.state.head.y + 1 === 30) return true;
        break;
      case 3:
        if (this.state.head.x + 1 === 30) return true;
        break;
      default:break;}


    for (let i = 0; i < this.state.body.length; i++) {
      if (this.state.head.x === this.state.body[i].x &&
      this.state.head.y === this.state.body[i].y) return true;
    }

    return false;
  }

  input(event) {
    let new_direction = this.state.direction;

    if (this.move) {
      switch (event.key) {
        case 'ArrowUp':
          if (new_direction !== 2) {
            new_direction = 0;
            this.move = false;
          }
          break;
        case 'ArrowLeft':
          if (new_direction !== 3) {
            new_direction = 1;
            this.move = false;
          }
          break;
        case 'ArrowDown':
          if (new_direction !== 0) {new_direction = 2;this.move = false;}
          break;
        case 'ArrowRight':
          if (new_direction !== 1) {new_direction = 3;this.move = false;}
          break;
        default:return;}

    }

    this.setState({ direction: new_direction });
  }

  init() {
    if (!this.start)
    {
      window.addEventListener('keydown', event => this.input(event));
      this.start = true;
      this.timer = setInterval(this.loop, 150);
    }
  }

  restart() {
    if (this.state.gameover)
    {
      let state = {
        direction: 0,
        head: {
          x: 14,
          y: 14 },

        body: [{ x: 14, y: 15 }, { x: 14, y: 16 }],
        apple: {
          x: 10,
          y: 10 },

        gameover: false };

      this.current = {
        x: 14,
        y: 14 };

      this.last = {};


      this.move = false;
      this.timer = null;

      this.setState(state);
      this.timer = setInterval(this.loop, 150);
    }
  }

  loop() {
    let new_body = this.state.body.slice(),
    new_snake_position = {
      x: this.state.head.x,
      y: this.state.head.y },

    eat = {};

    if (!this.collision()) {
      switch (this.state.direction) {
        case 0:
          new_snake_position.y--;
          break;
        case 1:
          new_snake_position.x--;
          break;
        case 2:
          new_snake_position.y++;
          break;
        case 3:
          new_snake_position.x++;
          break;
        default:break;}


      this.current = this.state.head;

      for (let i = 0; i < new_body.length; i++) {
        let swap = new_body[i];
        new_body[i] = this.current;
        this.current = swap;
      }

    } else return (() => {
      clearInterval(this.timer);
      this.setState({ gameover: true });
    })();

    if (this.state.head.x === this.state.apple.x &&
    this.state.head.y === this.state.apple.y) eat = this.eat(new_body);

    this.setState(state => ({
      head: new_snake_position,
      body: eat.apple ? eat.body : new_body,
      apple: eat.apple ? eat.apple : state.apple }));


    this.move = true;
  }

  render() {
    return /*#__PURE__*/(
      React.createElement("div", null, /*#__PURE__*/
      React.createElement(Context, { snake: this.state }), /*#__PURE__*/
      React.createElement("div", null, /*#__PURE__*/
      React.createElement("button", { onClick: this.state.gameover ? this.restart : this.init }, this.state.gameover ? 'Restart' : 'Start'))));
  }}

ReactDOM.render( /*#__PURE__*/
React.createElement(Game, null),
document.getElementById('root'));
    </script>
</body>
</html>

2. React Snake with Score Board

Made by librarylai. Source

<!DOCTYPE html>
<html lang="en" >
<head>
  <title></title>
<style>
html, body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  display: flex;
  justify-content: center;
  background-color: #ccc;
}

.container {
  width: 50vw;
  height: 100vh;
}

.snake-game__map-wrapper {
  margin-top: 10px;
  width: 100%;
  height: 70%;
  background-color: #222;
  display: grid;
  position: relative;
}
@media only screen and (max-width: 600px) {
  .snake-game__map-wrapper {
    width: calc(100vw - 20px);
    height: calc(100vw - 20px);
  }
}
.snake-game__map-wrapper .snake-game-button-wrapper {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  flex-direction: column;
}
.snake-game__map-wrapper .snake-game-button-wrapper .snake-game-score {
  position: absolute;
  color: rgba(255, 255, 255, 0.5);
  font-size: 1.5em;
  left: 10px;
  top: 10px;
}
.snake-game__map-wrapper .snake-game-button-wrapper .snake-game-button {
  width: 100px;
  height: 40px;
  background: black;
  border: 2px solid white;
  color: white;
  border-radius: 20px;
  font-size: 1.2em;
  cursor: pointer;
  outline: none;
}
.snake-game__map-wrapper .snake-game-button-wrapper .snake-game-button:hover {
  color: black;
  background: white;
  transition: all 0.3s;
}
.snake-game__map-wrapper .snake-game__map-block-item {
  border: 1px solid black;
  box-sizing: border-box;
}
.snake-game__map-wrapper .snake-game__draw-snake-body {
  background: white;
  transition: all 0.1s;
}
.snake-game__map-wrapper .snake-game__draw-snake-food {
  background: red;
  border-radius: 100%;
  -webkit-animation: foodAnimate 2s infinite;
          animation: foodAnimate 2s infinite;
}

@-webkit-keyframes foodAnimate {
  0% {
    box-shadow: 0 0 0 0 red;
  }
  70% {
    box-shadow: 0 0 0 20px rgba(24, 19, 44, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(204, 169, 44, 0);
  }
}

@keyframes foodAnimate {
  0% {
    box-shadow: 0 0 0 0 red;
  }
  70% {
    box-shadow: 0 0 0 20px rgba(24, 19, 44, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(204, 169, 44, 0);
  }
}
</style>
</head>
<body>
  <div id="app"></div>
  <script src='https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js'></script>
      <script>
function _defineProperty(obj, key, value) {if (key in obj) {Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });} else {obj[key] = value;}return obj;}
class Container extends React.Component {
  constructor() {
    super();_defineProperty(this, "getFood",

    () => {
      const { gameWidth } = this.state;
      this.setState({
        food: {
          x: Math.floor(Math.random() * gameWidth),
          y: Math.floor(Math.random() * gameWidth) } });


    });_defineProperty(this, "isEatSelf",


    (headPosition, body) => {
      return body.find(item => item.x === headPosition.x && item.y === headPosition.y);
    });_defineProperty(this, "handleOnSetSnakeMoving",


    () => {
      const { snake, food } = this.state;
      // ้ ญ็š„้ƒจๅˆ†
      let isModifySpeed = false;
      let isGameStart = true;
      snake.body.push({ x: snake.headPosition.x, y: snake.headPosition.y });
      snake.headPosition.x = this.updatePosition(snake.headPosition.x + snake.direction.x);
      snake.headPosition.y = this.updatePosition(snake.headPosition.y + snake.direction.y);

      if (this.isEatSelf(snake.headPosition, snake.body)) {
        isGameStart = false;
      }
      // ่บซ้ซ”็š„้ƒจๅˆ†
      if (snake.body.length > snake.maxLength) {
        snake.body.shift();
      }

      // ๅƒ้ฃŸ็‰ฉ้ƒจๅˆ†
      if (snake.headPosition.x === food.x && snake.headPosition.y === food.y) {
        snake.maxLength += 1;
        snake.speed -= 50;
        snake.score += 1;
        isModifySpeed = true;
        this.getFood();
      }

      this.setState({ snake, isModifySpeed, isGameStart }, () => {});
    });_defineProperty(this, "handleOnKeyDown",


    event => {
      this.handleOnSetSnakeDirection(event.code);
    });_defineProperty(this, "handleOnSetSnakeDirection",


    eventCode => {
      const { snake } = this.state;
      let newDirection = {};
      // ็ฆๆญขๅพ€ๅ›ž่ตฐ
      if (snake.direction.x * -1 === this.direction[eventCode].x ||
      snake.direction.y * -1 === this.direction[eventCode].y) {
        newDirection = snake.direction;
      } else {
        newDirection = this.direction[eventCode];
      }
      this.setState({
        snake: {
          ...snake,
          direction: newDirection } });


    });_defineProperty(this, "handleGaneStartClick",


    () => {
      this.setState({
        isGameStart: true,
        snake: {
          headPosition: {
            x: 0,
            y: 0 },

          body: [],
          maxLength: 0,
          direction: {
            x: 1,
            y: 0 },

          speed: 500,
          score: 0 } },

      () => {
        const { snake } = this.state;
        this.gameInterval = setInterval(() => {
          this.handleOnSetSnakeMoving();
        }, snake.speed);
      });
    });_defineProperty(this, "updatePosition",


    position => {
      const { gameWidth } = this.state;
      if (position > gameWidth - 1) {
        return 0;
      } else if (position < 0) {
        return gameWidth - 1;
      }
      return position;
    });this.state = { gameWidth: 30, isGameStart: false, isModifySpeed: false, food: { x: 0, y: 0 }, snake: { headPosition: { x: 0, y: 0 }, body: [], maxLength: 0, direction: { x: 1, y: 0 }, speed: 500, score: 0 } };this.gameInterval = null;this.direction = { 'ArrowUp': { x: 0, y: -1 }, 'ArrowDown': { x: 0, y: 1 }, 'ArrowLeft': { x: -1, y: 0 }, 'ArrowRight': { x: 1, y: 0 } };}componentDidMount() {document.addEventListener('keydown', this.handleOnKeyDown);this.getFood();}componentWillUnmount() {clearInterval(this.gameInterval);document.removeEventListener('keydown', this.handleOnKeyDown);}componentDidUpdate(prevProps, prevState) {const { isGameStart, isModifySpeed, snake } = this.state;if (!isGameStart) {clearInterval(this.gameInterval);return;}if (!isModifySpeed) return;if (prevState.isModifySpeed !== isModifySpeed && isModifySpeed) {clearInterval(this.gameInterval);this.gameInterval = setInterval(() => {this.handleOnSetSnakeMoving();}, snake.speed);this.setState({ isModifySpeed: false }, () => {console.log(this.state);});}} // ๅ–็š„้ฃŸ็‰ฉไฝ็ฝฎ

  render() {
    const { gameWidth } = this.state;
    return /*#__PURE__*/(
      React.createElement("div", { className: "container" }, /*#__PURE__*/

      React.createElement(Grid, {
        size: gameWidth,
        isGameStart: this.state.isGameStart,
        snake: this.state.snake,
        food: this.state.food,
        handleGaneStartClick: this.handleGaneStartClick })));


  }}


class Grid extends React.Component {constructor(...args) {super(...args);_defineProperty(this, "constructMap",
    () => {
      const { size } = this.props;
      const blocks = [...new Array(size)].map((value, indexY) =>
      [...new Array(size)].map((value, indexX) => (
      {
        id: indexX + size * indexY,
        x: indexX,
        y: indexY })));



      return blocks;
    });_defineProperty(this, "updateGameView",
    (snake, block, food) => {
      //draw snake head
      if (snake['headPosition'].x === block.x && snake['headPosition'].y === block.y)
      {
        return 'snake-game__map-block-item snake-game__draw-snake-body';
      }
      if (snake['body'].find(bodyPosition => bodyPosition.x === block.x && bodyPosition.y === block.y)) {
        return 'snake-game__map-block-item snake-game__draw-snake-body';
      }
      if (food.x === block.x && food.y === block.y) {
        return 'snake-game__draw-snake-food';
      }
      return 'snake-game__map-block-item';
    });}

  render() {
    const { size, isGameStart, snake, food, handleGaneStartClick } = this.props;
    const mapDatas = this.constructMap();
    return /*#__PURE__*/(
      React.createElement("div", {
        style: {
          gridTemplateColumns: `repeat(${size}, 1fr)`,
          gridTemplateRows: `repeat(${size}, 1fr)` },

        className: "snake-game__map-wrapper" }, /*#__PURE__*/

      React.createElement("div", { className: "snake-game-button-wrapper" }, /*#__PURE__*/
      React.createElement("div", { className: "snake-game-score" }, /*#__PURE__*/
      React.createElement("span", null, "Score: "), /*#__PURE__*/
      React.createElement("span", null, snake.score)),

      !isGameStart && /*#__PURE__*/
      React.createElement("button", { className: "snake-game-button", onClick: handleGaneStartClick }, "Start")),



      mapDatas.map((rows) =>
      rows.map((block) => /*#__PURE__*/
      React.createElement("div", {
        key: block.id,
        className: this.updateGameView(snake, block, food) })))));

  }}

ReactDOM.render( /*#__PURE__*/React.createElement(Container, null), document.getElementById("app"));
    </script>
</body>
</html>

3. Basic React Snake Game

Made by Viriel. Source

<!DOCTYPE html>
<html lang="en" >
<head>
  <title></title>
</head>
<body>
  <div id="container"></div>
  <script src='https://npmcdn.com/[email protected]/dist/react.min.js'></script>
<script src='https://npmcdn.com/[email protected]/dist/react-dom.min.js'></script>
      <script>
const SnakeGame = React.createClass({ displayName: "SnakeGame",
  getInitialState() {
    return {
      x: 190,
      y: 190,
      snakelength: [1],
      tailPosition: [],
      clearTail: [],
      direction: "left" };

  },
  move() {
    switch (this.state.direction) {
      case "left":
        this.moveLeft();
        break;
      case "up":
        this.moveUp();
        break;
      case "right":
        this.moveRight();
        break;
      case "down":
        this.moveDown();
        break;}

  },
  ifBump() {
    if (this.state.snakelength.length > 1) {
      for (let i = 0; i < this.state.tailPosition.length; i++) {
        if (this.state.x == this.state.tailPosition[i][0] && this.state.y == this.state.tailPosition[i][1]) {
          alert('GAME OVER! Try Again?');
          this.setState({ x: 190 });
          this.setState({ y: 190 });
          this.setState({ snakelength: [1] });
          this.setState({ clearTail: [] });
          this.setState({ tailPosition: [] });
        }
      }
    }
  },
  updateTail() {
    let tail = this.state.tailPosition;
    tail.push([this.state.x, this.state.y]);
    tail.shift();
    this.setState({ tailPosition: tail });
    console.log(this.state.x, this.state.y);console.log(this.state.tailPosition);
  },
  moveLeft() {
    this.ifBump();
    this.updateTail();
    this.state.x > 50 ? this.setState({ x: this.state.x - 10 }) : this.setState({ x: 340 });
    this.drawCanvas();
  },
  moveUp() {
    this.ifBump();
    this.updateTail();
    this.state.y > 50 ? this.setState({ y: this.state.y - 10 }) : this.setState({ y: 340 });
    this.drawCanvas();
  },
  moveRight() {
    this.ifBump();
    this.updateTail();
    this.state.x < 340 ? this.setState({ x: this.state.x + 10 }) : this.setState({ x: 50 });
    this.drawCanvas();
  },
  moveDown() {
    this.ifBump();
    this.updateTail();
    this.state.y < 340 ? this.setState({ y: this.state.y + 10 }) : this.setState({ y: 50 });
    this.drawCanvas();
  },
  fruitposition() {
    return (Math.floor(Math.random() * (34 - 5 + 1)) + 5) * 10;
  },
  moveSnake(event) {
    if (event.which == 37) {
      this.setState({ direction: "left" });
    }
    if (event.which == 40) {
      this.setState({ direction: "down" });
    }
    if (event.which == 38) {
      this.setState({ direction: "up" });
    }
    if (event.which == 39) {
      this.setState({ direction: "right" });
    }
  },
  ifMatch() {
    let position = this.state.tailPosition;
    if (this.state.x == this.state.fruitx && this.state.y == this.state.fruity) {
      this.setState({ fruitx: this.fruitposition() });
      this.setState({ fruity: this.fruitposition() });
      let length = this.state.snakelength;
      length.push(1);
      this.setState({ snakelength: length });
      if (this.state.snakelength.length > 1) {
        let y = this.state.y;
        let x = this.state.x;
        switch (this.state.direction) {
          case "up":
            position.push([x, y + 10]);
            break;
          case "right":
            position.push([x - 10, y]);
            break;
          case "down":
            position.push([x, y - 10]);
            break;
          case "left":
            position.push([x + 10, y]);
            break;}

        this.setState({ tailPosition: position });
      }
    }
  },
  componentDidMount() {
    this.drawCanvas();
    document.addEventListener('keydown', this.moveSnake);
    this.timerId = setInterval(this.move, 150);
    this.setState({
      fruitx: this.fruitposition(),
      fruity: this.fruitposition() });

  },
  componentWillUnmount() {
    document.removeEventListener('keydown', this.moveSnake);
  },
  drawCanvas() {
    const context = this.refs.canvas.getContext('2d');
    context.clearRect(40, 40, 370, 370);
    context.strokeRect(49, 49, 302, 302);
    context.fillStyle = "#777777";
    context.fillRect(this.state.x, this.state.y, 10, 10);
    this.ifMatch();
    context.fillStyle = "#ee4e91";
    context.fillRect(this.state.fruitx, this.state.fruity, 10, 10);
    if (this.state.snakelength.length > 1) {
      for (let i = 1; i <= this.state.snakelength.length; i++) {
        let x = this.state.tailPosition[this.state.tailPosition.length - i][0];
        let y = this.state.tailPosition[this.state.tailPosition.length - i][1];
        context.fillStyle = "#777777";
        context.fillRect(x, y, 10, 10);
      }
    }
  },
  render() {
    return /*#__PURE__*/(
      React.createElement("div", null, /*#__PURE__*/
      React.createElement("h1", null, " Snake Game "), /*#__PURE__*/
      React.createElement("canvas", { ref: "canvas", width: 400, height: 400 })));


  } });


ReactDOM.render( /*#__PURE__*/
React.createElement(SnakeGame, null),
document.getElementById('container'));
//# sourceURL=pen.js
    </script>
</body>
</html>