Tower Defense Game: Getting Started

Python package management is not the easiest thing to wrap your head around. Nevertheless, it’s important that we capture the requirements our game has, properly, and commit them to a Python package.

Getting Started

Configuring your Python Environment

You need Python 3.8 or higher to easily follow this course. The demo itself explicitly requires 3.8 or higher. You can use older versions, but certain, minor, Python language features and standard library additions are unavailable if you do.

You must ensure that your version of Python is installed with tkinter, a UI toolkit used in the demo to handle opening and saving levels, if you want to run the demo.

It’s not a strict requirement for your own game, but you may need to install python3.X-tk on Ubuntu, or ensure TKinter is selected during installation on Windows and Mac.

You can check that it works by typing import tkinter.

I also recommend you develop in a virtual environment, a way of separating your packages so they don’t overlap with other projects.

Now, let’s create a package to host our game.

Creating a Python Package

Python’s package management gets a (deserved) bad reputation for complexity and confusion. But knowing how to create packages is one of those things that is difficult until you’ve done it a few times. Luckily, most packages – even ones you may end up deploying on a server somewhere – will usually work with the simple method I show you below.

Our goal is to have a proper package with a given package name – the demo is called tower, but you should pick a name of your own – that hosts the package requirements, source code and assets.

  1. Create an empty directory. I’m naming it tower in this example.

  2. Inside, optionally git init if you want it version-controlled.

  3. Now, we need to create two files. First, setup.py:

    from setuptools import setup
    setup()

    And this placeholder file that’ll help futureproof your code. It’s called pyproject.toml:

    [build-system]
    requires = ["setuptools"]
    build-backend = "setuptools.build_meta"
  4. And now for the most important file, setup.cfg:

    [metadata]
    name = tower
    version = 1.0
    description = Your description
    long_description = A longer description
    license = Your license here
    classifiers =
        Programming Language :: Python :: 3
    
    [options]
    zip_safe = false
    packages = find:
    install_requires =
        click==8.*
        pygame==2.*
        structlog
    
    [options.package_data]
    tower.assets.gfx = *.png
    tower.assets.audio = *.wav, *.ogg
    tower.assets.levels = *.json
    
    [options.entry_points]
    # Optional, but if you want to keep it,
    # make sure you have a function called
    # main() in tower.main!
    console_scripts =
        tower = tower.main:main

    This is the example file used in the demo (but with the comments stripped and a few things tweaked for simplicity’s sake.) You can replace the details with your own.

    The important bits deserve scrutiny though:

    1. install_requires is a newline-separated list of packages to install when the package is installed. This is important, of course, because we need these dependencies to run our code.

    2. name is the name of the package that is installed.

    3. packages detects your packages automatically.

    4. [options.package_data] is a list of locations where Python should look for things that it would not ordinarily include, like our media assets.

    5. console_scripts creates a shortcut you can invoke from your command prompt or terminal. It’s called tower, and it runs the main function in tower.main.

    This declarative configuration specifies the structure of your package.

  5. Now the directory structure. Create a directory called tower (or whatever you prefer.)

    1. Inside the tower directory, create a blank file called __init__.py. This is the root of your project, so that when you type import tower, everything works.

    2. If you want to use the same directory structure as I specified in the setup.cfg example above, you will need a few more directories and files:

    setup.py
    setup.cfg
    tower/
    ├── assets
    │   ├── __init__.py
    │   ├── audio
    │   │   ├── __init__.py
    │   ├── gfx
    │   │   ├── __init__.py
    │   └── levels
    │       └── __init__.py
    ├── __init__.py
    └── main.py

Feel free to shift things around; the important thing to remember is that each sub-directory of tower has an __init__.py file. If you don’t want main.py, then don’t forget to update console_scripts.

Now you’re ready to test that your project installation works. To start, we’ll install it in editable mode, that means we tell setuptools (and thus Python) to find the code in the directory that you created the files instead of an opaque directory structure usually reserved for packages you install but don’t want to edit.

To do this, go to the root of your package with setup.cfg and run this:

$ python -m pip install --editable .

Pip will now install your package. When it’s done, you should see something like this:

[ ... lots of output ... ]
Successfully installed tower-1.0

You can confirm it works by typing this in a python shell:

>>> import tower

If you encounter errors, check that you’ve replicated the package structure correctly and that, if you renamed things, you did it consistently. Alternatively you can use the structure in the demo to get you started.

If everything worked correctly, you’ll import your package successfully, and you’re ready to go.

Understanding package management is important

Yes, we’re just writing a game, but this knowledge will work just as well with a large webapp as it would almost anything else. Our requirements – and indeed that of all but the most complex packages you find on PyPi – is a simple case of capturing requirements and, if you have non-python-code you want to include, the location of those assets.

Doing it properly will help you down the line

I see a lot of Python developers subvert the packaging process by amending sys.path or other such trickery. That approach works just fine until it doesn’t – like when you want to share your code with someone else, or use the ability to dynamically import resources from your package (and we’ll be doing just that with our media assets.)

Spend a bit of time to familiarize yourself with this process. You may one day be called upon to create a package or resolve problems with one.

If you mess up, revert to a known state

This is easiest to do with source control systems like Git. You should also ensure that you delete the <package name>.egg-info directory as setuptools loves to cache state in that directory.

There are third-party alternatives available also

Tools like Poetry promise to make the process easier or more manageable, but we’re a long, long while away from deprecating and replacing the existing package machinery. So even if you do use Poetry, most other packages don’t. You’ll eventually find yourself interacting with, and debugging or extending, the standard method of writing packages.

Installing & Playing the Tower Defense Demo

This course ships with source code that demonstrates all the concepts you’ll learn about. I recommend you install and play with it, just to get a feeling for what the end-goal is, and to serve as working example that you can refer back to in case you run into problems with your own game.

First, download the demo and extract it to a directory.

Next, you must install it:

$ cd <demo path>
$ python -m pip install --editable .

If done in a virtual environment, you now have a clean slate to edit, run and experiment with the demo. You can launch it by typing tower launch or python -m tower.main launch.

Done right, you should see the main menu appear.

The game ships with a demo level to demonstrate the game play. You can find it by selecting “Play” in the game, and navigating to the tower/assets/levels directory and opening “demo.json”.

Sound and Graphical Assets

You can find a selection of assets – or you can use your own, itch.io is a fine source – in the demo under tower/assets. The assets are part of the package hierarchy, so we can use Python’s import mechanism to import them without having to worry about finding out where they’re located on the file system.

Summary

Spending a little bit of time getting a proper package structure set up and working will pay dividends down the road.

Packages capture third-party requirements

Keeping track of the versions of third-party packages your package depends on avoids version drift and compatibility issues. It’s a common problem where a newer version of a package is released and you inadvertently end up utilizing a package version that your software was never tested against.

You can also include non-Python assets, like data files

Python packages can include data file assets – like images, sound effects, etc. – if you tell it to. We’ll use it later to load our assets into pygame in a maintainable way that avoids messing with explicit file paths.

Liked the Article?

Why not follow us …

Be Inspired Get Python tips sent to your inbox

We'll tell you about the latest courses and articles.

Absolutely no spam. We promise!