Implementing a Plants vs. Zombies Clone with Python and Pygame

Begin by importing the necesary libraries and defining the global configuration constants. These settings establish the screen dimensions, asset directories, and initial state variables for the game session.

import pygame
import sys

# Configuration constants
ASSET_DIR = "resources/"
WIDTH = 800
HEIGHT = 600
TARGET_FPS = 60

# Game state variables
game_active = True
level_index = 1
current_score = 0
sun_currency = 250

Next, define the primary game engine class. This component manages window initialization, the main event loop, and screen updates. The execution loop persists until the termination flag is set to false.

class GameEngine:
    def __init__(self):
        self.display = None
        self.clock = None

    def initialize_screen(self):
        pygame.init()
        self.display = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption("Garden Defense")
        self.clock = pygame.time.Clock()

    def run_loop(self):
        self.initialize_screen()
        while game_active:
            self.display.fill((255, 255, 255))
            self.process_events()
            self.render_interface()
            pygame.display.flip()
            self.clock.tick(TARGET_FPS)

    def process_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

Interface elements such as score, currency, and control instructions require dynamic rendering. Implement a helper method to generate text surfaces and draw them onto the main display at specific coordinates.

    def generate_text(self, message, size, color):
        font = pygame.font.SysFont('consolas', size)
        return font.render(message, True, color)

    def render_interface(self):
        # Display currency
        sun_text = self.generate_text(f"Sun: {sun_currency}", 24, (0, 0, 0))
        self.display.blit(sun_text, (10, 10))

        # Display level and score
        status = self.generate_text(
            f"Level: {level_index} | Score: {current_score}", 
            24, (0, 0, 0)
        )
        self.display.blit(status, (10, 40))

        # Instructions
        hint = self.generate_text(
            "Left Click: Sunflower | Right Click: Peashooter", 
            18, (255, 0, 0)
        )
        self.display.blit(hint, (WIDTH - 400, HEIGHT - 30))

Finally, construct the grid system where plants are positioned. The map class handles tile coordinates and background imagery rendering.

class GridMap:
    def __init__(self):
        self.tile_size = 100
        self.row_count = 5
        self.col_count = 9
        self.grid = []

    def load_textures(self):
        # Placeholder for loading tile images
        self.light_tile = pygame.Surface((self.tile_size, self.tile_size))
        self.light_tile.fill((100, 200, 100))
        self.dark_tile = pygame.Surface((self.tile_size, self.tile_size))
        self.dark_tile.fill((50, 150, 50))

    def render(self, surface):
        for r in range(self.row_count):
            for c in range(self.col_count):
                x = c * self.tile_size
                y = r * self.tile_size
                if (r + c) % 2 == 0:
                    surface.blit(self.light_tile, (x, y))
                else:
                    surface.blit(self.dark_tile, (x, y))

Tags: python pygame game-development Tutorial coding

Posted on Tue, 13 Oct 2026 16:56:27 +0000 by sloth456