Skip to main content

Pygame Essentials

Project description


title: 'Guide: How to use PyGess'

Introduction

This document will walk you through the implementation of the PyGess library.

PyGess is a physics engine designed to manage game objects, their interactions, and their updates within a game world. It provides classes and functions to handle entities, game objects, and worlds, along with utility functions to manage these components.

We will cover:

  1. The GameObjects class and its methods.
  2. The World class and its methods.
  3. The entity and MovingEntity classes.
  4. Utility functions for managing worlds and entities.
  5. A test script to demonstrate usage.

GameObjects class

The GameObjects class is responsible for storing and updating a list of entities. It acts like a sprite group but is tailored for entities.

Initialization


The constructor initializes the list of entities.

class GameObjects:
    '''
    # Description
    A class which stores list of Entities. Also updates them.
    Basically a sprite group for entities instead.
    
    # Functions
    ## Init
    ```
    def __init__(self, entities:list) -> None:
        self.entities = entities
    ```
    Initializes entity list.

Update method


The update method ensures all entities in the list are unique and calls their update method.


    ## update
    ```
    def update(self):
        from . import entity as ent
        self.entities = list(set(self.entities))
        for entity in self.entities:
            if isinstance(entity, (ent.Entity)):
                entity.update()
    ```
    Updates all entities in list.
    
    '''
    def __init__(self, entities:list) -> None:
        self.entities = entities
        
    def update(self):
        from . import entity as ent
        self.entities = list(set(self.entities))
        for entity in self.entities:
            if isinstance(entity, (ent.Entity)):
                entity.update()
            
    def append(self, *entity):
        for e in entity:
            if e != None:
                self.entities = list(self.entities)
                self.entities.append(e)

Append method


The append method adds new entities to the list.


    ## update
    ```
    def update(self):
        from . import entity as ent
        self.entities = list(set(self.entities))
        for entity in self.entities:
            if isinstance(entity, (ent.Entity)):
                entity.update()
    ```
    Updates all entities in list.
    
    '''
    def __init__(self, entities:list) -> None:
        self.entities = entities
        
    def update(self):
        from . import entity as ent
        self.entities = list(set(self.entities))
        for entity in self.entities:
            if isinstance(entity, (ent.Entity)):
                entity.update()
            
    def append(self, *entity):
        for e in entity:
            if e != None:
                self.entities = list(self.entities)
                self.entities.append(e)

World class

The World class manages the game world, including gravity, time, and game objects.

Initialization


The constructor initializes the world with gravity, game objects, and other necessary attributes.

class World:
    def __init__(self, grav: tuple, *game_objects) -> None:
        self.gravity = pyg.math.Vector2(grav)
        self.dt = 0
        self.prev_time = time.time()
        self.is_active = False
        
        self.__counter = 0
        self.__counter2 = 0
        
        self.__objects = GameObjects(game_objects)
        self.runtime_obj = copy.deepcopy(self.__objects)
        self.__base_state = self.runtime_obj
        
        worlds.append(self)
        
    def update(self):
        if not self.is_active:
            self.__counter2 = 0
            return
        
        if self.__counter2 == 0:
            self.__reset()
        
        if self.__counter == 0:
            self.__set_runtime()

Update method


The update method handles the world's update logic, including resetting and setting runtime states.


        self.runtime_obj.update()
        
        self.__counter += 1
        self.__counter2 += 1
    
    def add_gameobj(self, *gameobj):
        for obj in gameobj:
            self.__objects.append(obj)
    
    def load_new_object(self, *gameobj):
        for obj in gameobj:
            self.runtime_obj.append(obj)
        
    def update_delta_time(self):

Add and load game objects


The add_gameobj and load_new_object methods add game objects to the world and runtime objects, respectively.


        self.runtime_obj.update()
        
        self.__counter += 1
        self.__counter2 += 1
    
    def add_gameobj(self, *gameobj):
        for obj in gameobj:
            self.__objects.append(obj)
    
    def load_new_object(self, *gameobj):
        for obj in gameobj:
            self.runtime_obj.append(obj)
        
    def update_delta_time(self):

Update delta time


The update_delta_time method updates the delta time for the world.


        if self.is_active: 
            self.dt = min(time.time() - self.prev_time, 0.1)
            self.prev_time = time.time()
            return
        self.dt = get_active_world().dt
        self.dt = min(self.dt, 0.1)
    
    def __set_runtime(self):
        ent = []
        for e in self.__objects.entities:
            if e.rect not in data.all_rects:
                data.all_rects.append(e.rect)
            en = copy.deepcopy(e)
            en.id = uuid.uuid4()
            en.parent = e
            ent.append(copy.deepcopy(en))
        
        self.runtime_obj = GameObjects(ent)
        self.__base_state = GameObjects(copy.deepcopy(ent))
        
    def __reset(self):
        ent = []
        for e in self.__base_state.entities:
            if e.rect not in data.all_rects:
                data.all_rects.append(e.rect)
            ent.append(copy.deepcopy(e))
        
        self.runtime_obj = GameObjects(ent)

Set runtime and reset methods


The __set_runtime and __reset methods manage the runtime state of the world.


        if self.is_active: 
            self.dt = min(time.time() - self.prev_time, 0.1)
            self.prev_time = time.time()
            return
        self.dt = get_active_world().dt
        self.dt = min(self.dt, 0.1)
    
    def __set_runtime(self):
        ent = []
        for e in self.__objects.entities:
            if e.rect not in data.all_rects:
                data.all_rects.append(e.rect)
            en = copy.deepcopy(e)
            en.id = uuid.uuid4()
            en.parent = e
            ent.append(copy.deepcopy(en))
        
        self.runtime_obj = GameObjects(ent)
        self.__base_state = GameObjects(copy.deepcopy(ent))
        
    def __reset(self):
        ent = []
        for e in self.__base_state.entities:
            if e.rect not in data.all_rects:
                data.all_rects.append(e.rect)
            ent.append(copy.deepcopy(e))
        
        self.runtime_obj = GameObjects(ent)

Deactivate method


The _deactivate method deactivates the world.


    def _deactivate(self):
        self.is_active = False

Utility functions

Get active world


The get_active_world function returns the currently active world.

def get_active_world() -> World:
    for world in worlds:
        if world.is_active:
            return world

Debug no active worlds


The _debug_no_active_worlds function counts the number of active worlds.

def _debug_no_active_worlds():
    counter = 0
    
    for world in worlds:
        if world.is_active:
            counter += 1
    
    return counter

Set active world


The set_active_world function sets a given world as active and deactivates the current active world if any.

def set_active_world(world:World):
    if _debug_no_active_worlds() > 0:
        get_active_world()._deactivate()
        
        
    world.is_active = True

Get all worlds


The get_all_worlds function returns all worlds.

def get_all_worlds():
    return worlds

Update delta time for all worlds


The update_delta_time function updates the delta time for all worlds.

def update_delta_time():
    for w in get_all_worlds():
        w.update_delta_time()

Update all worlds


The update_worlds function updates all worlds.

def update_worlds():
    for w in get_all_worlds():
        w.update()

Prefab instance functions


The first_instance_of_prefab_in_world and all_instances_of_prefab_in_world functions find instances of a prefab entity in a world.

def first_instance_of_prefab_in_world(world, prefab_entity) -> 'entity.Entity':
    for e in world.runtime_obj.entities:
        if e.parent.id == prefab_entity.id:
            return e


def all_instances_of_prefab_in_world(world, prefab_entity) -> list:
    instances = []
    for e in world.runtime_obj.entities:
        if e.parent.id == prefab_entity.id:
            instances.append(e)
    
    return instances

Entity class

The entity class represents a game entity with position, dimensions, and optional color or image.

Initialization


The constructor initializes the entity with position, dimensions, and optional color or image.

class Entity(pyg.sprite.DirtySprite):
    def __init__(self, position: tuple, dimensions: tuple, color=None, image_path=None) -> None:
    
        pyg.sprite.DirtySprite.__init__(self)
        self.pos = pyg.math.Vector2(position)
        self.dimensions = dimensions
        self.color = color
        
        self.parent = None
        self.id = uuid.uuid4()

Update method


The update method updates the entity's position, checks for collisions, and updates its sprite group.


    def get_all_obj_colliding_with(self):
        return self._colliding_objects

    def update(self):
        self.active_world = physics.get_active_world()

        self.update_rect()
        self.check_collisions()
        
        if self in self.spr_group:
            self.spr_group.remove(self)
            self.spr_group.update()
            self.spr_group.add(self)
        else:
            self.spr_group.update()
            
        self.spr_group.draw(pyg.display.get_surface())

Collision methods


The update_rect, check_collisions, is_colliding_with, and get_all_obj_colliding_with methods handle collision detection and response.


        self._colliding_objects = []
            
        data.all_rects.append(self.rect)
    
    def update_rect(self):
        index = data.all_rects.index(self.rect)
        data.all_rects.remove(self.rect)
        
        self.rect.topleft = self.pos
        self.rect.size = self.dimensions
        
        data.all_rects.insert(index, self.rect)
    
    def check_collisions(self):
        self._colliding_objects = [r for r in data.all_rects if r != self.rect and self.rect.colliderect(r)]
    
    def is_colliding_with(self, rect):
        return rect in self._colliding_objects

    def get_all_obj_colliding_with(self):
        return self._colliding_objects

    def update(self):
        self.active_world = physics.get_active_world()

        self.update_rect()
        self.check_collisions()
        
        if self in self.spr_group:
            self.spr_group.remove(self)
            self.spr_group.update()
            self.spr_group.add(self)
        else:
            self.spr_group.update()
            
        self.spr_group.draw(pyg.display.get_surface())

MovingEntity class

The MovingEntity class extends entity to include velocity and gravity effects.

Initialization


The constructor initializes the moving entity with position, dimensions, velocity, and optional color or image.

class MovingEntity(Entity):
    def __init__(self, position: tuple, dimensions: tuple, velocity: tuple, color:tuple=None, image_path=None) -> None:
        super().__init__(position, dimensions, color=color, image_path=image_path)
        self.velocity = pyg.math.Vector2(velocity)
        self.orignal_vel = pyg.math.Vector2(velocity)
        self.is_affected_by_gravity = False

    def update(self):
        self.active_world = physics.get_active_world()

Update method


The update method updates the entity's position, checks for collisions, and moves the entity.


        self.update_rect()
        self.check_collisions()
        self.move()
        
        if self in self.spr_group:
            self.spr_group.remove(self)
            self.spr_group.update()
            self.spr_group.add(self)
        else:
            self.spr_group.update()
            
        self.spr_group.draw(pyg.display.get_surface())
        
    def move(self):
        self.pos += self.velocity * self.active_world.dt
        
        if not self.is_affected_by_gravity:
            self.velocity.y = 0
            return
        
        self.velocity += self.active_world.gravity
        
    def set_gravitified(self, bool:bool):
        self.is_affected_by_gravity = bool

Move method


The move method updates the entity's position based on its velocity and gravity.


        self.update_rect()
        self.check_collisions()
        self.move()
        
        if self in self.spr_group:
            self.spr_group.remove(self)
            self.spr_group.update()
            self.spr_group.add(self)
        else:
            self.spr_group.update()
            
        self.spr_group.draw(pyg.display.get_surface())
        
    def move(self):
        self.pos += self.velocity * self.active_world.dt
        
        if not self.is_affected_by_gravity:
            self.velocity.y = 0
            return
        
        self.velocity += self.active_world.gravity
        
    def set_gravitified(self, bool:bool):
        self.is_affected_by_gravity = bool

Set gravity method


The set_gravitified method enables or disables gravity for the entity.


        self.update_rect()
        self.check_collisions()
        self.move()
        
        if self in self.spr_group:
            self.spr_group.remove(self)
            self.spr_group.update()
            self.spr_group.add(self)
        else:
            self.spr_group.update()
            
        self.spr_group.draw(pyg.display.get_surface())
        
    def move(self):
        self.pos += self.velocity * self.active_world.dt
        
        if not self.is_affected_by_gravity:
            self.velocity.y = 0
            return
        
        self.velocity += self.active_world.gravity
        
    def set_gravitified(self, bool:bool):
        self.is_affected_by_gravity = bool

Data and colors

Data module


The data module contains a list of all rectangles for collision detection.

all_rects = []

Colors module


The colors module defines some basic colors.

WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

Initialization

Init module


The __init__ module imports necessary components and sets the version.

from . import entity
from . import data
from . import colors
from . import physics
from . import entity
import time


__version__ = '1.0.1'

Test script

Here is a test script to demonstrate the usage of PyGess:

import pygess
import time

# Create entities
entity1 = pygess.entity.Entity((50, 50), (10, 10), color=pygess.colors.RED)
entity2 = pygess.entity.MovingEntity((100, 100), (10, 10), (1, 1), color=pygess.colors.BLUE)

# Create a world with gravity
world = pygess.physics.World((0, 9.8), entity1, entity2)

# Set the world as active
pygess.physics.set_active_world(world)

# Main loop
while True:
    pygess.physics.update_worlds()
    time.sleep(0.016)  # Simulate 60 FPS

This script creates a world with two entities, sets the world as active, and continuously updates the world in a loop.

Powered by Swimm

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

pygess_py-3.0.26.tar.gz (8.1 kB view details)

Uploaded Source

Built Distribution

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

pygess_py-3.0.26-py3-none-any.whl (7.6 kB view details)

Uploaded Python 3

File details

Details for the file pygess_py-3.0.26.tar.gz.

File metadata

  • Download URL: pygess_py-3.0.26.tar.gz
  • Upload date:
  • Size: 8.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.7 Linux/6.5.0-1025-azure

File hashes

Hashes for pygess_py-3.0.26.tar.gz
Algorithm Hash digest
SHA256 532dcbdd231fabd9e6afef1e612cc0165916a19e82da5c0dc06fe0cbf6b24adc
MD5 d0de3e2a51bdf68ba628dd8f6fd4f763
BLAKE2b-256 663e1cbc932b537e401f7a156039e753a4eff8268be474219f4aa9c01e7474a5

See more details on using hashes here.

File details

Details for the file pygess_py-3.0.26-py3-none-any.whl.

File metadata

  • Download URL: pygess_py-3.0.26-py3-none-any.whl
  • Upload date:
  • Size: 7.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.8.3 CPython/3.12.7 Linux/6.5.0-1025-azure

File hashes

Hashes for pygess_py-3.0.26-py3-none-any.whl
Algorithm Hash digest
SHA256 6c88452f17003af3cd64bdde6bf8a78bbc94f4bd39b11350295271c29fc2807f
MD5 612f9543ddada666921bfeb7c33abe7c
BLAKE2b-256 11c4b713e9500a03762138ca5ec8daf6c96b4394e436d90a5b435522e67b5aac

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