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>