How to Make Video Games from Scratch

a girl sitting with books

This is a beginner-level article; unlike my other posts which are specific to unique mechanics. This article is aimed at absolute beginners in game development.

If you’re wondering how to make video games from scratch and want to see the details of developing a game, this guide is for you. In this post on creating video games; we’re going to go into specific details that will help both beginners and those with some development experience looking to learn game development on a deeper level. Whether you’re aiming to build 2D indie games or AAA-style 3D games, this guide aims to get you started into the industry. Later, you’ll figure out the details and will be able to choose your own path.

Why Making a Video Game?

You might have several reasons:

  1. You just love the idea of making games & taking it as a hobby.
  2. You want to earn money by publishing games & taking it as a business.
  3. You are studying gamedev at school.

Understanding the Basics of Game Development

Before diving into the technical side, it’s crucial to understand what game development entails. The entire process can be broken down into these core components:

  1. Game Design – Conceptualizing the game’s mechanics, story, characters, and environments.
  2. Programming – Writing the code that powers the game. This includes game physics, player controls, AI behavior, and more.
  3. Art and Assets – Creating 2D or 3D models, textures, animations, sound effects, and music.
  4. Testing and Debugging – Ensuring the game is free of bugs and runs smoothly across different platforms.
  5. Publishing and Marketing – Releasing the game and ensuring it reaches the right audience.

If you want to learn game development comprehensively, it’s important to recognize that all these stages need careful attention.

In AAA studios, all of these aspects are handled by separate teams. Artists, for example, have a whole career entirely dedicated to creating game objects such as characters, items and so on. Programmers, like me, are dedicated to coding the game mechanics. Game publishers or marketers are business people who invest into the creation of a game to earn profit from it.

In many cases, developers are separate from publishers. They get funding from the publishers, develop a game and let the publishers market it & generate revenue. Since publishers have done investment, they usually take large profits.

But for small scale game development, called indie game development, a single person or a small team handles all the aspects; usually without financial investment. Some indie games succeed & generate profits, while others don’t. But the percentage of successful games is low; even probability of completing a game project is not so optimistic.

Choosing the Right Game Engine

Choosing a game engine is one of the first things you’ll encounter when figuring out how to make computer games. The engine you select will directly impact your development process and workflow. Here are a few top engines to consider, along with their niches:

  • Godot Engine: If you’re learning to make video games and prefer something that’s beginner-friendly yet powerful, Godot is a fantastic option. It’s lightweight, completely open-source, and supports both 2D and 3D game development. The scripting language (GDScript) is easy to learn for beginners.
  • Unity: One of the most popular engines, Unity is perfect for developing a wide variety of games. It offers extensive documentation and has a huge online community, making it an excellent choice if you want to learn game development through community interaction and shared resources.
  • Unreal Engine: This engine is more advanced and suited for high-fidelity 3D games. If your goal is to make realistic AAA-style games, Unreal Engine offers cutting-edge graphics. However, its steep learning curve might not be ideal for beginners.
  • And the list goes on…

Make sure you select an engine that aligns with your long-term goals, as the skills you acquire in one engine can influence your future gamedev career.

Learning to Code for Game Development

Even with the best tools, understanding programming is crucial to learn making games. Here are some niche yet essential coding languages to focus on, depending on your game engine:

  • GDScript (Godot): A Python-like language that’s specific to Godot. It’s intuitive for beginners but also robust enough for larger projects.
  • C# (Unity): Unity uses C# for scripting, which is a versatile language that can be applied in many fields beyond just game development. There are numerous gamedev courses focused on C# scripting within Unity.
  • C++ (Unreal Engine): Unreal Engine’s core programming language. C++ is powerful but complex, and learning it can open doors for more advanced game development, especially for systems like physics, AI, or custom game engines.
  • Python: Python isn’t traditionally a game development language, but it’s great for learning algorithms, game logic, and prototyping. Once comfortable, you can switch to more specialized languages.

Developing Niche Game Mechanics

While many tutorials on learning to make video games focus on broad topics, creating unique mechanics is often overlooked. Here are some niche areas worth diving into for more specialized game development:

  • Procedural Generation: Procedural content generation can be used to create massive, randomized game worlds (think No Man’s Sky). It involves algorithms that generate levels, landscapes, or even characters dynamically. Tools like Perlin Noise or Simplex Noise algorithms can be used for procedural terrain generation.
  • AI Pathfinding: Creating smart enemies and NPCs is crucial for immersive games. A* Pathfinding is a common algorithm, but for more complex behaviors, you might want to explore steering behaviors or decision trees. For example, in Godot, you can use its Navigation2D system to develop custom AI movements based on the game world.
  • Game Physics: Understanding how to simulate gravity, collision detection, or rigid body dynamics is vital. Engines like Unity and Godot come with built-in physics, but sometimes you’ll need to tweak these systems or even write your own. Learning rigid body physics, collision layers, and raycasting can give you more control over how objects interact in your game world.

Mastering Game Art and Assets

Good art can make or break a game. Depending on the type of game you’re making, you might need to create 2D sprites, 3D models, textures, animations, or visual effects. Here’s how you can specialize in niche asset creation:

  • 2D Games: Tools like Aseprite, Photoshop or GIMP are great for creating pixel art. For vector-based 2D games, consider learning Inkscape. You’ll also need to learn about texture atlases, sprite sheets, and how to optimize 2D assets for performance.
  • 3D Games: If you’re venturing into 3D, Blender is the go-to free software for modeling, rigging, and animating characters. Learning to use shaders (like PBR shaders for realistic materials) can significantly improve your game’s visual quality.

Testing and Debugging Your Game

Testing is one of the most crucial yet often rushed stages in learning how to make computer games. Here are some deep niche details about debugging in game development:

  • Automated Testing: Setting up automated tests for your game can save a lot of time, especially as your project scales. You can write scripts to test game mechanics, ensuring that certain conditions work correctly without manually playing the game each time.
  • Memory and Performance Optimization: As your game grows, you’ll encounter performance bottlenecks. Learning how to use profiling tools in your engine (such as Unity’s Profiler or Godot’s Performance Monitors) helps you identify memory leaks or CPU spikes. Optimizing texture sizes, reducing draw calls, and using efficient algorithms for AI can drastically improve performance.
  • Bug Tracking Systems: For larger projects, consider using bug tracking software like Jira, ClickUp, Trello or GitHub Issues to keep track of issues. This is especially useful when collaborating with a team.

Publishing and Marketing Your Game

Once you’ve finished your game, you’ll need to figure out how to publish and market it. This is a crucial step that many developers don’t plan for when they start learning how to make video games. Here are a few detailed pointers on this:

  • Platform Choices: You can publish your game on platforms like Steam, itch.io, or the App Store. Each has its own set of requirements, so ensure that you optimize your game for the platform you’re targeting. Steamworks SDK, for example, provides features like achievements and cloud saves.
  • SEO for Game Pages: Optimize your game’s page for search engines. Use keywords like “learn game development” or “best indie game” to ensure it ranks well in search results. Write a compelling description and include high-quality images and trailers.
  • Community Building: To build an audience, start early by creating dev logs, posting on forums, and sharing progress on social media. Reddit communities like r/gamedev are great for feedback and marketing.

A great way to market your games as an indie developer is to go for YouTube streams who are willing to stream your game for free; they get content & you get marketing. This is one of the options worth exploring.

Marketing of the games usually start before the game is even published.

In Nutshell

Making computer games is a complex yet rewarding journey. Whether you’re just starting to learn game development or have some experience under your belt, looking into niche areas like procedural generation, AI pathfinding, and performance optimization can set your game apart. If you’re serious about creating games, I recommend looking into advanced gamedev courses or tutorials that specialize in your areas of interest.

By focusing on the right game engine, mastering coding skills, learning about niche mechanics, and ensuring proper testing and marketing, you can transform your ideas into a polished, playable reality.

See More Posts


Part 2: Building a Simple Space Shooter in Pygame

In Part 1, we covered the detailed process of how to make video games and explored all the necessary components involved. Now, in Part 2, we’ll put that theory into practice by building a simple space shooter game using Python and Pygame. This step-by-step tutorial will focus on writing clean, well-documented code, breaking down each piece to help you truly understand how everything works together.

This is just a warm-up to get you the feel of gamedev. I choose pygame because it is very easy to setup (however, I don’t recommend it for your real games).

What is Pygame?

Pygame is a cross-platform set of Python modules designed for writing video games. It is fair for 2D games, making it perfect for our small space shooter project. Pygame provides libraries for handling sprites, sound, and some very simple physics.

Setting Up Your Environment

Before you can start building the game, make sure you have Python and Pygame installed on your machine. If you don’t have them already, follow these steps:

  1. Install Python: Download and install Python from the official Python website.
  2. Install Pygame: Open a terminal or command prompt and run the following command to install Pygame: pip install pygame

Once you have Pygame installed, you’re ready to start coding!

—————————————————————————————–

Creating the Game Window

The first thing we need to do is create the game window where everything will be displayed. This is a critical step in game development, as the window will serve as the canvas where all sprites, animations, and game mechanics come to life.

Here’s the code to create a basic window:

import pygame
import sys

# Initialize Pygame
pygame.init()

# Set up the screen dimensions
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter")

# Frame rate
clock = pygame.time.Clock()

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Let’s break it down:

  • pygame.init(): Initializes all Pygame modules. You must call this before using any Pygame functionalities.
  • pygame.display.set_mode(): Creates a window where all game elements will be drawn. We’ve set the dimensions to 800×600 pixels.
  • pygame.display.set_caption(): Sets the window title, which will be shown at the top of the game window.
  • screen.fill((0, 0, 0)): Fills the screen with a solid black background each frame.
  • pygame.display.flip(): Updates the entire display at the end of each frame.
  • clock.tick(60): Caps the frame rate at 60 frames per second (FPS).

At this stage, you should see a black window that stays open until you close it.

Adding the Player Spaceship

Now that we have the window, we’ll add a player spaceship sprite. We’ll use simple Pygame shapes for this instead of complex images for simplicity.

Here’s how we can add a spaceship that moves using the arrow keys:

# Player variables
player_width, player_height = 50, 50
player_x, player_y = WIDTH // 2 - player_width // 2, HEIGHT - 60
player_speed = 5

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    # Get key states
    keys = pygame.key.get_pressed()

    # Player movement
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_speed
    if keys[pygame.K_RIGHT] and player_x < WIDTH - player_width:
        player_x += player_speed

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Draw the player spaceship (simple rectangle)
    pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Explanation:

  • player_x, player_y: These variables control the player’s position on the screen.
  • player_speed: This determines how fast the spaceship moves when you press an arrow key.
  • pygame.key.get_pressed(): Checks for keyboard input. The code checks whether the left or right arrow key is pressed and moves the spaceship accordingly.
  • pygame.draw.rect(): Draws a rectangle representing the player’s spaceship. The color (0, 128, 255) gives the spaceship a nice blue color.

Now, the player can move the spaceship left and right across the screen using the arrow keys.

Shooting Bullets

What’s a space shooter without shooting? Let’s add the ability to fire bullets.

Here’s how to do it:

# Bullet variables
bullets = []
bullet_width, bullet_height = 5, 10
bullet_speed = 7

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        
        # Shoot a bullet when the spacebar is pressed
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                bullet_x = player_x + player_width // 2 - bullet_width // 2
                bullet_y = player_y
                bullets.append([bullet_x, bullet_y])

    # Get key states
    keys = pygame.key.get_pressed()

    # Player movement
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_speed
    if keys[pygame.K_RIGHT] and player_x < WIDTH - player_width:
        player_x += player_speed

    # Update bullets
    for bullet in bullets:
        bullet[1] -= bullet_speed
        if bullet[1] < 0:
            bullets.remove(bullet)

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Draw the player spaceship
    pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))

    # Draw the bullets
    for bullet in bullets:
        pygame.draw.rect(screen, (255, 255, 255), (bullet[0], bullet[1], bullet_width, bullet_height))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Explanation:

  • bullets[]: A list that stores each bullet’s x and y coordinates.
  • pygame.KEYDOWN: Detects when a key is pressed. When the spacebar is pressed, a new bullet is created and added to the bullets list.
  • bullet[1] -= bullet_speed: Moves the bullet upward. If the bullet leaves the screen, it is removed from the list.
  • pygame.draw.rect(): Draws each bullet on the screen as a small white rectangle.

Now you can shoot bullets by pressing the spacebar!

Adding Enemies

The next step is adding enemies for the player to shoot. We’ll create enemy ships that move down the screen, and if they collide with a bullet, they’ll be destroyed.

Here’s how you can do it:

import random

# Enemy variables
enemies = []
enemy_width, enemy_height = 50, 50
enemy_speed = 3

# Add enemies randomly
def spawn_enemy():
    enemy_x = random.randint(0, WIDTH - enemy_width)
    enemy_y = random.randint(-100, -40)
    enemies.append([enemy_x, enemy_y])

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            bullet_x = player_x + player_width // 2 - bullet_width // 2
            bullet_y = player_y
            bullets.append([bullet_x, bullet_y])

    # Spawn enemies periodically
    if random.randint(1, 50) == 1:
        spawn_enemy()

    # Get key states
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_speed
    if keys[pygame.K_RIGHT] and player_x < WIDTH - player_width:
        player_x += player_speed

    # Move and remove enemies
    for enemy in enemies:
        enemy[1] += enemy_speed
        if enemy[1] > HEIGHT:
            enemies.remove(enemy)

    # Update bullets and check for collisions
    for bullet in bullets:
        bullet[1] -= bullet_speed
        if bullet[1] < 0:
            bullets.remove(bullet)
        for enemy in enemies:
            if enemy[0] < bullet[0] < enemy[0] + enemy_width and enemy[1] < bullet[1] < enemy[1] + enemy_height:
                enemies.remove(enemy)
                bullets.remove(bullet)
                break

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Draw the player spaceship
    pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))

    # Draw the bullets
    for bullet in bullets:
        pygame.draw.rect(screen, (255, 255, 255), (bullet[0], bullet[1], bullet_width, bullet_height))

    # Draw the enemies
    for enemy in enemies:
        pygame.draw.rect(screen, (255, 0, 0), (enemy[0], enemy[1], enemy_width, enemy_height))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Explanation:

  • spawn_enemy(): This function randomly spawns enemies at the top of the screen. We use random.randint() to randomize the enemy’s horizontal position and start them slightly off-screen.
  • enemies[]: Stores the positions of all active enemies. Each enemy moves down the screen, and once it goes off the bottom, it is removed from the list.
  • Collision Detection: For each bullet, we check if it collides with any enemy. If a collision occurs, both the bullet and the enemy are removed from their respective lists.

This creates a basic shooting mechanic where you can destroy enemies by firing bullets.

Game Over and Restart

At this point, the player can move, shoot bullets, and destroy enemies. But there’s no penalty for letting enemies pass or colliding with them. Let’s add a game-over condition and the option to restart.

# Player health
lives = 3

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            bullet_x = player_x + player_width // 2 - bullet_width // 2
            bullet_y = player_y
            bullets.append([bullet_x, bullet_y])

    # Spawn enemies periodically
    if random.randint(1, 50) == 1:
        spawn_enemy()

    # Get key states
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_speed
    if keys[pygame.K_RIGHT] and player_x < WIDTH - player_width:
        player_x += player_speed

    # Move and remove enemies, and check for collisions with the player
    for enemy in enemies:
        enemy[1] += enemy_speed
        if enemy[1] > HEIGHT:
            enemies.remove(enemy)
            lives -= 1  # Lose a life when an enemy passes the screen bottom
        if enemy[0] < player_x + player_width and enemy[0] + enemy_width > player_x and \
                enemy[1] + enemy_height > player_y:
            lives = 0  # Instant death when colliding with an enemy

    # Update bullets and check for collisions with enemies
    for bullet in bullets:
        bullet[1] -= bullet_speed
        if bullet[1] < 0:
            bullets.remove(bullet)
        for enemy in enemies:
            if enemy[0] < bullet[0] < enemy[0] + enemy_width and enemy[1] < bullet[1] < enemy[1] + enemy_height:
                enemies.remove(enemy)
                bullets.remove(bullet)
                break

    # Check if the game is over
    if lives <= 0:
        # Display "Game Over" and allow the player to restart
        font = pygame.font.Font(None, 74)
        text = font.render('Game Over', True, (255, 0, 0))
        screen.blit(text, (WIDTH // 2 - 150, HEIGHT // 2 - 50))
        pygame.display.flip()

        pygame.time.wait(2000)

        # Reset the game state
        enemies.clear()
        bullets.clear()
        player_x, player_y = WIDTH // 2 - player_width // 2, HEIGHT - 60
        lives = 3

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Draw the player spaceship
    pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))

    # Draw the bullets
    for bullet in bullets:
        pygame.draw.rect(screen, (255, 255, 255), (bullet[0], bullet[1], bullet_width, bullet_height))

    # Draw the enemies
    for enemy in enemies:
        pygame.draw.rect(screen, (255, 0, 0), (enemy[0], enemy[1], enemy_width, enemy_height))

    # Display remaining lives
    font = pygame.font.Font(None, 36)
    lives_text = font.render(f'Lives: {lives}', True, (255, 255, 255))
    screen.blit(lives_text, (10, 10))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Explanation:

  • Lives System: We added a lives variable that tracks how many chances the player has left. When an enemy passes the screen’s bottom, or when the player collides with an enemy, lives are reduced.
  • Game Over: If lives reach 0, we display a “Game Over” message using pygame.font.Font() to create the text, then wait for 2 seconds before resetting the game.
  • Restarting the Game: When the game resets, we clear all enemies and bullets from the screen, re-position the player, and reset the lives counter to 3.

Final Thoughts on Building a Simple Space Shooter in Pygame

In this tutorial, we covered every detail of creating a small space shooter game in Pygame. From setting up the game window and handling player movement to adding enemies, shooting mechanics, and collision detection, you’ve now got a basic understanding of how to build a 2D game.

This is just the beginning. From here, you can experiment with:

  • Power-ups: Add items that temporarily boost the player’s abilities.
  • Multiple Levels: Increase difficulty by adding more enemies or changing their behavior in subsequent levels.
  • Enemy Patterns: Create enemies that move in more complex ways, like zigzags or spirals.
  • Sound Effects: Use Pygame’s sound module to add shooting, explosion, and background music.

If you’re serious about learning game development, continue experimenting with more advanced game concepts and explore other game engines like Unity or Godot. Happy coding!

Full Game Code

import pygame
import sys
import random

# Initialize Pygame
pygame.init()

# Set up the screen dimensions
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Space Shooter")

# Define player variables
player_width, player_height = 50, 30
player_x, player_y = WIDTH // 2 - player_width // 2, HEIGHT - 60
player_speed = 5

# Define bullet variables
bullet_width, bullet_height = 5, 10
bullet_speed = 7
bullets = []

# Define enemy variables
enemy_width, enemy_height = 50, 30
enemy_speed = 2
enemies = []

# Player health
lives = 3

# Set up the clock for FPS
clock = pygame.time.Clock()

# Function to spawn an enemy
def spawn_enemy():
    enemy_x = random.randint(0, WIDTH - enemy_width)
    enemy_y = -enemy_height
    enemies.append([enemy_x, enemy_y])

# Main game loop
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            bullet_x = player_x + player_width // 2 - bullet_width // 2
            bullet_y = player_y
            bullets.append([bullet_x, bullet_y])

    # Spawn enemies periodically
    if random.randint(1, 50) == 1:
        spawn_enemy()

    # Get key states
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT] and player_x > 0:
        player_x -= player_speed
    if keys[pygame.K_RIGHT] and player_x < WIDTH - player_width:
        player_x += player_speed

    # Move and remove enemies, and check for collisions with the player
    for enemy in enemies:
        enemy[1] += enemy_speed
        if enemy[1] > HEIGHT:
            enemies.remove(enemy)
            lives -= 1  # Lose a life when an enemy passes the screen bottom
        if enemy[0] < player_x + player_width and enemy[0] + enemy_width > player_x and \
                enemy[1] + enemy_height > player_y:
            lives = 0  # Instant death when colliding with an enemy

    # Update bullets and check for collisions with enemies
    for bullet in bullets:
        bullet[1] -= bullet_speed
        if bullet[1] < 0:
            bullets.remove(bullet)
        for enemy in enemies:
            if enemy[0] < bullet[0] < enemy[0] + enemy_width and enemy[1] < bullet[1] < enemy[1] + enemy_height:
                enemies.remove(enemy)
                bullets.remove(bullet)
                break

    # Check if the game is over
    if lives <= 0:
        # Display "Game Over" and allow the player to restart
        font = pygame.font.Font(None, 74)
        text = font.render('Game Over', True, (255, 0, 0))
        screen.blit(text, (WIDTH // 2 - 150, HEIGHT // 2 - 50))
        pygame.display.flip()

        pygame.time.wait(2000)

        # Reset the game state
        enemies.clear()
        bullets.clear()
        player_x, player_y = WIDTH // 2 - player_width // 2, HEIGHT - 60
        lives = 3

    # Fill the screen with black color
    screen.fill((0, 0, 0))

    # Draw the player spaceship
    pygame.draw.rect(screen, (0, 128, 255), (player_x, player_y, player_width, player_height))

    # Draw the bullets
    for bullet in bullets:
        pygame.draw.rect(screen, (255, 255, 255), (bullet[0], bullet[1], bullet_width, bullet_height))

    # Draw the enemies
    for enemy in enemies:
        pygame.draw.rect(screen, (255, 0, 0), (enemy[0], enemy[1], enemy_width, enemy_height))

    # Display remaining lives
    font = pygame.font.Font(None, 36)
    lives_text = font.render(f'Lives: {lives}', True, (255, 255, 255))
    screen.blit(lives_text, (10, 10))

    # Update the screen
    pygame.display.flip()

    # Cap the frame rate
    clock.tick(60)

Thank you for reading <3