Skip to main content

A game engine that lets you write text/ansii based games, targets 60fps.

Project description

Installation

pip install frolic

Frolic Engine depends on a few packages, so to get it running they will need to be installed as well

pip install pynput numpy colorama

Creating a basic game

Create a class that inherits from Game, provide an __init__() and call super().__init__(). Overriding update() and draw() are required.

import datetime
from frolic import Game

class TestGame(Game):
    def __init__(self):
        super().__init__()

    def update(self, deltatime: datetime.timedelta):
        # deltatime is the time since the previous update call
        # deltatime.total_seconds() is a floating point
        pass

    def draw(self)
        # must call super
        super().draw()

Launch the game by calling the game's run() function. This example so far will just produce an empty screen.

from frolic import Game

class TestGame(Game):
    . . .

game = TestGame()
game.run()

Handling inputs. Notice the keyboard import.

from frolic import Game
from pynput import keyboard

class TestGame(Game):
    def __init__(self):
        super().__init__()
        self.set_on_keydown(self.on_key_down)

    def on_key_down(self, key: keyboard.Key):
        character_key = hasattr(key, 'char')

        # will show how to use character keys later
        if character_key:
            pass

        # non character keys, like Shift or Ctrl
        else:
            # on escape kill the game
            if key == keyboard.Key.esc:
                # end_game() is inherited from frolic.Game
                self.end_game()
                return

To draw characters/symbols to the screen override the draw() function. self.screen is a Screen object that represents the current frame. Set values on the screen to have them show up in the console.

from frolic import Game, Matrix, Vector2
class TestGame(Game):
    . . .

    def draw(self):
        # call screen.set() to put a character at a given x, y coordinate
        self.screen.set(x=0, y=0, '#')

        # draw a matrix at a given position by calling screen.draw_matrix()
        position = Vector2(3, 3)
        matrix = Matrix([
            ['#', '#', '#'],
            ['#', '0', '#'],
            ['#', '#', '#'],
        ])
        self.screen.draw_matrix(matrix, position)

        # Matrix also has a convenient way of making a simple matrix by using Matrix.empty_sized():
        #     the following produces:
        #         ['X', 'X']
        #         ['X', 'X']
        #         ['X', 'X']
        matrix2 = Matrix.empty_sized(rows=3, columns=2, value='▢')

        # Note: Matrices are anchored at the top left corner,
        #       so drawing matrix2 at position Vector2(x=1, y=1)
        #       will produce this screen:
        self.screen.draw_matrix(matrix2, Vector2(x=1, y=1))
        # [' ', ' ', ' ', ' ', ' ', ' ', ' ']
        # [' ', 'X', 'X', ' ', ' ', ' ', ' ']
        # [' ', 'X', 'X', ' ', ' ', ' ', ' ']
        # [' ', 'X', 'X', ' ', ' ', ' ', ' ']
        # [' ', ' ', ' ', ' ', ' ', ' ', ' ']
        # [' ', ' ', ' ', ' ', ' ', ' ', ' ']

        # call super and the Game will handle applying this frame's "screen" to the console window
        super().draw()

Instances of GameObject are a convenience class to represent objects in the game. They have a matrix that is of type Matrix and a position that is of type Vector2.

from frolic import Game, GameObject, Matrix, Vector2
from pynput import keyboard

class Player(GameObject):
    def __init__(self):
        super().__init__()
        self.position = Vector2(x=5, y=0)
        self.matrix = Matrix.empty_sized(rows=3, columns=2, value='0')
        # self.size is a Vector2 getter representing the size of the current matrix,
        # so in this example self.size.x == 2 because self.matrix has 2 columns
    def moveLeft():
        self.position.x -= 1
    def moveRight():
        self.position.x += 1

class TestGame(Game):
    def __init__(self):
        super().__init__()
        self.player = Player()
        self.set_on_keydown(self.on_key_down)

    . . .

    def on_key_down(self, key: keyboard.Key):
        character_key = hasattr(key, 'char')
        if character_key:
            if key.char == 'a':
                if self.player.position.x > 0:
                    self.player.moveLeft()
                return
            if key.char == 'd':
                if self.player.position.x < 10:
                    self.player.moveRight()
                return
        else:
            if key == keyboard.Key.esc:
                self.end_game()
                return

    def draw(self):
        self.screen.draw_matrix(self.player.matrix, self.player.position)
        super().draw()

Another convenience is the MatrixBorder class, it creates a copy of the given matrix with a border on it. MatrixBorder has a default border of SINGLE_LINE_THIN but also has SINGLE_LINE_THICK and DOUBLE_LINE

border = MatrixBorder(sides=MatrixBorder.DOUBLE_LINE)
        °°°°°        ╔═══╗
        °°°°°        ║°°°║
input   °°A°° output ║°A°║
        °°°°°        ║°°°║
        °°°°°        ╚═══╝

Borders other than the provided side-characters can also be used:

border = MatrixBorder(sides={
    'top': 'X',
    'top_left': 'X',
    'top_right': 'X',
    'left': 'X',
    'right': 'X',
    'bottom': 'X',
    'bottom_left': 'X',
    'bottom_right': 'X',
})
        °°°°°        XXXXX
        °°°°°        X°°°X
input   °°A°° output X°A°X
        °°°°°        X°°°X
        °°°°°        XXXXX
class Card(GameObject):
    def __init__(self):
        super().__init__()
        self.position = Vector2(x=2, y=1)
        _matrix = Matrix.empty_sized(rows=6, columns=6, value=' ')
        _matrix[1][1] = '2'
        # ♤ ♡ ♧ ♢
        _matrix[2][1] = '♤'
        border = MatrixBorder() # default to single thin line
        self.matrix = _matrix.with_border(border)

Examples

A simple example to copy/paste: example_game.py

Another simple game that creates a viewport (for a game like zelda) example_game_viewport.py

A more fleshed out full Tetris example: CharPyTetris Bundle-Breaker (a match 3 game): CharPyBundleBreaker

Developing CharPy

Clone this project

git clone <url for this project>

Create a virtual environment https://docs.python.org/3/library/venv.html and activate it

# windows:
.\venv\Scripts\activate

# linux:
./venv/bin/activate

Install this package into venv

pip install .

Start developing by modifying the example_game.py or create some tests. Remember that this README's examples very closely follow example_game.py so changes there should reflect here in this README.

python example_game.py
python tests/border.py
python tests/matrix.py

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

frolic-engine-1.0.0.tar.gz (14.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

frolic_engine-1.0.0-py3-none-any.whl (14.2 kB view details)

Uploaded Python 3

File details

Details for the file frolic-engine-1.0.0.tar.gz.

File metadata

  • Download URL: frolic-engine-1.0.0.tar.gz
  • Upload date:
  • Size: 14.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.5

File hashes

Hashes for frolic-engine-1.0.0.tar.gz
Algorithm Hash digest
SHA256 7f38e423cb2aa403ffe6069963120a4ae3b534e7391506bbb3357d9dde4def19
MD5 7d4ff3b677769368c7317aefa033ae0d
BLAKE2b-256 8f081376f7c7a62d5b52db12bb28b2005b0c1b06725f29babd1a8ff0b80b5863

See more details on using hashes here.

File details

Details for the file frolic_engine-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: frolic_engine-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 14.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.5

File hashes

Hashes for frolic_engine-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ce2dab521e50f01ffdfc59ec5124a0cc7236de27290b71be91f91204fccd5e0
MD5 bf92ae4be38d7a8a481fa0fe4b4d4adc
BLAKE2b-256 a42b0df61960401ef4dbcb1a5297928929f33a4cc6e771ba16d6097e7dfd8040

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page