Skip to content

JARVISbyte/voila

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 

Repository files navigation

Voila

Voila is a simple scene engine for pygame. It provides a very basic functionality of managing scene transitions and game exit via straightforward mechanism called fetchcalls.

History // Technical information

Although written in 2024 for internal use, voila is made public in 2026 to perhaps help novice pygame users or experienced programmers tired of rewriting the same code over and over again.

In no way it tries to appear as an example of perfect code, but rather a simple template that can save time and hopefully even support a small-to-middle sized project.

Voila was tested on Python 3.11.4 with Pygame 2.5.2.

Structure

Voila relies on 3 main classes:

  • Engine manages scene-transitions and game exits.
  • Scene defines a common api for Engine. All scenes must inherit Scene class.
  • Fetchcall defines a message format that scenes send to Engine whenever they want something done.

Engine

Engine(title: str, resolution: tuple[int, int], fps: int, scenes: tuple[Scene], default_scene_id: str)

  • title - title of the pygame window.
  • resolution - resolution of the window.
  • fps - desired fps count. If actual fps is greater, engine will attempt to slow game down by a difference between desired and actual inter-frame time.
  • scenes - an array of all scenes that can potentially be entered in the game.
  • default_scene_id - id of the scene that is desired to be entering (e.g. main menu).

Engine is implemented in a singleton pattern, meaning that calling Engine() in multiple places inside one project will return the same instance. This allows for easier access in a project with multiple files.

Scene

Scene(id: str) - engine distinguishes scenes by ids.

A custom scene can be made to function by redefining this 4 methods:

  • __init__(self) - if (re)defined, this must call super().__init__(id: str)
  • handle_event(self, event) - allows scene to capture key-presses, mouse clicks, etc. This method gets called by engine individually for each event.
  • update(self, dt) - allows scene to 'think'. Delta time is passed in seconds.
  • draw(self, screen) - allows scene to draw on a screen. By default, engine does not clear screen surface (i.e. there is no screen.fill('black') in game loop), but only flips display after the scene returns draw.

Other important method is set_fetchcall(fetchcall: Fetchcall). For example, if the scene wants to quit the game upon left mouse button click, the code should resemble this:

def handle_event(self, event):
    ...
    if event.type == pygame.MOUSEBUTTONDOWN and pygame.mouse.get_pressed()[0]:
        self.set_fetchcall(Fetchcall(Fetchcall.QUIT))
    ...

More on fetchcalls below.

Fetchcall

Fetchcall(code: int, *args) - code defines the type of fetchcall.

Fetchcall is essentially a request that any scene can make to ask the engine to do something with the game. It is intended to be expandable, so that any reasonable game-wide action scene would like to be done can be implemented by inhereting the fetchcall class.

The two predefined fetchcalls are QUIT and CHANGE_SCENE:

  • QUIT fetchcall has code 0 and requires no arguments.
  • CHANGE_SCENE fetchcall has code 1 and requires single argument: id of the desired scene.

Fetchcall class defines fetchcall codes, so instantiating a QUIT fetchcall might look like Fetchcall(Fetchcall.QUIT), and instantiating a CHANGE_SCENE fetchcall might look like Fetchcall(Fetchcall.CHANGE_SCENE, 'another_scene_id').

Fetchcall arguments should be passed as regular method arguments, not enclosed into an array (i.e. Fetchcall(code, arg1, arg2, arg3, ...) and NOT Fetchcall(code, (arg1, arg2, arg3, ...))), as python will enclose them into an array automatically.

IMPORTANT when Scene.set_fetchcall() is called, the Scene instance stores provided fetchcall in the internal variable _fetchcall, so it can be retrieved by engine when it is time to do so. This implies that a given scene can only store 1 fetchcall at a time. For this reason, Scene has an internal preference system: fetchcalls with lower codes have higher priority. For example, if you ask scene to execute QUIT fetchcall and then to execute CHANGE_SCENE fetchcall, the latter one will simply be ignored. This is precisely why QUIT has code 0 and CHANGE_SCENE 1.

Example

Full example can be found in demo.py.

About

Pygame-based scene control game engine.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages