Project template (gale-admin)

You can organize the source code of your project as you want. However, this library provides the a command to create a basic template for your project. If you want to use it, you only need to execute the following command:

gale-admin create-project {project_name}

For instance, if you want to create a project called “my_first_arpg_game”, then you should execute:

gale-admin create-project my_first_arpg_game

It will create a directory with the same name with the following structure:

my_first_arpg_game
├── assets
│   ├── fonts
│   ├── graphics
│   └── sounds
├── main.py
├── README.md
├── settings.py
└── src
   └── MyFirstArpgGame.py
  • fonts is an empty directory where you should store your font files.

  • graphics is an empty directory where you should store your image files.

  • sounds is an empty directory where you should store your audio files.

  • README.md contains a base README file. It contains the following contents:

# My First Arpg Game
  • main.py is the main program to run your game, it contains the following contents:

"""
This module was autogenerated by gale.
"""
import settings
from src.MyFirstArpgGame import MyFirstArpgGame

if __name__ == "__main__":
    game = MyFirstArpgGame(
        "My First Arpg Game",
        settings.WINDOW_WIDTH, settings.WINDOW_HEIGHT,
        settings.VIRTUAL_WIDTH, settings.VIRTUAL_HEIGHT
    )
    game.exec()
  • settings.py contains some contants and the registering of the key escape to quit the game. Its contents is the following:

"""
This module was autogenerated by gale.
"""
import pathlib

import pygame

from gale import frames
from gale import input_handler

input_handler.InputHandler.set_keyboard_action(input_handler.KEY_ESCAPE, "quit")

# Size we want to emulate
VIRTUAL_WIDTH = 320
VIRTUAL_HEIGHT = 180

# Size of our actual window
WINDOW_WIDTH = 1280
WINDOW_HEIGHT = 720

BASE_DIR = pathlib.Path(__file__).parent

# Register your textures from the graphics folder, for instance:
# TEXTURES = {
#     "my_texture": pygame.image.load(BASE_DIR / "graphics/my_texture.png")
# }
TEXTURES = {}

# Register your frames, for instance:
# FRAMES = {
#     "my_frames": frames.generate_frames(TEXTURES["my_texture"], 16, 16)
# }
FRAMES = {}

pygame.mixer.init()

# Register your sound from the sounds ```folder, for instance:
# SOUNDS = {
#     "my_sound": pygame.mixer.Sound(BASE_DIR, "assets" / "sounds/my_sound.wav"),
# }
SOUNDS = {}

pygame.font.init()

# Register your fonts from the fonts folder, for instance:
# FONTS = {
#     "small": pygame.font.Font(BASE_DIR / "fonts/font.ttf", 8)
# }
FONTS = {}
  • src/MyFirstArpgGame.py contains the class to define your game. Its contents is the following:

"""
This module was autogenerated by gale.
"""
import pygame

from gale.game import Game
from gale.input_handler import InputData, InputHandler, InputListener
from gale.state import StateMachine


class MyFirstArpgGame(Game, InputListener):
    def init(self) -> None:
        self.state_machine = StateMachine()
        InputHandler.register_listener(self)

    def update(self, dt: float) -> None:
        self.state_machine.update(dt)

    def render(self, surface: pygame.Surface) -> None:
        self.state_machine.render(surface)

    def on_input(self, input_id: str, input_data: InputData) -> None:
        if (input_id == "quit" and input_data.pressed):
            self.quit()

Adding a state (gale-admin create-state)

Once inside a project’s directory (the one with main.py and src/ in it), you can scaffold a new gale.state.BaseState subclass with:

gale-admin create-state {state_name}

For instance:

gale-admin create-state menu

creates src/states/menu_state.py (and src/states/__init__.py, if it doesn’t exist yet) with a MenuState class stubbed out with every BaseState method (enter, exit, on_input, update, render), ready to be registered with a StateMachine:

from src.states.menu_state import MenuState

self.state_machine = StateMachine({"menu": MenuState})
self.state_machine.change("menu")

The name is normalized regardless of how it’s cased or whether a trailing state/State is already there — menu, menu_state, and MenuState all produce the same MenuState class in the same file.