Source code for visualiser.util
'''Utility functions and classes'''
import os
from enum import Enum
import pygame
SPRITE_DIR = os.path.dirname(__file__) +'/../sprites'
OBSTACLE_SPRITE_PREFIX = 'obstacles/'
_spriteCache = {}
[docs]class Actions(Enum):
'''Enumerations of the actions that the simulator can receive'''
#: No action
NONE = 1
#: Move into the lane to the left
LEFT = 2
#: Move into the lane to the right
RIGHT = 3
#: Toggle the pause state of the simulator
PAUSE = 4
[docs]def loadSprite(path, scale=1):
'''Load an image as a :class:`pygame.Surface`.
Automatically caches loaded images in the background
:param path: (:class:`str`) Path to desired image, relative to the sprites/
directory
:param scale: (:class:`float`) Multiplied against the size of the image
in order to scale as desired
'''
if path in _spriteCache:
img = _spriteCache[path].copy()
else:
src = os.path.join(SPRITE_DIR, path)
img = pygame.image.load(src).convert_alpha()
_spriteCache[path] = img
size = img.get_size()
return pygame.transform.scale(
img, tuple(map(lambda x: int(x *scale), size)))
[docs]class Vector:
'''A 2D vector, with arithmetic magic methods implemented'''
def __init__(self, x=0, y=0):
#: The x component of the vector
self.x = x
#: The y component of the vector
self.y = y
def __add__(self, val):
vec = hasattr(val, 'x')
return Vector(
self.x + (val.x if vec else val),
self.y + (val.y if vec else val))
def __sub__(self, val):
vec = hasattr(val, 'x')
return Vector(
self.x - (val.x if vec else val),
self.y - (val.y if vec else val))
def __mul__(self, val):
vec = hasattr(val, 'x')
return Vector(
self.x * (val.x if vec else val),
self.y * (val.y if vec else val))
def __div__(self, val):
vec = hasattr(val, 'x')
return Vector(
self.x / (val.x if vec else val),
self.y / (val.y if vec else val))
def __repr__(self):
return 'Vector'+ str((self.x, self.y))
[docs]class Pos(Vector):
'''2D vector that automatically updates its vehicle's rect position'''
def __init__(self, vehicle, x=0, y=0):
# pylint: disable=super-init-not-called
# Vector's init is undesireable because it would override attributes
self._x = 0
self._y = 0
self._vehicle = vehicle
self.x = x
self.y = y
@property
def x(self):
'''The x component of the vector
:getter: Return x value
:setter: Set x value, rounded to nearest :class:`int`'''
return self._x
@x.setter
def x(self, val):
if not self._vehicle.rect is None:
self._vehicle.rect.x = round(val)
self._x = val
@property
def y(self):
'''The y component of the vector
:getter: Return y value
:setter: Set y value, rounded to nearest :class:`int`'''
return self._y
@y.setter
def y(self, val):
if not self._vehicle.rect is None:
self._vehicle.rect.y = round(val)
self._y = val