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:
- The
GameObjects
class and its methods.
- The
World
class and its methods.
- The
entity
and MovingEntity
classes.
- Utility functions for managing worlds and entities.
- 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](https://app.swimm.io/)