Building a Snake Game in React Native: A Complete Guide

Introduction

React Native has become the go-to framework for building mobile applications using JavaScript. Among the vibrant community of developers eager to harness its capabilities, crafting engaging games is a popular choice. In this tutorial, we’ll dive into building a classic Snake game using React Native. Not only will this project sharpen your coding skills, but it will also provide a solid understanding of game mechanics, state management, and touch interactions.

Whether you are a beginner exploring the intersection of JavaScript and mobile development or an experienced developer looking to enhance your skills, this guide is designed for you. By the end, you will have a fully functional snake game that you can run on your mobile device and expand upon as you wish.

Let’s get started!

Setting Up Your Development Environment

Before we start coding, we need to set up our development environment. If you haven’t installed React Native yet, ensure you have the necessary tools ready:

  • Node.js: This is essential for managing packages and running your React Native apps.
  • Expo CLI: Expo simplifies the development process with React Native. You can install it by running npm install -g expo-cli.
  • Text Editor: Use an IDE like Visual Studio Code for coding.

Once you have these prerequisites, create a new React Native project by running:

expo init SnakeGame

This command will prompt you to choose a template. Selecting the blank template will give you a clean slate to work from. After the project is created, navigate into the project folder and start the development server by using:

cd SnakeGame
expo start

Your development environment is now set up! You should see a QR code in your terminal, allowing you to open the app on your mobile device using the Expo Go app.

Implementing the Game Logic

Let’s dive into the core of our Snake game—the logic. This game will involve a simple grid where the snake moves, grows when it eats food, and the game ends when it collides with the walls or itself.

First, we’ll create a component named SnakeGame. This component will manage the game’s state using hooks from React. We’ll need to track the snake’s position, the direction it is moving, and the food’s position. Here’s a basic layout for our component:

import React, { useState, useEffect } from 'react';
import { View, StyleSheet, TouchableWithoutFeedback } from 'react-native';

const SnakeGame = () => {
  const [snake, setSnake] = useState([{ x: 0, y: 0 }]);
  const [food, setFood] = useState({ x: 5, y: 5 });
  const [direction, setDirection] = useState('RIGHT');

  // Game logic goes here
};

export default SnakeGame;

In this code, we initialize the snake’s starting position and the food’s position. We’ll be implementing functions that will handle movement, food collision, and snake growth.

Handling Movement

Next, we need a key aspect of game functionality: movement. To accomplish this, we set up a function that alters the snake’s position based on its direction. We update the position every few milliseconds to create the animation. Here’s how you can implement the moving functionality:

const moveSnake = () => {
  const head = { ...snake[0] };
  switch (direction) {
    case 'UP':
      head.y -= 1;
      break;
    case 'DOWN':
      head.y += 1;
      break;
    case 'LEFT':
      head.x -= 1;
      break;
    case 'RIGHT':
      head.x += 1;
      break;
  }
  const newSnake = [head, ...snake];
  setSnake(newSnake);
};

useEffect(() => {
  const gameInterval = setInterval(moveSnake, 100);
  return () => clearInterval(gameInterval);
}, [snake, direction]);

This function retrieves the snake’s current position and updates it based on the direction. The useEffect hook sets an interval to call this function every 100 milliseconds, creating the movement effect.

Growing the Snake

The next step is to handle what happens when the snake eats food. If the snake’s head collides with the food’s position, we will add to the snake’s length and generate a new food position:

const eatFood = () => {
  if (snake[0].x === food.x && snake[0].y === food.y) {
    const newFood = generateFood();
    setFood(newFood);
    increaseSnake();
  }
};

const increaseSnake = () => {
  const newSnake = [...snake];
  newSnake.push({}); // Add a new segment (initially empty)
  setSnake(newSnake);
};

const generateFood = () => {
  return { x: Math.floor(Math.random() * GRID_SIZE), y: Math.floor(Math.random() * GRID_SIZE) };
};

The eatFood function checks the snake’s head against the food’s position. If they match, it generates a new food position and increases the snake’s size. The generateFood function randomly places the food on the grid.

Rendering the Game

Now that we have the logic in place, it’s time to render the game visually. We’ll create a simple grid layout where each square represents a position in our game. The snake will be displayed as a series of rectangles, and the food as a different colored rectangle.

Using the StyleSheet from React Native, we can create a grid style for our game:

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    position: 'relative',
  },
  cell: {
    width: 20,
    height: 20,
    backgroundColor: 'green',
    position: 'absolute',
  },
  food: {
    backgroundColor: 'red',
  },
});

Each cell in the grid corresponds to a 20×20 pixel square on the screen. We will iterate over the snake’s state to render the segments dynamically. Here’s how the rendering function can look:

return (
  
    {snake.map((segment, index) => (
      
    ))}
    
  
);

This code maps the snake’s segments and places them in the correct grid location. The food is rendered in red to distinguish it from the snake.

Implementing Controls

To make the game interactive, we need to enable controls for the user to change the snake’s direction. We can achieve this using React Native’s TouchableWithoutFeedback component to capture touch gestures. Here’s how we can implement the controls:

const setDirectionFromTouch = (event) => {
  const { locationX, locationY } = event.nativeEvent;
  if (locationY < height / 2 && direction !== 'DOWN') {
    setDirection('UP');
  } else if (locationY > height / 2 && direction !== 'UP') {
    setDirection('DOWN');
  } else if (locationX < width / 2 && direction !== 'RIGHT') {
    setDirection('LEFT');
  } else if (locationX > width / 2 && direction !== 'LEFT') {
    setDirection('RIGHT');
  }
};

return (
  
    ...
  
);

The setDirectionFromTouch function changes the direction based on where the user taps on the screen. We check the location of the tap against the height and width of the view to ensure that the snake doesn’t reverse direction.

Game Over Conditions

The last vital aspect of our Snake game is determining when the game ends. We need to implement collision detection for both the snake colliding with the walls and itself. This will stop the game and could prompt the player to restart. Here’s how we can handle collisions:

const checkGameOver = () => {
  const head = snake[0];
  if (
    head.x < 0 ||
    head.x >= GRID_SIZE ||
    head.y < 0 ||
    head.y >= GRID_SIZE ||
    snake.slice(1).some(segment => segment.x === head.x && segment.y === head.y)
  ) {
    alert('Game Over');
    resetGame();
  }
};

const resetGame = () => {
  setSnake([{ x: 0, y: 0 }]);
  setFood(generateFood());
  setDirection('RIGHT');
};

The checkGameOver function checks if the head of the snake has hit the boundary of the grid or collided with any of its segments. If either condition is true, it alerts the player with a ‘Game Over’ message and resets the game.

Conclusion

Congratulations! You’ve built a classic Snake game in React Native. This project is not only a fun exercise but also a great way to familiarize yourself with the key concepts of game development using React Native. You’ve learned how to manage state, handle user inputs, and implement simple game logic.

Now that you’ve got the foundation in place, consider enhancing your game further. You could add features like scoring, levels with increasing difficulty, or even sounds when the snake eats food. The possibilities for expansion are endless, and your creativity is the only limit.

If you found this tutorial helpful, feel free to share it with your fellow developers or reach out for any questions or feedback. Happy coding!

Scroll to Top