summer update

This commit is contained in:
bendtherules
2014-07-07 18:18:56 -07:00
parent d1f4cc61cc
commit 0cf8b29572
58 changed files with 9282 additions and 766 deletions
+14
View File
@@ -0,0 +1,14 @@
class A(object):
"""docstring for A"""
a = 2
pass
class B(object):
"""docstring for A"""
pass
b = A.a
print("Run completed")
+443
View File
@@ -0,0 +1,443 @@
import pygame
from math_utils import distance
import math
import base
import inspect
import sprite_types
from utils import remove_from_list, rect_to_pygame_rect
class Circle(object):
map_class = "Circle"
def __init__(self, center=(None, None), radius=None, color=None, container_obj=None):
if not (len(center) == 2):
raise AttributeError("Center must be (x,y)")
x = center[0]
y = center[1]
if (radius is None):
raise AttributeError("radius must be provided")
self.radius = radius
self.color = color
if not container_obj:
if (x is None) or (y is None):
raise AttributeError("Center=(x,y) must be provided")
else:
self.container_obj = None
self.center = (x, y)
else:
self.container_obj = container_obj # Use weakrefs
@property
def center(self):
if self.container_obj:
return (self.container_obj.x, self.container_obj.y)
else:
return self._center
@center.setter
def center(self, val):
if self.container_obj:
self.container_obj.x, self.container_obj.y = val
else:
self._center = val
@classmethod
def from_container_obj(cls, container_obj, radius, color=None):
return cls(radius=radius, color=color, container_obj=container_obj)
@property
def center_x(self):
return self.center[0]
@property
def center_y(self):
return self.center[1]
@center_x.setter
def center_x(self, new_x):
self.center[0] = new_x
@center_y.setter
def center_y(self, new_y):
self.center[1] = new_y
@property
def x(self):
return self.center_x
@x.setter
def x(self, val):
self.center_x = val
@property
def y(self):
return self.center_y
@y.setter
def y(self, val):
self.center_y = val
@property
def bbox(self):
# left = self.center_x - self.radius
# top = self.center_y - self.radius
width = height = self.radius * 2
return sprite_types.Rect(self.center, (width, height))
# todo: remember about the colour. document - center is list unlike tuple
# in case of rect.
def __repr__(self):
return "{0.__class__}( center={0.center}, radius={0.radius}, color={0.color})".format(self)
def __copy__(self):
return self.__class__(self.center, self.radius, self.color)
def move(self, move_x, move_y):
return Circle((self.center_x + move_x, self.center_y + move_y), self.radius, self.color)
def move_ip(self, move_x, move_y):
self.center_x += move_x
self.center_y += move_y
return self
def inflate(self, inflate_radius):
# check if resultant radius is -ve
return Circle(self.center, self.radius + inflate_radius, self.color)
def inflate_ip(self, inflate_radius):
self.radius += inflate_radius
return self
def is_inside(self, another_circle):
''' Checks if this circle is fully inside another_circle '''
if self.radius >= another_circle.radius:
return None
else:
bigger_circle = another_circle
smaller_circle = self
return distance(bigger_circle.center, smaller_circle.center) + smaller_circle.radius < bigger_circle.radius
def is_inside_mutual(self, another_circle):
''' Checks if this circle is fully inside another_circle or the opposite.'''
radius_diff = self.radius - another_circle.radius
if radius_diff > 0:
bigger_circle = self
smaller_circle = another_circle
elif radius_diff == 0:
# None of them can be inside the other
return None
else:
smaller_circle = self
bigger_circle = another_circle
return distance(bigger_circle.center, smaller_circle.center) + smaller_circle.radius < bigger_circle.radius
def collide(self, other_obj, moved_center=(None, None), from_container_obj=False):
''' Collision handler for any type of obj'''
# todo: handle game_class=="all"
# todo: point class
if not hasattr(other_obj, "__class__"):
raise AttributeError(
"other_obj must be a class or instance")
# Handle instances
if isinstance(other_obj, Circle):
return self.collide_circle(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, sprite_types.Rect):
return self.collide_rect(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, sprite_types.Img):
return self.collide_img(other_obj, moved_center, from_container_obj)
else:
pass
# Handle classes
if inspect.isclass(other_obj):
if issubclass(other_obj, Circle):
return self.collide_list_circle(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, sprite_types.Rect):
return self.collide_list_rect(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, sprite_types.Img):
return self.collide_list_img(other_obj.list_instance, moved_center, from_container_obj)
else:
pass
# Handle fun_Game and fun_Class or their instances
if isinstance(other_obj, base.fun_Game) or (inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Game)):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten="level-class")
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Class):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten=False)
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if isinstance(other_obj, base.fun_Class):
other_obj_sprite = other_obj.sprite
to_return = self.collide(
other_obj_sprite, moved_center, from_container_obj=True)
# doesnt return list, so prev. case operations not done
return to_return
def collide_img(self, another_img, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with another_img. '''
does_collide = self.collide(
another_img.col_shape, moved_center, from_container_obj=False)
if does_collide:
if from_container_obj:
to_return = another_img.container_obj
else:
to_return = another_img
else:
to_return = False
return to_return
def collide_list_img(self, list_img, moved_center=(None, None), from_container_obj=False):
list_collided_img = []
for each_img in list_img:
if self.collide_img(each_img, moved_center, from_container_obj):
# Collide_img itself takes container_obj into account, so no
# need of post-processing
list_collided_img.append(each_img)
else: # else of the for loop
return False
return list_collided_img
def collide_circle(self, another_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with another_circle. '''
if not (len(moved_center) == 2):
raise AttributeError("moved_center must be of the form (x,y)")
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
# temporarily move self to moved_center and shift back later
self.center = moved_center
does_collide = (distance(self.center, another_circle.center) <= (
self.radius + another_circle.radius))
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_circle.container_obj
else:
to_return = another_circle
else:
to_return = False
return to_return
def collide_point(self, (point_x, point_y)):
''' Checks if (point_x, point_y) is inside this circle. '''
does_collide = (
distance(self.center, (point_x, point_y)) <= self.radius)
if does_collide:
return True
else:
return False
def collide_list_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Returns list of circles in list_circle which intersects with this circle. '''
list_collided_circle = []
for circle in list_circle:
if self.collide_circle(circle, moved_center, from_container_obj):
# Collide_circle itself takes container_obj into account, so no
# need of post-processing
list_collided_circle.append(circle)
else: # else of the for loop
return False
return list_collided_circle
def collide_list_any_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with any of the circles in circle_list. '''
for circle in list_circle:
if self.collide_circle(circle, moved_center, from_container_obj):
return True
else: # else of the for loop
return False
def collide_list_all_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with all of the circles in circle_list. '''
for circle in list_circle:
if not self.collide_circle(circle, moved_center, from_container_obj):
return False
else: # else of the for loop
return True
def collide_rect(self, another_rect, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle collides with another_rect. '''
if not (len(moved_center) == 2):
print "moved_center must be of the form (x,y)"
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
self.center = moved_center
does_collide = not ((self.center_x + self.radius) < another_rect.left or (self.center_x - self.radius) > another_rect.right or (
self.center_y + self.radius) < another_rect.top or (self.center_y - self.radius) > another_rect.bottom)
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_rect.container_obj
else:
to_return = another_rect
else:
to_return = False
return to_return
def collide_list_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns list of rect in list_rect which intersects with this circle. '''
list_collided_rect = []
for rect in list_rect:
if self.collide_rect(rect, moved_center, from_container_obj):
list_collided_rect.append(rect)
else: # else of the for loop
return False
return list_collided_rect
def collide_list_any_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns True if collides with any of the rect in the list. '''
for temp_rect in list_rect:
if self.collide_rect(self, temp_rect, moved_center, from_container_obj):
return True
else:
return False
def collide_list_all_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns True if collides with all the rect in the list. '''
for temp_rect in list_rect:
if not self.collide_rect(self, temp_rect, moved_center, from_container_obj):
return False
else:
return True
@classmethod
def get_circumcircle_from_rect(cls, another_rect):
# create a circle with same center and radius=sqrt(w^2+h^2)/2
return cls(another_rect.center, math.sqrt(another_rect.width ** 2 + another_rect.height ** 2) / 2)
@classmethod
def get_incircle_from_rect(cls, another_rect):
# radius of incircle is same as the (min of width and height)/2 (as it's not a
# square)
return cls(another_rect.center, min(another_rect.width, another_rect.height) / 2)
# union -needs to be a circle *within* which the union of the bounding box of all the circles can be fit.
# warning about all the union functions: The circles returned are not
# necessarily the most optimum union circle, but it will surely contain
# the others.
def _union(self, circle_1, circle_2):
''' ??? self.__union((new_center_x,new_center_y),new_radius) -> ([x,y],radius) which are the resultant values. '''
return self.circumcircle_from_rect(circle_1.bbox.union(circle_2.bbox))
def union(self, new_circle):
''' Returns a new circle which is the union of these two circles '''
return self._union(self, new_circle)
def union_ip(self, new_circle):
''' Turns this circle into a circle which is a union of these two circles. '''
temp_circle = self._union(self, new_circle)
self.center, self.radius = temp_circle.center, temp_circle.radius
return self
# list_circle_params : [((x1,y1),radius_1), ((x2,y2),radius_2), ...]
def _unionall(self, circle_1, seq_circle):
''' returns ([x,y],radius) for the resultant union of all circles.
sequence_circle must be a sequence of circles. '''
return self.circumcircle_from_rect(circle_1.bbox.unionall([temp_circle.bbox for temp_circle in seq_circle]))
def unionall(self, seq_circle): # seq_circle: sequence of circles
return self._unionall(self, seq_circle)
def unionall_ip(self, seq_circle):
''' Turns this circle into a circle which is a union of this circles with all circles in seq_circle'''
temp_circle = self._unionall(self, seq_circle)
self.center, self.radius = temp_circle.center, temp_circle.radius
return self
# draw functions
def blit(self, surface, (x, y)=(None, None), color=None, clip_rect=None, width=1, use_antialiasing=False):
''' Draws this Circle on surface. It must be of width and height greater than or equal to its bbox.
(x,y)->co-ordinates whether the center of the Circle should be drawn on the surface.
width argument doesnt work with antialiasing. width=0 makes it filled.
antialiasing may break in later versions as the backend pygame.gfxdraw is experimental.
color falls back first to Circle.color (if present) and then to blue color.'''
if (x, y) == (None, None):
(x, y) = self.center
# pygame.Rect does this, which is used in clear_rect
x, y = int(x), int(y)
if not color:
if self.color:
color = self.color
else:
color = pygame.Color("blue")
if clip_rect:
# Set clip region
surface.set_clip(clip_rect)
if not use_antialiasing:
pygame.draw.circle(surface, color, (x, y), self.radius, width)
else:
pygame.gfxdraw.aacircle(surface, x, y, self.radius, color)
if clip_rect:
# Remove clip region
surface.set_clip(None)
def draw(self):
tmp_dirty_sprite = {
"sprite": self,
# later shape may be used for matching insted of sprites, as sprite
# may be subclassed, changing "sprite" obj
"shape": "Circle",
# Very IMP: If using Rect for bbox, use rect_to_pygame_rect like
# below.
"bbox": rect_to_pygame_rect(self.bbox),
"config": {
"center": self.center,
"radius": self.radius,
"color": self.color
}
}
for tmp_old_sprite in self.container_obj.list_rendered_sprite:
# if any of them is eqv. to new dirty sprite, mark old one as
# still_valid
if tmp_old_sprite == tmp_dirty_sprite:
# puts "still_valid" entry in the old_dirty_sprite_dict
# quite good approach, wont match with anything again
# but "still_valid" should be removed, before next step (tick), to allow
# checks later
tmp_old_sprite["still_valid"] = True
break
else:
# i.e. if no match found, list it as dirty sprite
self.container_obj.list_dirty_sprite.append(tmp_dirty_sprite)
def get_surface(self, surface=None, flags=0):
''' Returns a new surface with dimensions of (Circle.bbox.width,Circle.bbox.width) and other properties as surface.
This Circle can be safely drawn on it.'''
if surface:
return pygame.Surface((self.bbox.width, self.bbox.height), flags, surface)
else:
return pygame.Surface((self.bbox.width, self.bbox.height), flags)
def get_surface_drawn(self, (x, y)=(None, None), color=None, width=1, use_antialiasing=False, surface=None, flags=0):
''' Returns a surface which has the tiltedRect drwan on it. '''
temp_surf = self.get_surface(surface, flags)
self.draw(temp_surf, (x, y), color, width, use_antialiasing)
return temp_surf
# end of Circle class
BIN
View File
Binary file not shown.
+422
View File
@@ -0,0 +1,422 @@
import pygame
import sprite_types
import inspect
import base
from utils import remove_from_list
class Img(object):
map_class = "Img"
def __init__(self, center=(None, None), file_name_or_obj=None, namehint="", collision_shape=None, container_obj=None):
if not (len(center) == 2):
raise TypeError("Center must be (x,y)")
x = center[0]
y = center[1]
if not container_obj:
if (x is None) or (y is None):
raise TypeError("Center=(x,y) must be provided")
else:
self.container_obj = None
self.center = (x, y)
else:
self.container_obj = container_obj # Use weakrefs
if (file_name_or_obj is None):
raise TypeError(
"file_name_or_obj must be filename, file_obj or surface")
if not isinstance(file_name_or_obj, pygame.Surface):
if namehint == "":
self.surf = pygame.image.load(file_name_or_obj)
else:
self.surf = pygame.image.load(file_name_or_obj, namehint)
else:
# From surface
# Todo: Some param for caching
self._surf = file_name_or_obj
if collision_shape:
self._col_shape = collision_shape
else:
self._col_shape = self.bbox
@property
def col_shape(self):
return self._col_shape
@col_shape.setter
def col_shape(self, value):
self._col_shape = value
def sync_col_shape(self):
self.col_shape.center = self.center
@property
def center(self):
if self.container_obj:
return (self.container_obj.x, self.container_obj.y)
else:
return self._center
@center.setter
def center(self, val):
if self.container_obj:
self.container_obj.x, self.container_obj.y = val
else:
self._center = val
self.sync_col_shape()
@classmethod
def from_container_obj(cls, container_obj, file_name_or_obj, namehint=""):
return cls(file_name_or_obj=file_name_or_obj, namehint=namehint, container_obj=container_obj)
@classmethod
def from_surface(cls, center, surf):
return cls(center=center, file_name_or_obj=surf)
@property
def surf(self):
return self._surf
@surf.setter
def surf(self, value):
if isinstance(value, pygame.Surface):
self._surf = value
else:
return TypeError("surf can only be set to anther pygame.Surface")
@property
def center_x(self):
return self.center[0]
@property
def center_y(self):
return self.center[1]
@center_x.setter
def center_x(self, new_x):
self.center[0] = new_x
@center_y.setter
def center_y(self, new_y):
self.center[1] = new_y
@property
def x(self):
return self.center_x
@x.setter
def x(self, val):
self.center_x = val
@property
def y(self):
return self.center_y
@y.setter
def y(self, val):
self.center_y = val
@property
def bbox(self):
'''Returns sprite_types.Rect copy of bounding box'''
surf_rect = self.get_rect()
return sprite_types.Rect.from_rect(surf_rect)
def get_rect(self):
'''Returns pygame.Rect copy of bounding box'''
return self.surf.get_rect(center=self.center)
def get_surface(self):
''' Returns a copy of internal surface '''
return self.surf.copy()
def __repr__(self):
return "{0.__class__}( center={0.center}, size={0.size})".format(self)
def __copy__(self):
return self.__cls__.from_surface(self.center, self.surf.copy())
def save_to_disk(self, filename):
pygame.image.save(self.get_surface(), filename)
return True
@property
def size(self):
return self.surf.get_size()
@size.setter
def size(self, value):
raise NotImplementedError(
"Setting size is ambiguous, so not implemented")
@property
def width(self):
return self.get_width()
@width.setter
def width(self, value):
raise NotImplementedError(
"Setting width is ambiguous, so not implemented")
@property
def height(self):
return self.get_height()
@height.setter
def height(self, value):
raise NotImplementedError(
"Setting height is ambiguous, so not implemented")
@property
def w(self):
return self.width
@w.setter
def w(self, value):
self.width = value
@property
def h(self):
return self.height
@h.setter
def h(self, value):
self.height = value
# Surface methods not provided, apply on self.surf
def blit(self, surface, (x, y)=(None, None), clip_rect=None):
if (x, y) == (None, None):
(x, y) = self.center
# pygame.Rect does this, which is used in clear_rect
x, y = int(x), int(y)
if clip_rect:
# Set clip region
surface.set_clip(clip_rect)
surface.blit(self.surf, self.bbox.topleft)
if clip_rect:
# Remove clip region
surface.set_clip(None)
def draw(self):
tmp_dirty_sprite = {
"sprite": self,
# later shape may be used for matching insted of sprites, as sprite
# may be subclassed, changing "sprite" obj
"shape": "Img",
"bbox": self.get_rect(),
"config": {
"center": self.center,
"file_name_or_obj": self.surf
}
}
for tmp_old_sprite in self.container_obj.list_rendered_sprite:
# if any of them is eqv. to new dirty sprite, mark old one as
# still_valid
if tmp_old_sprite == tmp_dirty_sprite:
# puts "still_valid" entry in the old_dirty_sprite_dict
# quite good approach, wont match with anything again
# but "still_valid" should be removed, before next step (tick), to allow
# checks later
tmp_old_sprite["still_valid"] = True
break
else:
# i.e. if no match found, list it as dirty sprite
self.container_obj.list_dirty_sprite.append(tmp_dirty_sprite)
# collide func
def collide(self, other_obj, moved_center=(None, None), from_container_obj=False):
''' Collision handler for any type of obj'''
if not hasattr(other_obj, "__class__"):
raise AttributeError(
"other_obj must be a class or instance")
# Handle instances
if isinstance(other_obj, sprite_types.Circle):
return self.collide_circle(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, sprite_types.Rect):
return self.collide_rect(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, Img):
# Todo: add img collision
return self.collide_img(other_obj, moved_center, from_container_obj)
else:
pass
# Handle classes
if inspect.isclass(other_obj):
if issubclass(other_obj, sprite_types.Circle):
return self.collide_list_circle(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, sprite_types.Rect):
return self.collide_list_rect(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, Img):
# Todo: add img collision
return self.collide_list_img(other_obj.list_instance, moved_center, from_container_obj)
else:
pass
# Handle fun_Game and fun_Class or their instances
if isinstance(other_obj, base.fun_Game) or (inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Game)):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten="level-class")
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Class):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten=False)
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if isinstance(other_obj, base.fun_Class):
other_obj_sprite = other_obj.sprite
to_return = self.collide(
other_obj_sprite, moved_center, from_container_obj=True)
# doesnt return list, so prev. case operations not done
return to_return
def collide_img(self, another_img, moved_center=(None, None), from_container_obj=False):
''' Checks if this img intersects with another_img. '''
does_collide = self.collide(
another_img.col_shape, moved_center, from_container_obj=False)
if does_collide:
if from_container_obj:
to_return = another_img.container_obj
else:
to_return = another_img
else:
to_return = False
return to_return
def collide_list_img(self, list_img, moved_center=(None, None), from_container_obj=False):
list_collided_img = []
for each_img in list_img:
if self.collide_img(each_img, moved_center, from_container_obj):
# Collide_img itself takes container_obj into account, so no
# need of post-processing
list_collided_img.append(each_img)
else: # else of the for loop
return False
return list_collided_img
def collide_circle(self, another_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with another_circle. '''
if not (len(moved_center) == 2):
raise AttributeError("moved_center must be of the form (x,y)")
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
# temporarily move self to moved_center and shift back later
self.center = moved_center
does_collide = another_circle.collide_img(self)
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_circle.container_obj
else:
to_return = another_circle
else:
to_return = False
return to_return
def collide_point(self, (point_x, point_y)):
''' Checks if (point_x, point_y) is inside this circle. '''
does_collide = self.col_shape.collide_point((point_x, point_y))
if does_collide:
return True
else:
return False
def collide_list_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Returns list of circles in list_circle which intersects with this circle. '''
list_collided_circle = []
for circle in list_circle:
if self.collide_circle(circle, moved_center, from_container_obj):
# Collide_circle itself takes container_obj into account, so no
# need of post-processing
list_collided_circle.append(circle)
else: # else of the for loop
return False
return list_collided_circle
def collide_list_any_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with any of the circles in circle_list. '''
for circle in list_circle:
if self.collide_circle(circle, moved_center, from_container_obj):
return True
else: # else of the for loop
return False
def collide_list_all_circle(self, list_circle, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle intersects with all of the circles in circle_list. '''
for circle in list_circle:
if not self.collide_circle(circle, moved_center, from_container_obj):
return False
else: # else of the for loop
return True
def collide_rect(self, another_rect, moved_center=(None, None), from_container_obj=False):
''' Checks if this circle collides with another_rect. '''
if not (len(moved_center) == 2):
print "moved_center must be of the form (x,y)"
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
self.center = moved_center
does_collide = another_rect.collide_img(self)
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_rect.container_obj
else:
to_return = another_rect
else:
to_return = False
return to_return
def collide_list_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns list of rect in list_rect which intersects with this circle. '''
list_collided_rect = []
for rect in list_rect:
if self.collide_rect(rect, moved_center, from_container_obj):
list_collided_rect.append(rect)
else: # else of the for loop
return False
return list_collided_rect
def collide_list_any_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns True if collides with any of the rect in the list. '''
for temp_rect in list_rect:
if self.collide_rect(self, temp_rect, moved_center, from_container_obj):
return True
else:
return False
def collide_list_all_rect(self, list_rect, moved_center=(None, None), from_container_obj=False):
''' Returns True if collides with all the rect in the list. '''
for temp_rect in list_rect:
if not self.collide_rect(self, temp_rect, moved_center, from_container_obj):
return False
else:
return True
BIN
View File
Binary file not shown.
+258
View File
File diff suppressed because one or more lines are too long
+641
View File
@@ -0,0 +1,641 @@
import pygame
from utils import remove_from_list
import base
import sprite_types
import inspect
class Rect(object):
"""Pythonic rect wrapper, using in-built Rect for speed"""
map_class = "Rect"
def __init__(self, center=(None, None), size=(None, None), color=None, container_obj=None):
if not (len(center) == 2):
raise AttributeError("Center must be (x,y)")
x = center[0]
y = center[1]
if (not (len(size) == 2)) or (None in size):
raise AttributeError(
"size must be provided and is of format (w,h)")
self.color = color
if not container_obj:
if (x is None) or (y is None):
raise AttributeError("Center=(x,y) must be provided")
else:
self.container_obj = None
self.center = (x, y)
else:
self.container_obj = container_obj # Use weakrefs
tmp_left = self.center[0] - size[0] / 2
tmp_top = self.center[1] - size[1] / 2
self._rect = pygame.Rect((tmp_left, tmp_top), size)
self.sync_self()
@classmethod
def from_rect(cls, rect):
# Doesnt use the same rect, effectively makes a copy
# As rects cant have extra props, it shouldnt impose any limitations.
return cls(rect.center, rect.size)
@classmethod
def from_top_left(cls, top_left=(None, None), size=(None, None), color=None, container_obj=None):
if not (None in top_left):
tmp_center = top_left[0] + size[0] / 2, top_left[1] + size[1] / 2
else:
tmp_center = top_left
return cls(tmp_center, size, color, container_obj)
@property
def center(self):
if self.container_obj:
return (self.container_obj.x, self.container_obj.y)
else:
return self._center
@center.setter
def center(self, val):
if self.container_obj:
self.container_obj.x, self.container_obj.y = val
else:
self._center = val
@classmethod
def from_container_obj(cls, container_obj, size, color=None):
return cls(size=size, color=color, container_obj=container_obj)
@property
def center_x(self):
return self.center[0]
@property
def center_y(self):
return self.center[1]
@center_x.setter
def center_x(self, new_x):
self.center[0] = new_x
@center_y.setter
def center_y(self, new_y):
self.center[1] = new_y
@property
def x(self):
return self.center_x
@x.setter
def x(self, val):
self.center_x = val
@property
def y(self):
return self.center_y
@y.setter
def y(self, val):
self.center_y = val
@property
def bbox(self):
return self.inner_rect.copy()
@property
def inner_rect(self):
self.sync_inner_rect()
return self._rect
def sync_inner_rect(self):
self._rect.center = self.center
def sync_self(self):
self.center = self._rect.center
# misc. methods
def __repr__(self):
return "{0.__class__}( center={0.center}, size={0.size}, color={0.color})".format(self)
def __copy__(self):
return self.__class__(**self.get_props())
def get_props(self):
''' Returns all of the constructor params, reqd for creationg a copy '''
return {
"center": self.center,
"size": self.size,
"color": self.color,
"container_obj": self.container_obj,
}
def __eq__(self, another_rect):
if self.get_props() == another_rect.get_props():
return True
else:
return False
# draw and blit func
def blit(self, surface, (x, y)=(None, None), color=None, clip_rect=None, width=1, use_antialiasing=False):
if (x, y) == (None, None):
(x, y) = self.center
# pygame.Rect does this, which is used in clear_rect
x, y = int(x), int(y)
if not color:
if self.color:
color = self.color
else:
color = pygame.Color("blue")
if clip_rect:
# Set clip region
surface.set_clip(clip_rect)
if not use_antialiasing:
pygame.draw.rect(
surface, color, self.bbox, width)
else:
# do later
pass
if clip_rect:
# Remove clip region
surface.set_clip(None)
def draw(self):
tmp_dirty_sprite = {
"sprite": self,
# later shape may be used for matching insted of sprites, as sprite
# may be subclassed, changing "sprite" obj
"shape": "Rect",
# Very IMP: If using Rect for bbox, use rect_to_pygame_rect like
# below.
"bbox": self.bbox,
"config": {
"center": self.center,
"size": self.size,
"color": self.color
}
}
for tmp_old_sprite in self.container_obj.list_rendered_sprite:
# if any of them is eqv. to new dirty sprite, mark old one as
# still_valid
if tmp_old_sprite == tmp_dirty_sprite:
# puts "still_valid" entry in the old_dirty_sprite_dict
# quite good approach, wont match with anything again
# but "still_valid" should be removed, before next step (tick), to allow
# checks later
tmp_old_sprite["still_valid"] = True
break
else:
# i.e. if no match found, list it as dirty sprite
self.container_obj.list_dirty_sprite.append(tmp_dirty_sprite)
# collide func
def collide(self, other_obj, moved_center=(None, None), from_container_obj=False):
''' Collision handler for any type of obj'''
# todo: handle game_class=="all"
# todo: point class
if not hasattr(other_obj, "__class__"):
raise AttributeError(
"other_obj must be a class or instance")
# Handle instances
if isinstance(other_obj, sprite_types.Circle):
return self.collide_circle(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, Rect):
return self.collide_rect(other_obj, moved_center, from_container_obj)
elif isinstance(other_obj, sprite_types.Img):
return self.collide_img(other_obj, moved_center, from_container_obj)
else:
pass
# Handle classes
if inspect.isclass(other_obj):
if issubclass(other_obj, sprite_types.Circle):
return self.collide_list_circle(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, Rect):
return self.collide_list_rect(other_obj.list_instance, moved_center, from_container_obj)
elif issubclass(other_obj, sprite_types.Img):
return self.collide_list_img(other_obj.list_instance, moved_center, from_container_obj)
else:
pass
# Handle fun_Game and fun_Class or their instances
if isinstance(other_obj, base.fun_Game) or (inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Game)):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten="level-class")
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if inspect.isclass(other_obj) and issubclass(other_obj, base.fun_Class):
def instance_collide(other_obj):
return self.collide(other_obj.sprite, moved_center, from_container_obj=True)
to_return = other_obj.for_all_instance(
instance_collide, flatten=False)
remove_from_list(to_return, self.container_obj)
remove_from_list(to_return, False, recursive=True)
remove_from_list(to_return, None, recursive=True)
remove_from_list(to_return, False, recursive=True)
return to_return
if isinstance(other_obj, base.fun_Class):
other_obj_sprite = other_obj.sprite
to_return = self.collide(
other_obj_sprite, moved_center, from_container_obj=True)
# doesnt return list, so prev. case operations not done
return to_return
# Rest are all synced props and methods
# w, h, width, height
# top, left, bottom, right
# topleft, bottomleft, topright, bottomright
# midtop, midleft, midbottom, midright
# size
# Getters first
@property
def width(self):
return self.bbox.width
@property
def height(self):
return self.bbox.height
@property
def w(self):
return self.bbox.w
@property
def h(self):
return self.bbox.h
@property
def top(self):
return self.bbox.top
@property
def left(self):
return self.bbox.left
@property
def bottom(self):
return self.bbox.bottom
@property
def right(self):
return self.bbox.right
@property
def topleft(self):
return self.bbox.topleft
@property
def bottomleft(self):
return self.bbox.bottomleft
@property
def topright(self):
return self.bbox.topright
@property
def bottomright(self):
return self.bbox.bottomright
@property
def midtop(self):
return self.bbox.midtop
@property
def midleft(self):
return self.bbox.midleft
@property
def midbottom(self):
return self.bbox.midbottom
@property
def midright(self):
return self.bbox.midright
@property
def size(self):
return self.bbox.size
# Then setters
@width.setter
def width(self, val):
self.inner_rect.width = val
self.sync_self()
@height.setter
def height(self, val):
self.inner_rect.height = val
self.sync_self()
@w.setter
def w(self, val):
self.inner_rect.w = val
self.sync_self()
@h.setter
def h(self, val):
self.inner_rect.h = val
self.sync_self()
@top.setter
def top(self, val):
self.inner_rect.top = val
self.sync_self()
@left.setter
def left(self, val):
self.inner_rect.left = val
self.sync_self()
@bottom.setter
def bottom(self, val):
self.inner_rect.bottom = val
self.sync_self()
@right.setter
def right(self, val):
self.inner_rect.right = val
self.sync_self()
@topleft.setter
def topleft(self, val):
self.inner_rect.topleft = val
self.sync_self()
@bottomleft.setter
def bottomleft(self, val):
self.inner_rect.bottomleft = val
self.sync_self()
@topright.setter
def topright(self, val):
self.inner_rect.topright = val
self.sync_self()
@bottomright.setter
def bottomright(self, val):
self.inner_rect.bottomright = val
self.sync_self()
@midtop.setter
def midtop(self, val):
self.inner_rect.midtop = val
self.sync_self()
@midleft.setter
def midleft(self, val):
self.inner_rect.midleft = val
self.sync_self()
@midbottom.setter
def midbottom(self, val):
self.inner_rect.midbottom = val
self.sync_self()
@midright.setter
def midright(self, val):
self.inner_rect.midright = val
self.sync_self()
@size.setter
def size(self, val):
self.inner_rect.size = val
self.sync_self()
# in-place methods
def move_ip(self, *args, **kwargs):
self.inner_rect.move_ip(*args, **kwargs)
self.sync_self()
return self
def inflate_ip(self, *args, **kwargs):
self.inner_rect.inflate_ip(*args, **kwargs)
self.sync_self()
return self
def clamp_ip(self, *args, **kwargs):
self.inner_rect.clamp_ip(*args, **kwargs)
self.sync_self()
return self
def normalize_ip(self):
self.inner_rect.normalize()
self.sync_self()
return self
def union_ip(self, *args, **kwargs):
self.inner_rect.union_ip(*args, **kwargs)
self.sync_self()
return self
def unionall_ip(self, *args, **kwargs):
self.inner_rect.unionall_ip(*args, **kwargs)
self.sync_self()
return self
# non in-place methods
def copy(self, *args, **kwargs):
return self.bbox.copy(*args, **kwargs)
def move(self, *args, **kwargs):
return self.bbox.move(*args, **kwargs)
def inflate(self, *args, **kwargs):
return self.bbox.inflate(*args, **kwargs)
def clamp(self, another_rect):
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
return self.bbox.clamp(tmp_rect)
def clip(self, another_rect):
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
return self.bbox.clip(tmp_rect)
def union(self, another_rect):
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
return self.bbox.union(tmp_rect)
def unionall(self, rect_sequence):
new_rect_seq = []
for another_rect in rect_sequence:
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
new_rect_seq.append(tmp_rect)
return self.bbox.unionall(new_rect_seq)
def fit(self, another_rect):
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
return self.bbox.fit(tmp_rect)
def contains(self, another_rect):
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
return self.bbox.contains(tmp_rect)
def collide_point(self, *args, **kwargs):
''' collide_point(x,y) -> return bool
collide_point((x,y)) -> return bool '''
return self.bbox.collidepoint(*args, **kwargs)
def collide_rect(self, another_rect, moved_center=(None, None), from_container_obj=False):
if not (len(moved_center) == 2):
print "moved_center must be of the form (x,y)"
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
self.center = moved_center
# Real collision code starts
if hasattr(another_rect, "bbox"):
tmp_rect = another_rect.bbox
else:
tmp_rect = another_rect
does_collide = self.bbox.colliderect(tmp_rect)
# Ends
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_rect.container_obj
else:
to_return = another_rect
else:
to_return = False
return to_return
def collide_list_rect(self, rect_sequence, moved_center=(None, None), from_container_obj=False):
''' Returns a list of rects, which collide; else empty list '''
return_list = []
for each_rect in rect_sequence:
if self.collide_rect(each_rect, moved_center, from_container_obj):
return_list.append(each_rect)
return return_list
def collide_list_all_rect(self, rect_sequence, moved_center=(None, None), from_container_obj=False):
''' Returns True if all rects in rect_sequence which collide,
else False '''
for each_rect in rect_sequence:
if not self.collide_rect(each_rect, moved_center, from_container_obj):
return False
else:
return True
def collide_list_any_rect(self, rect_sequence, moved_center=(None, None), from_container_obj=False):
'''Returns the first rect which collides, else False'''
for each_rect in rect_sequence:
if self.collide_rect(each_rect, moved_center, from_container_obj):
return each_rect
else:
return False
def collide_circle(self, another_circle, moved_center=(None, None), from_container_obj=False):
if not (len(moved_center) == 2):
print "moved_center must be of the form (x,y)"
_center = self.center
moved_center = list(moved_center)
if moved_center[0] is None:
moved_center[0] = _center[0]
if moved_center[1] is None:
moved_center[1] = _center[1]
self.center = moved_center
# Collision code (uses Circles collision method) starts
does_collide = another_circle.collide_rect(self)
# Ends
self.center = _center
if does_collide:
if from_container_obj:
to_return = another_circle.container_obj
else:
to_return = another_circle
else:
to_return = False
return to_return
def collide_list_circle(self, circle_sequence, moved_center=(None, None), from_container_obj=False):
''' Returns a list of Circles, which collide; else empty list '''
return_list = []
for each_circle in circle_sequence:
if self.collide_circle(each_circle, moved_center, from_container_obj):
return_list.append(each_circle)
return return_list
def collide_list_all_circle(self, circle_sequence, moved_center=(None, None), from_container_obj=False):
''' Returns True if all circles in circle_sequence which collide,
else False '''
for each_circle in circle_sequence:
if not self.collide_circle(each_circle, moved_center, from_container_obj):
return False
else:
return True
def collide_list_any_circle(self, circle_sequence, moved_center=(None, None), from_container_obj=False):
'''Returns the first circle which collides, else False'''
for each_circle in circle_sequence:
if self.collide_circle(each_circle, moved_center, from_container_obj):
return each_circle
else:
return False
def collide_img(self, another_img, moved_center=(None, None), from_container_obj=False):
''' Checks if this rect intersects with another_img. '''
does_collide = self.collide(
another_img.col_shape, moved_center, from_container_obj=False)
if does_collide:
if from_container_obj:
to_return = another_img.container_obj
else:
to_return = another_img
else:
to_return = False
return to_return
def collide_list_img(self, list_img, moved_center=(None, None), from_container_obj=False):
list_collided_img = []
for each_img in list_img:
if self.collide_img(each_img, moved_center, from_container_obj):
# Collide_img itself takes container_obj into account, so no
# need of post-processing
list_collided_img.append(each_img)
else: # else of the for loop
return False
return list_collided_img
BIN
View File
Binary file not shown.
+298
View File
@@ -0,0 +1,298 @@
import pygame
from math_utils import distance
import math
import base
from Circle import Circle
# start of Rotated_Rect class
class Rotated_Rect(pygame.Rect):
# make a metaclass which wraps a lot of functions just like move is defined below.
# functions to be wrapped - move,inflate
# Think about them - clamp,clip,union,fit,contains,collide
# the metaclass can probably also change the __str__ of the class.
# About drawing - use pygame.transform.rotate to get a rotated surface to
# be drawed.
def __init__(self, leftTop_or_center, w_h, angle, centered_coords=False, color=None):
''' Angle in degrees.
leftTop_or_center, w_h -> both are 2-element tuples or list
centered_coords -> whether the (left,top) is actually intended to be (center_x,center_y) or not.
I.e. if centered_coords==True the (left,top) co-ordinates are used as (center_x,center_y) co-ordinates of the Rotated_Rect'''
self.angle = angle
self.color = color
try:
left = leftTop_or_center[0]
top = leftTop_or_center[1]
except:
raise AttributeError(
"leftTop_or_center must be of format (left,top)")
try:
width = w_h[0]
height = w_h[1]
except:
raise AttributeError("w_h must be of format (width,height)")
if centered_coords:
left = left - width / 2
top = top - height / 2
super(Rotated_Rect, self).__init__((left, top), (width, height))
def __copy__(self):
return Rotated_Rect((self.left, self.top), (self.width, self.height), self.angle)
def __repr__(self):
return "{0.__class__.__name__}((top={0.top}, left={0.left}), (width={0.width}, height={0.height}), angle={0.angle}, color={0.color})".format(self)
@classmethod
def create_from_rect(cls, another_rect, angle):
return cls((another_rect.left, another_rect.top), (another_rect.width, another_rect.height), angle)
def get_rect(self):
return pygame.Rect((self.left, self.top), (self.width, self.height))
# most in_place versions retained from super-class
def move(self, x, y):
return self.__copy__().move_ip(x, y)
def inflate(self, x, y):
return self.__copy__().inflate_ip(x, y)
def normalize(self):
# not sure what this one does - ask others
return self.__copy__().normalize_ip()
def rotate_ip(self, some_angle):
self.angle += some_angle
def rotate(self, some_angle):
return self.__copy__().rotate_ip(some_angle)
# generalise the parameters to accept x1,y1,x2,y2,rot_angle
def rotate_point_about_center(self, x, y, theta=None):
''' x,y -> Absolute co-ords of the point to be rotated wrt to the rectangles center.
self.centerx,self.centery are internally substracted from them.
theta -> angle (in degrees) by which the point is to be rotated. Default value is self.angle.
Returns absolute positions of the points after rotation. '''
if theta is None:
theta = self.angle
return self.rotate_point(x, y, self.centerx, self.centery, theta)
@staticmethod
# to be allowed as rotate_point(class)
def rotate_point(x, y, origin_x, origin_y, theta):
''' x,y -> Absolute co-ords of the point to be rotated. origin_x,origin_y are internally substracted from them.
(origin_x,origin_y) -> Absolute co-ords of the origin wrt to which the point will be rotated
theta -> angle (in degrees) by which the point is to be rotated.
Returns absolute positions of the points after rotation. '''
import math
x_diff = x - origin_x
y_diff = y - origin_y
# -y_diff because of the inverted nature of y co-ordinate system in pygame
y_diff = -y_diff
r = math.sqrt(x_diff ** 2 + y_diff ** 2)
initial_angle = math.atan2(y_diff, x_diff)
final_angle = initial_angle + math.radians(theta)
rotated_x_diff = r * math.cos(final_angle)
rotated_y_diff = r * math.sin(final_angle)
rotated_y_diff = -rotated_y_diff # - used for same reason as above
rotated_x = rotated_x_diff + origin_x
rotated_y = rotated_y_diff + origin_y
return (rotated_x, rotated_y)
def rotate_point_polar(self, r, initial_angle, theta=None):
''' theta and initial_angle in radians.
initial_angle ->angle r makes with horizontal.
theta -> angle to be rotated by. '''
if theta is None:
theta = self.angle
final_angle = initial_angle + theta
rotated_x = r * math.cos(final_angle)
rotated_y = r * math.sin(final_angle)
return (rotated_x, rotated_y)
@property
def bottomleft_rotated(self):
temp = self.bottomleft
return self.rotate_point_about_center(temp[0], temp[1])
@property
def topleft_rotated(self):
temp = self.topleft
return self.rotate_point_about_center(temp[0], temp[1])
@property
def bottomright_rotated(self):
temp = self.bottomright
return self.rotate_point_about_center(temp[0], temp[1])
@property
def topright_rotated(self):
temp = self.topright
return self.rotate_point_about_center(temp[0], temp[1])
@property
def midleft_rotated(self):
temp = self.midleft
return self.rotate_point_about_center(temp[0], temp[1])
@property
def midright_rotated(self):
temp = self.midright
return self.rotate_point_about_center(temp[0], temp[1])
@property
def midtop_rotated(self):
temp = self.midtop
return self.rotate_point_about_center(temp[0], temp[1])
@property
def midbottom_rotated(self):
temp = self.midbottom
return self.rotate_point_about_center(temp[0], temp[1])
# related to bounding box
@property
def bbox(self):
list_x = [self.topleft_rotated[0], self.topright_rotated[0],
self.bottomleft_rotated[0], self.bottomright_rotated[0]]
list_y = [self.topleft_rotated[1], self.topright_rotated[1],
self.bottomleft_rotated[1], self.bottomright_rotated[1]]
min_x = math.floor(min(list_x))
max_x = math.ceil(max(list_x))
min_y = math.floor(min(list_y))
max_y = math.ceil(max(list_y))
return pygame.Rect((min_x, min_y), (max_x - min_x, max_y - min_y))
# corners
@property
def corners(self):
''' List of actual (rotated) corners. '''
return [self.topleft_rotated, self.topright_rotated, self.bottomright_rotated, self.bottomleft_rotated]
@property
def corners_relative(self):
return [(temp[0] - self.centerx, temp[1] - self.centery) for temp in self.corners]
# circles related to the rect
def get_circumcircle(self):
Circle.get_circumcircle_from_rect(self.bbox)
def get_incircle(self):
# get_rect used as incircle doesnt depend upon theta, same for rot and
# non-rot rect
Circle.get_incircle_from_rect(self.get_rect())
# collision events
def collide_point(self, *args):
''' collidepoint(x,y) ->
collidepoint((x,y)) -> '''
temp_len = len(args)
temp_x = None
temp_y = None
if temp_len == 2:
temp_x = args[0]
temp_y = args[1]
elif temp_len == 1:
if len(args[0]) == 2:
temp_x, temp_y = args[0]
else:
raise TypeError("Arguments are of incorrect type")
else:
raise TypeError("Arguments are of incorrect type")
if temp_x is None or temp_y is None:
raise TypeError("argument must contain two numbers")
return self.get_rect().collidepoint(self.rotate_point_about_center(temp_x, temp_y, -self.angle))
def collide_rect(self, rect):
''' Tests if it collides with rect, which should be instance of rect class. '''
# First test:whether bbox collides with rect. If not, no collision.
if not self.bbox.colliderect(rect):
return False
else:
# Todo: Else sure test: Need to do line class first. Test if any line
# of titedRect collides with any line of (instead, the whole) rect.
pass
# draw functions
def blit(self, surface, (x, y)=(None, None), color=None, clip_rect=None, width=1, use_antialiasing=False, blend=True):
''' Draws this Circle on surface. It must be of width and height greater than or equal to its bbox.
(x,y)->co-ordinates whether the center of the Rotated_Rect should be drawn on the surface.
width argument doesnt work with antialiasing. width=0 makes it filled.
antialiasing may break in later versions as the backend pygame.gfxdraw is experimental.
color falls back first to Circle.color (if present) and then to blue color.'''
if not ((x, y) == (None, None)):
sprite_to_draw = self.__copy__()
sprite_to_draw.center = (x, y)
else:
sprite_to_draw = self
# pygame.Rect does this, which is used in clear_rect
x, y = int(x), int(y)
if not color:
if self.color:
color = self.color
else:
color = pygame.Color("blue")
if clip_rect:
# Set clip region
surface.set_clip(clip_rect)
iter_corners = [(temp[0] + x, temp[1] + y)
for temp in sprite_to_draw.corners_relative]
if not use_antialiasing:
pygame.draw.polygon(surface, color, iter_corners, width)
else:
pygame.draw.aalines(surface, color, True, iter_corners, blend)
if clip_rect:
# Remove clip region
surface.set_clip(None)
def draw(self):
tmp_dirty_sprite = {
"sprite": self,
"shape": "Rotated_Rect",
"bbox": self.bbox,
"config": {
"leftTop_or_center": (self.left, self.top),
"w_h": (self.w, self.h),
"angle": self.angle,
"color": self.color
}
}
for tmp_old_sprite in self.container_obj.list_rendered_sprite:
# if any of them is eqv. to new dirty sprite, mark old one as
# still_valid
if tmp_old_sprite == tmp_dirty_sprite:
# puts "still_valid" entry in the old_dirty_sprite_dict
tmp_old_sprite["still_valid"] = True
break
else:
# i.e. if no match found, list it as dirty sprite
self.container_obj.list_dirty_sprite.append(tmp_dirty_sprite)
def get_surface(self, surface=None, flags=0):
''' Returns a new surface with dimensions of (Rotated_Rect.bbox.width,Rotated_Rect.bbox.width) and other properties as surface.
This Rotated_Rect can be safely drawn on it.'''
if surface:
return pygame.Surface((self.bbox.width, self.bbox.height), flags, surface)
else:
return pygame.Surface((self.bbox.width, self.bbox.height), flags)
def get_surface_drawn(self, (x, y)=(None, None), color=None, width=1, use_antialiasing=False, blend=True, surface=None, flags=0):
''' Returns a surface which has the Rotated_Rect drwan on it. '''
temp_surf = self.get_surface(surface, flags)
self.draw(temp_surf, (x, y), color, width, use_antialiasing, blend)
return temp_surf
def collide_Rotated_Rect(self, another_Rotated_Rect):
'''Checks whether this Rotated_Rect collides with another_titltedrect, which must be a instance of titledRect. '''
# Rotates both Rotated_Rect by -another_Rotated_Rect.angle. So, another_Rotated_Rect becomes a Rect called temp_Rect.
# Then check if the rotated version of this Rotated_Rect
# (temp_Rotated_Rect) collides with the obtained Rect.
temp_Rotated_Rect = self.rotate(-another_Rotated_Rect.angle)
temp_Rect = another_Rotated_Rect.get_rect()
return temp_Rotated_Rect.colliderect(temp_Rect)
+21
View File
@@ -0,0 +1,21 @@
class UncasedDict(dict):
def __getitem__(self, key):
for each_key in self:
if each_key.upper() == key.upper():
return super(UncasedDict, self).__getitem__(each_key)
else:
return super(UncasedDict, self).__getitem__(key)
def has_key(self, key):
return self.__contains__(key)
def get(self, key):
return self.__getitem__(key)
def __contains__(self, key):
for each_key in self:
if each_key.upper() == key.upper():
return True
else:
return False
BIN
View File
Binary file not shown.
+40
View File
@@ -0,0 +1,40 @@
# Using metaclass and decorator to allow class access during class creation time
from functools import partial
import inspect
class meta(type):
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods=inspect.getmembers(temp_cls,inspect.ismethod)
for (method_name,method_obj) in methods:
tmp_spec=inspect.getargspec(method_obj)
if "main_func" in tmp_spec.args:
what_to_do,main_func=tmp_spec.defaults
f=method_obj.im_func
f.func_code,f.func_defaults,f.func_dict,f.func_doc,f.func_name=main_func.func_code, main_func.func_defaults,main_func.func_dict,main_func.func_doc,main_func.func_name
what_to_do(method_obj)
return temp_cls
def do_it(what_to_do, main_func=None):
if main_func is None:
return partial(do_it,what_to_do)
def whatever(what_to_do=what_to_do,main_func=main_func):
pass
return whatever
def original_decorator(func):
func.im_class.a.append("so cool")
print "Calling original decorator"
class A(object):
__metaclass__=meta
a=[]
@do_it(original_decorator)
def some_method(self,a=5):
''' hello'''
print "Calling original method"
print("A.a is %s"%A.a)
print(inspect.getargspec(A().some_method))
+110
View File
@@ -0,0 +1,110 @@
from functools import partial
import inspect
def sync_func(func1, func2):
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
func1.func_code = func2.func_code
func1.func_defaults = func2.func_defaults
func1.func_dict = func2.func_dict
func1.func_doc = func2.func_doc
func1.func_name = func2.func_name
class meta(type):
# Using metaclass and decorator to allow class access during class creation time
# No method defined within the class should have "_process_meta" as arg
# Potential problems: Using closures, function.func_globals is read-only
# Doesnt get appropiate globals, maybe pass it (or the reqd global vars) as param on func defn
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods = inspect.getmembers(temp_cls, inspect.ismethod)
for (method_name, method_obj) in methods:
tmp_spec = inspect.getargspec(method_obj)
if "__process_meta" in tmp_spec.args:
what_to_do, main_func = tmp_spec.defaults[:-1]
f = method_obj.im_func
sync_func(f, main_func)
mod_func = what_to_do(temp_cls, f)
sync_func(f, mod_func)
return temp_cls
def do_it(what_to_do, main_func=None):
if main_func is None:
return partial(do_it, what_to_do)
def whatever(what_to_do=what_to_do, main_func=main_func, __process_meta=True):
pass
return whatever
def run_it(run_func):
def what_to_do(cls, func):
func(cls)
return func
return do_it(what_to_do=what_to_do,main_func=run_func)
def original_classmethod_decorator(cls, func):
# append default arg values to class variable "a"
func_defaults = inspect.getargspec(func).defaults
cls.a.append(func_defaults)
func.__doc__ = "This is a class method"
print "Calling original classmethod decorator"
return func
def original_method_decorator(cls, func):
# append default arg values to class variable "a"
func_defaults = inspect.getargspec(func).defaults
cls.a.append(func_defaults)
func.__doc__ = "This is a instance method" # Can change func properties
print "Calling original method decorator"
return func
def decorator_to_classmethod(cls, func):
cls.original_classmethod_decorator = classmethod(
original_classmethod_decorator)
return func
b=[]
class A(object):
__metaclass__ = meta
a = []
## original_classmethod_decorator = classmethod(
## original_classmethod_decorator)
## original_method_decorator = classmethod(original_method_decorator)
@classmethod
@do_it(original_classmethod_decorator)
def some_method(cls, x=1):
''' hello'''
print "Calling original class method"
@classmethod
@run_it
def register_class(cls):
b.append(cls)
##
# @classmethod
# @do_it(decorator_to_classmethod)
# def original_classmethod_decorator(cls):
# pass
# @classmethod
# @do_it(decorator_to_classmethod)
# def original_method_decorator(cls):
# pass
@do_it(original_method_decorator)
def some_method_2(self, y=2):
''' hello again'''
print "Calling original method"
# signature preserved
print(inspect.getargspec(A.some_method))
print(inspect.getargspec(A.some_method_2))
+81
View File
@@ -0,0 +1,81 @@
# Using metaclass and decorator to allow class access during class creation time
# No method defined within the class should have "_process_meta" as arg
# Potential problems: Using closures, function.func_globals is read-only
# => may cause problem
from functools import partial
import inspect
def sync_func(func1, func2):
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
func1.func_code = func2.func_code
func1.func_defaults = func2.func_defaults
func1.func_dict = func2.func_dict
func1.func_doc = func2.func_doc
func1.func_name = func2.func_name
class meta(type):
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods = inspect.getmembers(temp_cls, inspect.ismethod)
for (method_name, method_obj) in methods:
tmp_spec = inspect.getargspec(method_obj)
if "__process_meta" in tmp_spec.args:
what_to_do, main_func = tmp_spec.defaults[:-1]
# is_classmethod=False
# if method_obj.__self__==temp_cls:
# is_classmethod=True
f = method_obj.im_func
sync_func(f, main_func)
mod_func = what_to_do(temp_cls, f)
sync_func(f, mod_func)
return temp_cls
def do_it(what_to_do, main_func=None):
if main_func is None:
return partial(do_it, what_to_do)
def whatever(what_to_do=what_to_do, main_func=main_func, __process_meta=True):
pass
return whatever
def original_classmethod_decorator(cls, func):
# append default arg values to class variable "a"
func_defaults = inspect.getargspec(func).defaults
cls.a.append(func_defaults)
func.__doc__ = "This is a class method"
print "Calling original classmethod decorator"
return func
def original_method_decorator(cls, func):
# append default arg values to class variable "a"
func_defaults = inspect.getargspec(func).defaults
cls.a.append(func_defaults)
func.__doc__ = "This is a instance method"
print "Calling original method decorator"
return func
class A(object):
__metaclass__ = meta
a = []
@classmethod
@do_it(original_classmethod_decorator)
def some_method(cls, x=1):
''' hello'''
print "Calling original class method"
@do_it(original_method_decorator)
def some_method_2(self, y=2):
''' hello again'''
print "Calling original method"
print(inspect.getargspec(A.some_method))
print(inspect.getargspec(A.some_method_2))
+408 -743
View File
File diff suppressed because it is too large Load Diff
BIN
View File
Binary file not shown.
+539
View File
@@ -0,0 +1,539 @@
# only for python 2.x
# VERY IMP: Use weakrefs instead of list for fun_Game.list_class,\
# fun_Class.list_instance and fun_Class.list_update_func
from uniquelist import uniquelist # imports uniquelist
import pygame
from pygame.locals import * # imports the constants
import math
from utils import register_class, meta_accessor_class, register_event, selfie, KW_EVENTS_IB, sort_events, append_user_events, fuzzy_match_event_name, KW_EVENTS_ALL, rect_to_pygame_rect
# import utils
from functools import partial
from sprite_types import Circle, Rect
import logging
from copy import deepcopy
from math_utils import atan2_inv
logging.basicConfig(level=logging.DEBUG)
IS_TEST_MODE = True
# Mouse constants
B_LEFT_CLICK = 1
B_RIGHT_CLICK = 3
B_MIDDLE_CLICK = 2
B_SCROLLUP = 4
B_SCROLLDOWN = 5
# Direction constants
TOP = 1
LEFT = 2
BOTTOM = 3
RIGHT = 4
class fun_Game(object):
list_class = uniquelist()
list_event = [] # event_list of this step
list_event_old = [] # event_list of the previous step
# A sequence of boolean representing the state of every key
list_state_all_buttons = []
# A sequence of boolean representing the state of every key of previous
# step
list_state_all_buttons_old = []
def __init__(self, width, height, fps=30):
pygame.init()
self.fps = fps
self.clock = pygame.time.Clock()
self.width = width
self.height = height
self.test_init()
@property
def w(self):
return self.width
@w.setter
def w(self, val):
self.width = val
@property
def h(self):
return self.height
@h.setter
def h(self, val):
self.height = val
# @classmethod
# def _register_class_(cls, class_to_register):
# ''' Registers class_to_register to its list_class '''
# cls.list_class.append(class_to_register)
@classmethod
def register_class(cls, cls_to_register):
cls.list_class.append(cls_to_register)
@classmethod
def update_all_class(cls):
for tmp_cls in cls.list_class:
tmp_cls.update_instances(cls.list_event)
@classmethod
def process_event_list(cls, list_event_):
append_user_events(list_event_)
cls.list_event.sort(sort_events)
@classmethod
def _cache_event_list(cls):
''' Cache event_list in every step.
All events in fun_Game.list_event have a "type" property which are the usual constants. '''
cls.list_event_old = cls.list_event # move current list to old list
cls.list_state_all_buttons_old = cls.list_state_all_buttons
cls.list_event = pygame.event.get()
cls.process_event_list(cls.list_event)
# Returns a sequence of boolean representing the state of every key.
# Use key constant values for indexing.
cls.list_state_all_buttons = pygame.key.get_pressed()
# print cls.list_event # debug message
# control access to list_event
# with getter, do something crazy for filtering
# or a filtering function
@classmethod
def for_all_instance(cls, func_to_run, flatten):
''' Note: flatten can be "level-instance" or "level-class" or False'''
return_list = []
for tmp_cls in cls.list_class:
return_item = tmp_cls.for_all_instance(
func_to_run, flatten=flatten)
if flatten == "level-instance" or flatten == "level-class":
return_list.extend(return_item)
else:
return_list.append(return_item)
return return_list
@classmethod
def for_all_class(cls, func_to_run, flatten):
''' Note: flatten can be True or False'''
return_list = []
for tmp_class in cls.list_class:
return_item = func_to_run(tmp_class)
if flatten:
return_list.extend(return_item)
else:
return_list.append(return_item)
return return_list
@staticmethod
def collect_self_clear_rect(self):
_list_clear_rect = []
_list_rendered_sprite = []
# perf hog: search for better way to remove list items iteratively
for tmp_old_sprite in self.list_rendered_sprite:
if (not tmp_old_sprite.get("still_valid")):
# returns bbox of all list_rendered_sprite that are not still_valid, after removing them from that list
# so, list now contains only of the older sprites still_valid
tmp_clear_rect_bbox = tmp_old_sprite["bbox"]
_list_clear_rect.append(tmp_clear_rect_bbox)
else:
_list_rendered_sprite.append(tmp_old_sprite)
if ("still_valid" in tmp_old_sprite):
tmp_old_sprite.pop("still_valid")
# in next step :
# _list_rendered_sprite.append(self.list_dirty_sprite)
# self.list_dirty_sprite=[]
self.list_rendered_sprite = _list_rendered_sprite
return _list_clear_rect
@staticmethod
def collect_self_rendered_sprite(self):
return self.list_rendered_sprite
@staticmethod
def collect_self_dirty_sprite(self):
return self.list_dirty_sprite
@staticmethod
def move_dirty_to_rendered(self):
self.list_rendered_sprite.extend(self.list_dirty_sprite)
self.list_dirty_sprite = []
return None
def blit_all_class(self):
# step 1: collect all clear rects
# i.e. remove last_rendered_rects which are not still_valid and return them
# also move to_be_rendered_sprites into that list and clear dirty list
list_clear_rect = self.for_all_instance(
self.collect_self_clear_rect, flatten="level-instance")
list_rendered_sprite = self.for_all_instance(
self.collect_self_rendered_sprite, flatten="level-instance")
list_dirty_sprite = self.for_all_instance(
self.collect_self_dirty_sprite, flatten="level-instance")
# step 2: check if any clear_rect intersects with last_rendered_rects,
# return a list of dirty overlay for those last_rendered_rects.
# also if it is contained (totally within), mark clear_rect for removal
list_dirty_overlay_sprite = []
list_cancelled_clear_rect = []
for tmp_old_sprite in list_rendered_sprite:
for tmp_clear_rect in list_clear_rect:
tmp_intersect_rect = tmp_clear_rect.clip(
tmp_old_sprite["bbox"])
if tmp_intersect_rect.w > 0 and tmp_intersect_rect.h > 0:
# make blit funcs capable of taking a clip rect, will be appplied before blitting
## print("explicit blit")
copy_old_sprite = deepcopy(tmp_old_sprite)
copy_old_sprite["clip_rect"] = tmp_intersect_rect
list_dirty_overlay_sprite.append(copy_old_sprite)
if tmp_old_sprite["bbox"].contains(tmp_clear_rect):
# Cancel clear rect
list_cancelled_clear_rect.append(tmp_clear_rect)
else:
# No explicit blit
pass
# step 3: for every clear_rect not marked for removal, do the
# clear_rects.
# print "Clear_rects= ",len(list_clear_rect)-len(list_cancelled_clear_rect)
i = 0
for tmp_clear_rect in list_clear_rect:
# convert to pygame rect
if not (tmp_clear_rect in list_cancelled_clear_rect):
self.screen.fill(pygame.Color(0, 0, 0, 1), tmp_clear_rect)
i += 1
print "i=", i
# step 4: do blit for all dirty_sprite and dirty_overlay
for tmp_dirty_sprite in list_dirty_sprite:
tmp_dirty_sprite["sprite"].blit(self.screen)
# print "Dirty_overlays= ",len(list_dirty_overlay_sprite)
# print list_dirty_overlay_sprite
for tmp_overlay_sprite in list_dirty_overlay_sprite:
new_overlay_sprite = tmp_overlay_sprite[
"sprite"].__class__(**tmp_overlay_sprite["config"])
new_overlay_sprite.blit(
self.screen, clip_rect=tmp_overlay_sprite["clip_rect"])
# step 5: update display
list_display_update = [tmp_dirty_sprite["bbox"]
for tmp_dirty_sprite in list_dirty_sprite] + list_clear_rect
pygame.display.update(list_display_update)
# if not (list_dirty_sprite[0]["sprite"].bbox in list_display_update):
# print("problem")
# step 6: cleaning jobs
self.for_all_instance(self.move_dirty_to_rendered, flatten=False)
# pygame.display.flip()
def test_init(self):
''' Empty function to be overloaded for extra init on test mode. '''
pass
def test_update(self):
''' Empty function to be overloaded for extra draw on test mode. '''
pass
def run(self):
self.screen = pygame.display.set_mode([self.width, self.height])
frame_no = 0
while True:
# Todo: Always exit on event_close : make it default behavior,
# although override-able
frame_no += 1
# print frame_no
self._cache_event_list()
self.update_all_class()
self.blit_all_class()
self.test_update()
# VERY IMPORTANT: Do a spare first step so that every variable / list gets initialized well.
# Start instant creation and execution from second step.
# IMPORTANT: First do all fun_Game related stuff before dealing
# with game objects.
self.clock.tick(self.fps)
# Todo - Add crazy functions to allow other objects and instances finding
# like GM
# Todo - Easy way to take screenshot and save it as pic
# Todo: Game testing module. Lets you compare screenshots and compare values with pixelarray or surface.get_at
# Also allows accessing different config values.
# class fun_Game ends here
# print(fun_Game)
# global register_event cached,as it will also be used as classmethod
# should use register_event=_register_event at end of all class defn
meta_fun_Class = meta_accessor_class
@register_class(fun_Game)
class fun_Class(object):
# think about this: priority_order and depth
# by default, depends on "when class was defined"
# cls.priority_order = cls.depth = len(fun_Game.list_class)
__metaclass__ = meta_fun_Class
# Below lines moved to meta_fun_Class
# list_instance = uniquelist()
# list_check_func = uniquelist()
# dict_action_func -> dict of action funcs, key=event_numb like KEYDOWN
# dict_action_func = {}
sprite_defaults = {
"type": Rect,
"params": {
"size": (40, 40),
"color": None
}
}
def __init__(self, x=None, y=None):
# use sprite as a general term, img->one kind of sprite, rect, circle
self.x_start = x
self.y_start = y
self.x = x
self.y = y
self.x_prev = x
self.y_prev = y
self.vel_x, self.vel_y, self.accln_x, self.accln_y = 0, 0, 0, 0
if (self.sprite_defaults and self.sprite_defaults.get("type")):
if (x is None) or (y is None):
raise AttributeError(
"fun_Class with sprite_defaults must have x,y")
self.sprite = self.sprite_defaults.get("type").from_container_obj(
container_obj=self, **self.sprite_defaults["params"])
self.list_dirty_sprite = []
# list_rendered_sprite => sprites that are effectively on the
# screen now
self.list_rendered_sprite = []
else:
self.sprite = None
self.list_instance.append(self)
# think about self.action_create()
@property
def vel(self):
return math.sqrt(self.vel_x ** 2 + self.vel_y ** 2)
@vel.setter
def vel(self, val):
self.vel_x = val * math.cos(math.radians(self.vel_direction))
self.vel_y = val * math.sin(math.radians(self.vel_direction))
@property
def vel_direction(self):
return atan2_inv(self.vel_y, self.vel_x)
@vel_direction.setter
def vel_direction(self, val):
self.vel_x = self.vel * math.cos(math.radians(val))
self.vel_y = self.vel * math.sin(math.radians(val))
@property
def accln(self):
return math.sqrt(self.accln_x ** 2 + self.accln_y ** 2)
@accln.setter
def accln(self, val):
self.accln_x = val * math.cos(math.radians(self.accln_direction))
self.accln_y = val * math.sin(math.radians(self.accln_direction))
@property
def accln_direction(self):
return atan2_inv(self.accln_y, self.accln_x)
@accln_direction.setter
def accln_direction(self, val):
self.accln_x = self.accln * math.cos(math.radians(val))
self.accln_y = self.accln * math.sin(math.radians(val))
@classmethod
def update_instances(cls, list_event):
'''calls update_self for all instances.'''
for tmp_instance in cls.list_instance:
tmp_instance.update_self(list_event)
def update_self(self, list_event):
# print list_event
for each_ev in list_event:
# print self.dict_action_func
if each_ev.type in self.dict_action_func:
for each_action in self.dict_action_func[each_ev.type]:
# similar as self.action_step()
each_action(self, each_ev)
@classmethod
def _check_event(cls, ev_name_or_type, new_or_old):
''' ev_name_or_type => name_or_type(numb)_of_event
new_or_old => current_event_list or old_event_list '''
matched_events = []
if new_or_old == "new":
list_to_check = cls.game_class.list_event
elif new_or_old == "old":
list_to_check = cls.game_class.list_event_old
else:
raise AttributeError("new_or_old must be 'new' or 'old'.")
if type(ev_name_or_type) is int:
ev_type = ev_name_or_type
elif type(ev_name_or_type) is str:
ev_name = fuzzy_match_event_name(ev_name_or_type, "event")
ev_type = KW_EVENTS_ALL[ev_name]
for ev in list_to_check:
if ev.type == ev_type:
matched_events.append(ev)
return matched_events
@classmethod
def check_event(cls, ev_name_or_type):
return cls._check_event(ev_name_or_type, "new")
@classmethod
def check_event_old(cls, ev_name_or_type):
return cls._check_event(ev_name_or_type, "old")
@classmethod
def register_event(cls, event_name=None, func_to_register=None):
global register_event
register_event(event_name, func_to_register, cls)
@classmethod
def for_all_instance(cls, func_to_run, flatten):
return_list = []
for tmp_instance in cls.list_instance:
return_item = func_to_run(tmp_instance)
if flatten == "level-instance":
return_list.extend(return_item)
else:
return_list.append(return_item)
return return_list
def collide(self, *args, **kwargs):
return self.sprite.collide(*args, **kwargs)
# always use selfie,not selfie_depreceated most compatible
# make this classmethod,selfie-ridden register_events as test
# @register_event()
def action_end_step_default(self, ev):
if not(self.x is None) and not(self.y is None):
# Set x_prev, y_prev
self.x_prev = self.x
self.y_prev = self.y
# Accelerate velocity
self.vel_x += self.accln_x
self.vel_y += self.accln_y
# Move x and y
self.x += self.vel_x
self.y += self.vel_y
def action_begin_step(self, ev):
# print "Calling begin_step"
pass
def action_JOY_BUTTON_UP(self, ev):
print "calling JOY_BUTTON_UP"
def action_key_down(self, ev):
print "Calling key_down"
def action_end_step(self, ev):
# print "Calling end step"
pass
def action_draw_default(self, ev):
# print "Drawing"
self.sprite.draw()
# end of fun_Class
# Other classes
# functions outside all classes
# list_to_get is attached to a constant list here
def get_event_list(event_types=None, further_check_variable_name=None, further_check_value=None, list_to_get=None):
''' Get the required events from the event_list.
get_event_list([event_types],[further_check_variable_name],further_check_value=None,list_to_get=fun_Game.list_event):
event_types (optional): event_name|list[event_name]
get_event_list() -> returns whole event_list(to be precise, list_to_get)
get_event_list(events) -> returns event_list(to be precise, list_to_get) filtered to contain only "events"
get_event_list([events],further_check_variable_name="var_name",further_check_value=value) ->
returns sub-list containing those elements of get_event_list([events]) for which var_name=value
Potential candidates for list_to_get ->
fun_Game.list_event, fun_Game.list_event_old, fun_Game.list_state_all_buttons, fun_Game.list_state_all_buttons_old'''
if list_to_get is None:
list_to_get = fun_Game.list_event_old
if further_check_variable_name:
further_check_enabled = True
else:
further_check_enabled = False
if event_types:
if not hasattr(event_types, "__iter__"):
# if not iterable, make a list out of it
event_types = [event_types]
def func_filter():
list_return = []
if not event_types:
return list_to_get
# all events in fun_Game.list_event have a "type" property
for temp_1 in list_to_get:
for temp_2 in event_types:
if temp_1.type == temp_2:
list_return.append(temp_1)
return list_return
# returns part of temp_list which passes further_check
def further_check_filter(temp_list):
list_return = []
if further_check_enabled:
for temp in temp_list:
# may raise error if further_check_variable_name is not present
# for all members of the list
if getattr(temp, further_check_variable_name) == further_check_value:
list_return.append(temp)
else:
list_return = temp_list
return list_return
# returns elements common in fun_Game.list_events and events which are
# accepted after further_check
return further_check_filter(func_filter())
# end of get_event_list()
# Todo: see below
# Collision helper event_collision funcs (Done, for circle)
# Allow collision with "all"
# More collision func like GM
# More extended draw funcs
# Make img sprite
# Use rects retuned from blit to display.update
#
# 1. (Think) Allow rect-like and circle-like constructs wherever rect and circle are expected.
# 2. Do all sort of type-checking.
# 3. Use sprites and groups in pygame as containers
# Imp: Allow debugging with event handlers and others with @debug
# Design tips I will use later
# use weakrefs as much as possible
# IMP: always derive classes from object. Else, in python 2.x, they become old-style class which sucks.
# use tuples instead of lists wherver possible because they are usually faster to create
# learn about generators
# named tuples, arrays are better. use more of them. named tuples can be accessed.
# refactor code into proper modules as-well-as use better named functions and variables
# use enumerate() for getting the index and value of elements while looping through lists. This mistake done atleast 1 time.
# use xrange instead of range. It produces one at a time. range is replaced by xrange in python 3.x
# use reversed() for backward loops, sorted() for sorted order.
# instead of zip(), use izip().
# use key instead of comparator
# use iter(iter_type,sentinel_value) instead of for loops
# partial() makes a function with more number of argument to less number of argument
# use for/else instead of exit based on flags
# look at dict.iteritems() and dict.setdefaults
# learn defaultdicts and collections module
BIN
View File
Binary file not shown.
+1005
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
import inspect
def original_decorator(func):
# need to access class here
# for eg, to append the func itself to class variable "a", to register itself
# or say, append their default arg values to class variable "a"
return func
class A(object):
a=[]
@classmethod
@original_decorator
def some_method(self,a=5):
''' hello'''
print "Calling some_method"
@original_decorator
def some_method_2(self):
''' hello again'''
print "Calling some_method_2"
##print("A.a is %s"%A.a)
##print(inspect.getargspec(A.some_method))
+38
View File
@@ -0,0 +1,38 @@
from functools import partial
import inspect
class meta(type):
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods=inspect.getmembers(temp_cls,inspect.ismethod)
print methods
print "inspecting.."
for tmp in methods:
method=tmp[1]
tmp_spec=inspect.getargspec(method)
if "main_func" in tmp_spec.args:
main_func=tmp_spec.defaults[1]
tmp_spec.defaults[0]()
main_func(50)
f=method.im_func
print f
f.func_code,f.func_defaults,f.func_dict,f.func_doc,f.func_name=main_func.func_code, main_func.func_defaults,main_func.func_dict,main_func.func_doc,main_func.func_name
return temp_cls
def doit(what_to_do, main_func):
def asd(what_to_do=what_to_do,main_func=main_func):
pass
return asd
def pr5():
print 5
do_pr5=partial(doit,pr5)
class A(object):
__metaclass__=meta
a=[]
@do_pr5
def abc(self,a=5):
''' hello'''
print a+1
+27
View File
@@ -0,0 +1,27 @@
import pygame
w,h=800,200
fps=60
pygame.init()
screen = pygame.display.set_mode([w, h])
color=pygame.Color("white")
clock=pygame.time.Clock()
radius=40
x,y=800,100
def get_bbox(x,y):
left = x - radius
top = y - radius
width = radius * 2
height = radius * 2
return pygame.Rect((left, top), (width, height))
while True:
pygame.event.pump()
old_x=x
x-=5
screen.fill(pygame.Color("black"),get_bbox(old_x,y))
pygame.draw.circle(screen, color, (x, y), radius, 1)
pygame.display.update([get_bbox(x,y),get_bbox(old_x,y)])
## pygame.display.flip()
clock.tick(fps)
## time_passed=clock.get_time()
## print(time_passed)
+517
View File
@@ -0,0 +1,517 @@
import pygame
import pygame.locals as pygame_consts
from UncasedDict import UncasedDict
DICT_EVENT_IB = {
"QUIT": pygame_consts.QUIT,
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
"KEY_DOWN": pygame_consts.KEYDOWN,
"KEY_UP": pygame_consts.KEYUP,
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
# "USER_EVENT": pygame_consts.USEREVENT,
# think of begin_step, step and end_step
}
DICT_KEYS = {
r"BACKSPACE": pygame_consts.K_BACKSPACE,
r"TAB": pygame_consts.K_TAB,
r"CLEAR": pygame_consts.K_CLEAR,
r"RETURN": pygame_consts.K_RETURN,
r"PAUSE": pygame_consts.K_PAUSE,
r"ESCAPE": pygame_consts.K_ESCAPE,
r"SPACE": pygame_consts.K_SPACE,
r"EXCLAIM": pygame_consts.K_EXCLAIM,
r"QUOTEDBL": pygame_consts.K_QUOTEDBL,
r"HASH": pygame_consts.K_HASH,
r"DOLLAR": pygame_consts.K_DOLLAR,
r"AMPERSAND": pygame_consts.K_AMPERSAND,
r"QUOTE": pygame_consts.K_QUOTE,
r"LEFTPAREN": pygame_consts.K_LEFTPAREN,
r"RIGHTPAREN": pygame_consts.K_RIGHTPAREN,
r"ASTERISK": pygame_consts.K_ASTERISK,
r"PLUS": pygame_consts.K_PLUS,
r"COMMA": pygame_consts.K_COMMA,
r"MINUS": pygame_consts.K_MINUS,
r"PERIOD": pygame_consts.K_PERIOD,
r"SLASH": pygame_consts.K_SLASH,
r"0": pygame_consts.K_0,
r"1": pygame_consts.K_1,
r"2": pygame_consts.K_2,
r"3": pygame_consts.K_3,
r"4": pygame_consts.K_4,
r"5": pygame_consts.K_5,
r"6": pygame_consts.K_6,
r"7": pygame_consts.K_7,
r"8": pygame_consts.K_8,
r"9": pygame_consts.K_9,
r"COLON": pygame_consts.K_COLON,
r"SEMICOLON": pygame_consts.K_SEMICOLON,
r"LESS": pygame_consts.K_LESS,
r"EQUALS": pygame_consts.K_EQUALS,
r"GREATER": pygame_consts.K_GREATER,
r"QUESTION": pygame_consts.K_QUESTION,
r"AT": pygame_consts.K_AT,
r"LEFTBRACKET": pygame_consts.K_LEFTBRACKET,
r"BACKSLASH": pygame_consts.K_BACKSLASH,
r"RIGHTBRACKET": pygame_consts.K_RIGHTBRACKET,
r"CARET": pygame_consts.K_CARET,
r"UNDERSCORE": pygame_consts.K_UNDERSCORE,
r"BACKQUOTE": pygame_consts.K_BACKQUOTE,
r"a": pygame_consts.K_a,
r"b": pygame_consts.K_b,
r"c": pygame_consts.K_c,
r"d": pygame_consts.K_d,
r"e": pygame_consts.K_e,
r"f": pygame_consts.K_f,
r"g": pygame_consts.K_g,
r"h": pygame_consts.K_h,
r"i": pygame_consts.K_i,
r"j": pygame_consts.K_j,
r"k": pygame_consts.K_k,
r"l": pygame_consts.K_l,
r"m": pygame_consts.K_m,
r"n": pygame_consts.K_n,
r"o": pygame_consts.K_o,
r"p": pygame_consts.K_p,
r"q": pygame_consts.K_q,
r"r": pygame_consts.K_r,
r"s": pygame_consts.K_s,
r"t": pygame_consts.K_t,
r"u": pygame_consts.K_u,
r"v": pygame_consts.K_v,
r"w": pygame_consts.K_w,
r"x": pygame_consts.K_x,
r"y": pygame_consts.K_y,
r"z": pygame_consts.K_z,
r"DELETE": pygame_consts.K_DELETE,
r"KP0": pygame_consts.K_KP0,
r"KP1": pygame_consts.K_KP1,
r"KP2": pygame_consts.K_KP2,
r"KP3": pygame_consts.K_KP3,
r"KP4": pygame_consts.K_KP4,
r"KP5": pygame_consts.K_KP5,
r"KP6": pygame_consts.K_KP6,
r"KP7": pygame_consts.K_KP7,
r"KP8": pygame_consts.K_KP8,
r"KP9": pygame_consts.K_KP9,
r"KP_PERIOD": pygame_consts.K_KP_PERIOD,
r"KP_DIVIDE": pygame_consts.K_KP_DIVIDE,
r"KP_MULTIPLY": pygame_consts.K_KP_MULTIPLY,
r"KP_MINUS": pygame_consts.K_KP_MINUS,
r"KP_PLUS": pygame_consts.K_KP_PLUS,
r"KP_ENTER": pygame_consts.K_KP_ENTER,
r"KP_EQUALS": pygame_consts.K_KP_EQUALS,
r"UP": pygame_consts.K_UP,
r"DOWN": pygame_consts.K_DOWN,
r"RIGHT": pygame_consts.K_RIGHT,
r"LEFT": pygame_consts.K_LEFT,
r"INSERT": pygame_consts.K_INSERT,
r"HOME": pygame_consts.K_HOME,
r"END": pygame_consts.K_END,
r"PAGEUP": pygame_consts.K_PAGEUP,
r"PAGEDOWN": pygame_consts.K_PAGEDOWN,
r"F1": pygame_consts.K_F1,
r"F2": pygame_consts.K_F2,
r"F3": pygame_consts.K_F3,
r"F4": pygame_consts.K_F4,
r"F5": pygame_consts.K_F5,
r"F6": pygame_consts.K_F6,
r"F7": pygame_consts.K_F7,
r"F8": pygame_consts.K_F8,
r"F9": pygame_consts.K_F9,
r"F10": pygame_consts.K_F10,
r"F11": pygame_consts.K_F11,
r"F12": pygame_consts.K_F12,
r"F13": pygame_consts.K_F13,
r"F14": pygame_consts.K_F14,
r"F15": pygame_consts.K_F15,
r"NUMLOCK": pygame_consts.K_NUMLOCK,
r"CAPSLOCK": pygame_consts.K_CAPSLOCK,
r"SCROLLOCK": pygame_consts.K_SCROLLOCK,
r"RSHIFT": pygame_consts.K_RSHIFT,
r"LSHIFT": pygame_consts.K_LSHIFT,
r"RCTRL": pygame_consts.K_RCTRL,
r"LCTRL": pygame_consts.K_LCTRL,
r"RALT": pygame_consts.K_RALT,
r"LALT": pygame_consts.K_LALT,
r"RMETA": pygame_consts.K_RMETA,
r"LMETA": pygame_consts.K_LMETA,
r"LSUPER": pygame_consts.K_LSUPER,
r"RSUPER": pygame_consts.K_RSUPER,
r"MODE": pygame_consts.K_MODE,
r"HELP": pygame_consts.K_HELP,
r"PRINT": pygame_consts.K_PRINT,
r"SYSREQ": pygame_consts.K_SYSREQ,
r"BREAK": pygame_consts.K_BREAK,
r"MENU": pygame_consts.K_MENU,
r"POWER": pygame_consts.K_POWER,
r"EURO": pygame_consts.K_EURO,
}
LIST_EVENTS_GAME_PRE = ["BEGIN_STEP"]
# Custom events to be registered here
LIST_EVENTS_GAME_POST = ["STEP", "DRAW", "END_STEP"]
LIST_EVENTS_CUSTOM = [
"KEY_PRESS", "MOUSE_PRESS", "Instance_Create", "Instance_Destroy"]
dict_event_name = UncasedDict()
list_event = []
list_event_old = []
list_state_key = []
list_state_key_old = []
list_state_mouse, list_state_mouse_old = [], []
def register_event_name(ev_name, ev_id=None):
if (ev_name in dict_event_name):
raise TypeError(
"ev_name={0} is already registered".format(ev_name))
if (ev_id is None):
ev_id = max(
pygame_consts.USEREVENT + 1, max(dict_event_name.values()) + 1)
dict_event_name[ev_name] = ev_id
def add_each_event(ev):
if not (ev.ev_name in dict_event_name):
return TypeError("ev_name not registered")
else:
# make list_event_accessible
list_event.append(ev)
def add_returned_events(ev_or_ev_list):
# fix below cond
if hasattr(ev_or_ev_list, "__iter__"):
# list of events
for each_ev in ev_or_ev_list:
add_each_event(each_ev)
else:
# single event
add_each_event(ev_or_ev_list)
def get_event_name(ev_id):
for ev_name in dict_event_name:
if dict_event_name[ev_name] == ev_id:
return ev_name
def get_event_id(ev_name):
return dict_event_name.get(ev_name)
def get_key_name(key_id):
for key_name in DICT_KEYS:
if DICT_KEYS[key_name] == key_id:
return key_name
def get_key_id(key_name):
return DICT_KEYS.get(key_name)
def get_mouse_btn_name(btn_id):
# btn_id can be 0, 1 or 2
if btn_id == 0:
return "left"
elif btn_id == 1:
return "middle"
elif btn_id == 2:
return "right"
else:
raise ValueError("btn_id must be 0, 1 or 2")
# No sort_events, event_generators should be pushed in correct order
def fuzzy_match_event_name(string_, event_or_action):
str_upper = string_.upper()
if not (str_upper in dict_event_name):
event_or_action = event_or_action.lower()
if event_or_action == "event" or event_or_action == "action":
# STR_STARTER becomes event_ or action_
STR_STARTER = event_or_action.upper() + "_"
else:
raise TypeError(
"event_or_action arg must be 'event' or 'action'.")
str_normalized = str_upper[
str_upper.find(STR_STARTER) + len(STR_STARTER):]
for tmp_event_name in dict_event_name:
# tmp event is the event_name, keys of KW_EVENTS
tmp_event_name_normalized = tmp_event_name.upper().replace("_", "")
if str_normalized.startswith(tmp_event_name) or str_normalized.startswith(tmp_event_name_normalized):
return tmp_event_name
else:
return str_upper
def add_ev_name_GAME_PRE():
for ev_name in LIST_EVENTS_GAME_PRE:
register_event_name(ev_name)
def add_ev_name_IB():
for ev_name in DICT_EVENT_IB:
register_event_name(ev_name, DICT_EVENT_IB[ev_name])
def add_ev_name_GAME_POST():
for ev_name in LIST_EVENTS_GAME_POST:
register_event_name(ev_name)
def add_ev_name_CUSTOM():
for ev_name in LIST_EVENTS_CUSTOM:
register_event_name(ev_name)
# event_generators
def gen_event_GAME_PRE():
return [Event(ev_name) for ev_name in LIST_EVENTS_GAME_PRE]
def gen_event_IB():
# move current list to old list
list_event_IB = pygame.event.get()
# Above list contains pygame_events, cant be modified
# But need to replace type with ev_name
new_list_ev = []
for each_ev in list_event_IB:
ev_name = get_event_name(each_ev.type)
tmp_ev = Event(ev_name, each_ev.dict)
new_list_ev.append(tmp_ev)
return new_list_ev
def gen_event_GAME_POST():
return [Event(ev_name) for ev_name in LIST_EVENTS_GAME_POST]
def gen_event_KEY_PRESS():
global list_state_key, list_state_key_old
list_state_key_old = list_state_key
list_state_key = pygame.key.get_pressed()
list_key_press_event = []
for tmp_key_id, bool_pressed in enumerate(list_state_key):
if bool_pressed:
tmp_key_name = get_key_name(tmp_key_id)
list_key_press_event.append(
Event("KEY_PRESS", {"key_name": tmp_key_name.lower(), "key_id": tmp_key_id}))
return list_key_press_event
def gen_event_MOUSE_PRESS():
global list_state_mouse, list_state_mouse_old
list_state_mouse_old = list_state_mouse
list_state_mouse = pygame.mouse.get_pressed()
list_mouse_press_event = []
for tmp_mouse_btn_id, bool_pressed in enumerate(list_state_mouse):
if bool_pressed:
tmp_btn_name = get_mouse_btn_name(tmp_mouse_btn_id)
list_mouse_press_event.append(
Event("MOUSE_PRESS", {"btn_name": tmp_btn_name.lower(), "btn_id": tmp_mouse_btn_id}))
return list_mouse_press_event
# pygame.mouse.get_pressed
# add ev_names
# Ordered list of name adders
LIST_ADDER_EV_NAME = [
add_ev_name_IB, add_ev_name_GAME_PRE, add_ev_name_GAME_POST, add_ev_name_CUSTOM]
for each_adder_func in LIST_ADDER_EV_NAME:
each_adder_func()
# add event generators
# Ordered list of generators
list_ordered_custom_generator = [gen_event_KEY_PRESS, gen_event_MOUSE_PRESS]
list_ordered_generators = [
gen_event_GAME_PRE, gen_event_IB, list_ordered_custom_generator, gen_event_GAME_POST]
def register_custom_event_generator(ev_func):
''' ev_func will be run in each step before step event and after begin step event and should return a / a list of dicts
each with ev_name (to be registered beforehand) and other props'''
global list_ordered_custom_generator
list_ordered_custom_generator.append(ev_func)
def get_event_generators():
return_list = []
for gen_or_list in list_ordered_generators:
if hasattr(gen_or_list, "__iter__"):
return_list.extend(gen_or_list)
else:
return_list.append(gen_or_list)
return return_list
# Todo: Howto programatically register at the right position of generator list
# Event collector
def collect_events():
# First, clear the old ev list
global list_event, list_event_old
list_event_old = list_event
list_event = []
for each_gen in get_event_generators():
add_returned_events(each_gen())
# Event dispatcher
# To be used by appr. classes
def dispatch_events_class(cls):
# cls.list_class must be available
for each_class in cls.list_class:
each_class.dispatch_events_instance(list_event)
def dispatch_events_instance(cls, list_event):
for each_instance in cls.list_instance:
each_instance.dispatch_events_self(list_event)
def dispatch_events_self(self, list_event):
for each_ev in list_event:
if each_ev.ev_name.upper() in self.dict_action_func:
self.dispatch_events_local()
for each_action in self.dict_action_func[each_ev.ev_name]:
# similar as self.action_step(each_ev)
each_action(self, each_ev)
def dispatch_events_local(self):
for each_ev in self.list_event_local:
if each_ev.ev_name.upper() in self.dict_action_func:
for each_action in self.dict_action_func[each_ev.ev_name]:
# similar as self.action_step(each_ev)
each_action(self, each_ev)
self.clear_event_local()
def push_event_local(self, ev_or_ev_list):
if hasattr(ev_or_ev_list, "__iter__"):
# list of events
for each_ev in ev_or_ev_list:
self._push_event_local_single(each_ev)
else:
# single event
self._push_event_local_single(ev_or_ev_list)
def clear_event_local(self):
self.list_event_local = []
def _push_event_local_single(self, ev):
self.list_event_local.append(ev)
class Event(object):
def __init__(self, ev_name, dict_=None):
super(Event, self).__init__()
self.ev_name = ev_name
self.dict = dict_
def _check_event(ev_name, new_or_old):
''' ev_name_or_type => name_or_type(numb)_of_event
new_or_old => current_event_list or old_event_list '''
global list_event, list_event_old
matched_events = []
if new_or_old == "new":
list_to_check = list_event
elif new_or_old == "old":
list_to_check = list_event_old
else:
raise AttributeError("new_or_old must be 'new' or 'old'.")
ev_name = fuzzy_match_event_name(ev_name, "event")
for ev in list_to_check:
if ev.ev_name == ev_name:
matched_events.append(ev)
return matched_events
def check_event(ev_name):
return _check_event(ev_name, "new")
def check_event_old(ev_name):
return _check_event(ev_name, "old")
def _get_key_press(key_name=None, new_or_old=None):
''' Returns list of dict with key_name and key_id, if key_name matches.
If key_name is None, all key preeses are allowed.'''
global list_state_key, list_state_key_old
if new_or_old == "new":
list_to_check = list_state_key
elif new_or_old == "old":
list_to_check = list_state_key_old
else:
raise TypeError("new_or_old must be 'new' or 'old', CANT be None")
list_key_press_event = []
for tmp_key_id, bool_pressed in enumerate(list_to_check):
if bool_pressed:
tmp_key_name = get_key_name(tmp_key_id)
if (key_name is None) or (tmp_key_name.lower() == key_name.lower()):
# Todo: Cant match event_name directly, need a fuzzy key name
# search func
list_key_press_event.append(
{"key_name": tmp_key_name.lower(), "key_id": tmp_key_id})
return list_key_press_event
def _get_mouse_press(btn_name=None, new_or_old=None):
global list_state_mouse, list_state_mouse_old
if new_or_old == "new":
list_to_check = list_state_mouse
elif new_or_old == "old":
list_to_check = list_state_mouse_old
else:
raise TypeError("new_or_old must be 'new' or 'old', CANT be None")
list_mouse_press_event = []
for tmp_mouse_btn_id, bool_pressed in enumerate(list_to_check):
if bool_pressed:
tmp_btn_name = get_mouse_btn_name(tmp_mouse_btn_id)
if (btn_name is None) or (btn_name.lower() == tmp_btn_name.lower()):
list_mouse_press_event.append(
{"btn_name": tmp_btn_name.lower(), "btn_id": tmp_mouse_btn_id})
return list_mouse_press_event
def get_key_press(key_name=None):
return _get_key_press(key_name, "new")
def get_key_press_old(key_name=None):
return _get_key_press(key_name, "old")
def get_mouse_press(btn_name=None):
return _get_mouse_press(btn_name, "new")
def get_mouse_press_old(btn_name=None):
return _get_mouse_press(btn_name, "old")
BIN
View File
Binary file not shown.
+43
View File
@@ -0,0 +1,43 @@
import inspect
def tryit(func):
print func
try:
print func.im_class
except:
print("Failed")
try:
print func.im_func
except:
print("Failed")
try:
print func.im_self
except:
print("Failed")
try:
func.asd=8
except:
print("Failed again")
return func
class meta_fun_Class(type):
def __new__(cls, name, base, clsdict):
temp_class = type.__new__(cls, name, base, clsdict)
temp_class.__class__=cls
l=inspect.getmembers(temp_class,inspect.ismethod)
for l1 in l:
l1[1].asd=4
return temp_class
class A(object):
__metaclass__=meta_fun_Class
def b(cls):
pass
@classmethod
def c(cls):
pass
@staticmethod
def d(cls):
pass
+20 -16
View File
@@ -1,25 +1,29 @@
import pyFun import pyFun
class pong(pyFun.fun_Game): class pong(pyFun.fun_Game):
class bat(pyFun.fun_Class): class bat(pyFun.fun_Class):
def __init__(self,up_key,down_key,*args,**kwargs):
super(bat,self).__init__(*args,**kwargs) def __init__(self, up_key, down_key, *args, **kwargs):
self.up_key=up_key super(bat, self).__init__(*args, **kwargs)
self.down_key=down_key self.up_key = up_key
self.img=pyFun.shapes.rect(w=24,h=96) self.down_key = down_key
self.img = pyFun.shapes.rect(w=24, h=96)
def action_create(self): def action_create(self):
self.move_step=3 self.move_step = 3
def action_key_press(self,key): def action_key_press(self, key):
if key==self.up_key: if key == self.up_key:
self.y-=self.move_step self.y -= self.move_step
if key==self.down_key: if key == self.down_key:
self.y+=self.move_step self.y += self.move_step
def action_touch_room_boundary(self): def action_touch_room_boundary(self):
self.y=self.y_prev self.y = self.y_prev
game=pong(width=760,height=640,fps=60) game = pong(width=760, height=640, fps=60)
game.bat(up_key=k_up,down_key=k_down,x=80,y=game.h/2) game.bat(up_key=k_up, down_key=k_down, x=80, y=game.h / 2)
game.bat(up_key=k_w,down_key=k_s,x=game.w-80,y=game.h/2) game.bat(up_key=k_w, down_key=k_s, x=game.w - 80, y=game.h / 2)
game.run() game.run()
+103
View File
@@ -0,0 +1,103 @@
import importlib
import sys
import os
import inspect
import room_sprite_panel
import json
dict_shape_panel = room_sprite_panel.CanvasPanel.dict_sprite_panel
def create_fake_cls(cls_name):
class fake_cls(object):
pass
# cls_name is unicode, so str() it
fake_cls.__name__ = str(cls_name)
return fake_cls
class obj_ext(object):
pass
def append_filepath(filepath):
if filepath:
sys.path.append(filepath)
def import_module(filename, filepath=None):
append_filepath(filepath)
module_ = importlib.import_module(filename)
return module_
def import_file(filename, filepath=None):
if not (filepath is None):
full_filename = os.path.join(filepath, filename)
print full_filename
else:
full_filename = filename
file_ = open(full_filename, "r")
return file_
def filter_class_with_panel(module_):
list_class = inspect.getmembers(module_, inspect.isclass)
list_filtered_cls = []
for (cls_name, cls_obj) in list_class:
if hasattr(cls_obj, "sprite_defaults"):
tmp_sprite = cls_obj.sprite_defaults["type"]
if tmp_sprite.map_class in dict_shape_panel.keys():
cls_obj.sprite_defaults["panel"] = dict_shape_panel[
tmp_sprite.map_class]
list_filtered_cls.append(cls_obj)
return list_filtered_cls
def load_module(filename_or_module, filepath=None):
if isinstance(filename_or_module, str) or isinstance(filename_or_module, unicode):
module_ = import_module(filename_or_module, filepath)
elif inspect.ismodule(filename_or_module):
if filepath is None:
module_ = filename_or_module
else:
raise TypeError("filepath must be None if first param is module")
return filter_class_with_panel(module_)
def load_json(filename_or_file, filepath=None):
if isinstance(filename_or_file, str) or isinstance(filename_or_file, unicode):
file_ = import_file(filename_or_file, filepath)
elif isinstance(filename_or_file, file):
file_ = filename_or_file
data_json = json.load(file_)
if isinstance(file_, file):
file_.close()
list_class_data = data_json["class_data"]
list_inst_data = data_json["instance_data"]
list_loaded_cls = []
for each_cls in list_class_data:
tmp_cls = create_fake_cls(each_cls["game_class"])
tmp_type = obj_ext()
tmp_type.map_class = each_cls["game_shape_class"]
tmp_cls.sprite_defaults = {
# "panel": each_cls["pygame_class"],
"params": each_cls["params"],
"type": tmp_type
}
# add panel to sprite_defaults
if each_cls["game_shape_class"] in dict_shape_panel.keys():
tmp_cls.sprite_defaults["panel"] = dict_shape_panel[
each_cls["game_shape_class"]]
list_loaded_cls.append(tmp_cls)
return (list_loaded_cls, list_inst_data)
BIN
View File
Binary file not shown.
+148
View File
@@ -0,0 +1,148 @@
{
"instance_data": [
{
"game_class": "wall",
"config": {
"color": null,
"center": [
121,
183
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "ball",
"config": {
"color": null,
"center": [
175,
76
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "wall",
"config": {
"color": null,
"center": [
62,
182
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "wall",
"config": {
"color": null,
"center": [
54,
137
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "wall",
"config": {
"color": null,
"center": [
120,
144
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "ball",
"config": {
"color": null,
"center": [
104,
88
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "ball",
"config": {
"color": null,
"center": [
72,
224
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "ball",
"config": {
"color": null,
"center": [
177,
169
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}
],
"class_data": [
{
"game_class": "wall",
"params": {
"color": null,
"size": [
60,
40
]
},
"game_shape_class": "Rect"
},
{
"game_class": "ball",
"params": {
"color": null,
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}
]
}
+136
View File
@@ -0,0 +1,136 @@
{
"instance_data": [{
"game_class": "wall",
"config": {
"color": null,
"center": [
121,
183
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "ball",
"config": {
"color": null,
"center": [
175,
76
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "wall",
"config": {
"color": null,
"center": [
62,
182
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "wall",
"config": {
"color": null,
"center": [
61,
144
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "wall",
"config": {
"color": null,
"center": [
120,
144
],
"size": [
60,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "ball",
"config": {
"color": null,
"center": [
104,
88
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "ball",
"config": {
"color": null,
"center": [
72,
224
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "ball",
"config": {
"color": null,
"center": [
177,
169
],
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}],
"class_data": [{
"game_class": "wall",
"params": {
"color": null,
"size": [
60,
40
]
},
"game_shape_class": "Rect"
}, {
"game_class": "ball",
"params": {
"color": null,
"size": [
80,
40
]
},
"game_shape_class": "Rect"
}]
}
+122
View File
@@ -0,0 +1,122 @@
# Maybe make a non-square rooted function for comparison (faster)
from uniquelist import uniquelist
import math
def atan2_inv(y_diff, x_diff):
'''Returns atan2 in inverted y-axis in degrees'''
return math.degrees(math.atan2(-y_diff, x_diff))
# following constants are required for the next function
def distance(point_1, point_2):
''' distance between point_1 and point_2, where both are 2 member iterable'''
if (not len(point_1) == 2) or (not len(point_2) == 2):
raise TypeError("point_1 and point_2 both must be 2 member iterable")
diff_x = point_2[0] - point_1[0]
diff_y = point_2[1] - point_1[1]
return math.hypot(diff_x, diff_y)
def vel_add(vel_1, vel_2):
''' vel_1 and vel_2 both must be in (magnitude,direction_in_degree) format.
Returns in same format.'''
if (not len(vel_1) == 2) or (not len(vel_2) == 2):
raise TypeError("vel_1 and vel_2 both must be 2 member iterable")
vel_1_x = vel_1[0] * math.cos(math.radians(vel_1[1]))
vel_1_y = -vel_1[0] * math.sin(math.radians(vel_1[1]))
vel_2_x = vel_2[0] * math.cos(math.radians(vel_2[1]))
vel_2_y = -vel_2[0] * math.sin(math.radians(vel_2[1]))
vel_tot_x = vel_1_x + vel_2_x
vel_tot_y = vel_1_y + vel_2_y
vel_tot = (
math.hypot(vel_tot_x, vel_tot_y), atan2_inv(vel_tot_y, vel_tot_x))
return vel_tot
def direction(point_1, point_2):
if (not len(point_1) == 2) or (not len(point_2) == 2):
raise TypeError("point_1 and point_2 both must be 2 member iterable")
diff_x = point_2[0] - point_1[0]
diff_y = point_2[1] - point_1[1]
return atan2_inv(diff_y, diff_x)
UNION = 1
INTERSECTION = 2
DIFFERENCE = 3
ADD = 4
# for each member (usually objects) in the list, it is replaced by one of
# its variables
MAKE_IT_VARIABLE_LIST = 5
def operation_on_lists(operation, list1, list2=None, variable_name=None):
''' operation_on_lists(operation, list1, list2) -> list
Does operation involving list1 and list2.
variable_name is required only for MAKE_IT_VARIABLE_LIST operation. It is a string representing the variable name
Valid operations are UNION, INTERSECTION, DIFFERENCE, ADD, MAKE_IT_VARIABLE_list '''
def intersection():
if list2 is None:
raise TypeError("second argument i.e. list2 should be a list")
list_return = []
for temp1 in list1:
for temp2 in list2:
if temp1 == temp2:
list_return.append(temp1)
return list_return
def union():
if list2 is None:
raise TypeError("second argument i.e. list2 should be a list")
list_return = uniquelist()
list_return.extend(list1)
list_return.extend(list2)
return list_return
def add():
if list2 is None:
raise TypeError("second argument i.e. list2 should be a list")
list_return = []
list_return.append(list1)
list_return.append(list2)
return list_return
def difference():
if list2 is None:
raise TypeError("second argument i.e. list2 should be a list")
list_return = []
list_intersection = intersection()
for temp1 in list1:
if temp1 not in list_intersection:
list_return.append(temp1)
return list_return
# for each member (usually objects) in the list, it is replaced by one of
# its variables
def make_it_variable_list():
if variable_name is None:
raise TypeError("variable_name should be a string")
if not list2 is None:
raise TypeError("list2 should be None")
return_list = [getattr(temp, variable_name) for temp in list1]
if operation == UNION:
return union()
elif operation == INTERSECTION:
return intersection()
elif operation == DIFFERENCE:
return difference()
elif operation == ADD:
return add()
elif operation == MAKE_IT_VARIABLE_LIST:
return make_it_variable_list()
else:
raise ValueError(
"Invalid operation name. Valid operations are UNION, INTERSECTION, DIFFERENCE.")
# end of operation_on_lists()
BIN
View File
Binary file not shown.
+9
View File
@@ -0,0 +1,9 @@
{
"folders":
[
{
"follow_symlinks": true,
"path": "."
}
]
}
File diff suppressed because it is too large Load Diff
+219
View File
@@ -0,0 +1,219 @@
#!/bin/env python
import wx
import json
import load_map
import os
import room_sprite_panel as sprite_panel
from copy import deepcopy
class MyFrame(wx.Frame):
def __init__(self):
self.size = (500, 300)
wx.Frame.__init__(self, None, -1, "My Frame", size=self.size)
self.create_panel_ctrl_canvas()
self.create_box_sizer()
self.bind_events_default()
self.load_saved_json()
# todo: make load_module_py func
def load_saved_json(self):
# Load map
wildcard_py = "Python source (*.py)|*.py|" \
"Compiled Python (*.pyc)|*.pyc|" \
"All files (*.*)|*.*"
wildcard_json = "Json file (*.json)|*.json"
dialog_file = wx.FileDialog(None, "Choose game.py file", os.getcwd(),
"", wildcard_json, wx.OPEN)
if dialog_file.ShowModal() == wx.ID_OK:
tmp_path = dialog_file.GetPath()
filename = os.path.basename(tmp_path)
# filename_without_ext = filename[:filename.rfind(".")]
filepath = os.path.dirname(tmp_path)
list_loaded_cls, data_loaded_inst = load_map.load_json(
filename, filepath)
self.dict_loaded_cls = {}
for each_cls in list_loaded_cls:
self.dict_loaded_cls[each_cls.__name__] = each_cls
## del list_loaded_cls
else:
raise TypeError("Enter a filename to proceed")
self.sync_panel_ctrl(self.dict_loaded_cls.keys())
self.generate_loaded_inst(data_loaded_inst)
dialog_file.Destroy()
def create_panel_ctrl_canvas(self):
# create the list control
self.panel_ctrl = wx.Panel(
self, -1, size=(-2, -1))
self.panel_ctrl.SetBackgroundColour("aquamarine")
self.panel_ctrl.SetMaxSize((250, -1))
self.panel_ctrl.list_ctrl = wx.ListCtrl(
self.panel_ctrl, -1, style=wx.LC_LIST, size=(200, 180))
self.list_shape = []
self.panel_canvas = wx.Panel(
self, -1, size=(-3, -1))
self.panel_canvas.SetBackgroundColour("light blue")
def create_box_sizer(self):
bxszr = wx.BoxSizer(wx.HORIZONTAL)
bxszr.Add(self.panel_ctrl, 2, flag=wx.EXPAND)
bxszr.Add(self.panel_canvas, 3, flag=wx.EXPAND)
self.SetSizer(bxszr)
# self.Fit()
def generate_loaded_inst(self, list_):
print(len(list_))
for each_inst in list_:
self.create_shape_panel_from_str(
each_inst["game_class"], each_inst["config"])
def sync_panel_ctrl(self, list_str):
for index, str_ in enumerate(list_str):
if index > self.panel_ctrl.list_ctrl.GetItemCount() - 1:
method_ = self.panel_ctrl.list_ctrl.InsertStringItem
else:
method_ = self.panel_ctrl.list_ctrl.SetItemText
# try:
method_(index, str_)
# self.panel_ctrl.list_ctrl.Refresh()
# except:
# pass
def create_shape_panel_from_str(self, str_, params=None):
tmp_game_cls = self.dict_loaded_cls[str_]
return self.create_shape_panel(tmp_game_cls, params)
def create_shape_panel(self, game_cls, params=None):
tmp_dict = deepcopy(game_cls.sprite_defaults)
tmp_panel = tmp_dict["panel"]
if params is None:
params = {}
tmp_params = tmp_dict["params"]
tmp_params.update(params)
center = tmp_params.pop("center")
tmp_shape_panel = tmp_panel(
self.panel_canvas, center=center, **tmp_params)
tmp_shape_panel.user_data = {"class": game_cls.__name__}
tmp_shape_panel.Show()
self.panel_canvas.Refresh()
self.list_shape.append(tmp_shape_panel)
return tmp_shape_panel
def action_key_press(self, ev):
print self.__class__
keyCode = ev.GetKeyCode()
try:
keyText = chr(keyCode).upper()
except:
keyText = None
print keyText
if keyText == "E":
print self.export_data("map.json")
def bind_events_default(self):
print "binding"
self.panel_ctrl.list_ctrl.Bind(wx.EVT_KEY_DOWN, self.action_key_press)
self.panel_canvas.Bind(wx.EVT_LEFT_DOWN, self.action_mouse_left_down)
def action_mouse_left_down(self, ev):
focus_id = self.panel_ctrl.list_ctrl.FocusedItem
if (focus_id == -1):
focus_id = 0
print "Setting focus"
self.panel_ctrl.list_ctrl.Focus(focus_id)
focus_id = self.panel_ctrl.list_ctrl.FocusedItem
focus_text = self.panel_ctrl.list_ctrl.GetItem(
focus_id).GetText()
pos = ev.GetPosition()
tmp_panel = self.create_shape_panel_from_str(
focus_text, {"center": pos})
tmp_panel.SetFocus()
@staticmethod
def for_all_panel_class(func_):
return_list = []
for tmp_panel_cls in sprite_panel.CanvasPanel.dict_sprite_panel.values():
val_return = func_(tmp_panel_cls)
return_list.append(val_return)
return return_list
@staticmethod
def for_all_panel_inst(func_, flatten=False):
# todo: use for_all_panel_class
list_return = []
for tmp_panel_cls in sprite_panel.CanvasPanel.dict_sprite_panel.values():
tmp_list = []
for tmp_panel_inst in tmp_panel_cls.list_panel_inst:
val_return = func_(tmp_panel_inst)
tmp_list.append(val_return)
if flatten:
list_return.extend(tmp_list)
else:
list_return.append(tmp_list)
return list_return
@staticmethod
def export_game_cls(game_cls):
dict_return = {}
dict_return["game_class"] = game_cls.__name__
tmp_sprite_defaults = deepcopy(game_cls.sprite_defaults)
dict_return["game_shape_class"] = tmp_sprite_defaults["type"].map_class
dict_return["params"] = tmp_sprite_defaults["params"]
return dict_return
def for_all_game_cls(self, func_):
list_return = []
for tmp_game_cls in self.get_all_loaded_cls():
val_return = func_(tmp_game_cls)
list_return.append(val_return)
return list_return
def get_all_loaded_cls(self):
return self.dict_loaded_cls.values()
def export_data(self, file_=None, pprint_=True):
class_data = self.for_all_game_cls(
lambda game_cls: self.export_game_cls(game_cls))
instance_data = self.for_all_panel_inst(
lambda panel_inst: panel_inst.get_props(), flatten=True)
data = {"class_data": class_data, "instance_data": instance_data}
if pprint_:
jsoned_data = json.dumps(data, indent=4)
print jsoned_data
else:
jsoned_data = json.dumps(data)
if file_ is None:
return jsoned_data
elif isinstance(file_, str):
file_ = open(file_, "w")
if isinstance(file_, file):
file_.write(jsoned_data)
file_.close()
else:
raise TypeError("file_ parameter must be of file or str type.")
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show(True)
app.MainLoop()
+189
View File
@@ -0,0 +1,189 @@
#!/bin/env python
import wx
import json
import load_map
import os
import room_sprite_panel as sprite_panel
from copy import deepcopy
class MyFrame(wx.Frame):
def __init__(self):
self.size = (500, 300)
wx.Frame.__init__(self, None, -1, "My Frame", size=self.size)
self.panel_ctrl = wx.Panel(
self, -1, size=(-2, -1))
self.panel_ctrl.SetBackgroundColour("aquamarine")
self.panel_ctrl.SetMaxSize((250, -1))
# load some images into an image list
il = wx.ImageList(16, 16, True)
il.Add(wx.EmptyBitmap(16, 16))
# create the list control
self.panel_ctrl.list_ctrl = wx.ListCtrl(
self.panel_ctrl, -1, style=wx.LC_LIST, size=(200, 180))
# self.list_shape = []
# Load map
wildcard_py = "Python source (*.py)|*.py|" \
"Compiled Python (*.pyc)|*.pyc|" \
"All files (*.*)|*.*"
dialog_file = wx.FileDialog(None, "Choose game.py file", os.getcwd(),
"", wildcard_py, wx.OPEN)
if dialog_file.ShowModal() == wx.ID_OK:
self.module_path = dialog_file.GetPath()
filename = os.path.basename(self.module_path)
filename_without_ext = filename[:filename.rfind(".")]
filepath = os.path.dirname(self.module_path)
list_loaded_cls = load_map.load_module(
filename_without_ext, filepath)
self.dict_loaded_cls = {}
for each_cls in list_loaded_cls:
self.dict_loaded_cls[each_cls.__name__] = each_cls
del list_loaded_cls
else:
raise TypeError("Enter a filename to proceed")
self.sync_panel_ctrl(self.dict_loaded_cls.keys())
dialog_file.Destroy()
# assign the image list to it
# self.panel_ctrl.list_ctrl.AssignImageList(il, wx.IMAGE_LIST_SMALL)
self.panel_canvas = wx.Panel(
self, -1, size=(-3, -1))
self.panel_canvas.SetBackgroundColour("light blue")
bxszr = wx.BoxSizer(wx.HORIZONTAL)
bxszr.Add(self.panel_ctrl, 2, flag=wx.EXPAND)
bxszr.Add(self.panel_canvas, 3, flag=wx.EXPAND)
self.SetSizer(bxszr)
# self.Fit()
self.bind_events_default()
def sync_panel_ctrl(self, list_str):
for index, str_ in enumerate(list_str):
if index > self.panel_ctrl.list_ctrl.GetItemCount() - 1:
method_ = self.panel_ctrl.list_ctrl.InsertStringItem
else:
method_ = self.panel_ctrl.list_ctrl.SetItemText
# try:
method_(index, str_)
# self.panel_ctrl.list_ctrl.Refresh()
# except:
# pass
def create_shape_panel(self, str_, default_center):
tmp_game_cls = self.dict_loaded_cls[str_]
tmp_dict = tmp_game_cls.sprite_defaults
if "center" in tmp_dict:
center = tmp_dict["center"]
else:
center = default_center
tmp_shape_panel = tmp_dict["panel"](
self.panel_canvas, center=center, **tmp_dict["params"])
tmp_shape_panel.user_data = {"class": tmp_game_cls.__name__}
tmp_shape_panel.Show()
self.panel_canvas.Refresh()
# self.list_shape.append(tmp_shape_panel)
def action_key_press(self, ev):
print self.__class__
keyCode = ev.GetKeyCode()
try:
keyText = chr(keyCode).upper()
except:
keyText = None
print keyText
if keyText == "\r":
focus_id = self.panel_ctrl.list_ctrl.FocusedItem
focus_text = self.panel_ctrl.list_ctrl.GetItem(focus_id).GetText()
self.create_shape_panel(focus_text, (0, 0))
if keyText == "E":
print self.export_data("map.json")
def bind_events_default(self):
print "binding"
self.panel_ctrl.list_ctrl.Bind(wx.EVT_KEY_DOWN, self.action_key_press)
@staticmethod
def for_all_panel_class(func_):
return_list = []
for tmp_panel_cls in sprite_panel.CanvasPanel.dict_sprite_panel.values():
val_return = func_(tmp_panel_cls)
return_list.append(val_return)
return return_list
@staticmethod
def for_all_panel_inst(func_, flatten=False):
# todo: use for_all_panel_class
list_return = []
for tmp_panel_cls in sprite_panel.CanvasPanel.dict_sprite_panel.values():
tmp_list = []
for tmp_panel_inst in tmp_panel_cls.list_panel_inst:
val_return = func_(tmp_panel_inst)
tmp_list.append(val_return)
if flatten:
list_return.extend(tmp_list)
else:
list_return.append(tmp_list)
return list_return
@staticmethod
def export_game_cls(game_cls):
dict_return = {}
dict_return["game_class"] = game_cls.__name__
tmp_sprite_defaults = deepcopy(game_cls.sprite_defaults)
dict_return["game_shape_class"] = tmp_sprite_defaults["type"].map_class
dict_return["params"] = tmp_sprite_defaults["params"]
return dict_return
def for_all_game_cls(self, func_):
list_return = []
for tmp_game_cls in self.get_all_loaded_cls():
val_return = func_(tmp_game_cls)
list_return.append(val_return)
return list_return
def get_all_loaded_cls(self):
return self.dict_loaded_cls.values()
def export_data(self, file_=None, pprint_=True):
class_data = self.for_all_game_cls(
lambda game_cls: self.export_game_cls(game_cls))
instance_data = self.for_all_panel_inst(
lambda panel_inst: panel_inst.get_props(), flatten=True)
data = {"class_data": class_data, "instance_data": instance_data}
if pprint_:
jsoned_data = json.dumps(data, indent=4)
print jsoned_data
else:
jsoned_data = json.dumps(data)
if file_ is None:
return jsoned_data
elif isinstance(file_, str):
file_ = open(file_, "w")
if isinstance(file_, file):
file_.write(jsoned_data)
file_.close()
else:
raise TypeError("file_ parameter must be of file or str type.")
if __name__ == '__main__':
app = wx.PySimpleApp()
frame = MyFrame()
frame.Show(True)
app.MainLoop()
+291
View File
@@ -0,0 +1,291 @@
import wx
def register_sprite_panel(sprite_panel):
CanvasPanel.dict_sprite_panel[sprite_panel.game_shape_class] = sprite_panel
return sprite_panel
class CanvasPanel(wx.Panel):
"""Parent canvas panel"""
dict_sprite_panel = {}
def __init__(self, *arg, **kwargs):
super(CanvasPanel, self).__init__(*arg, **kwargs)
self.create_internal()
self.init_start_var()
self.perc = 5.0 / 100
self.update = False
self.delta = None
self.bind_events_default()
def init_start_var(self):
if not hasattr(self, "_start_w"):
self._start_w = self.w
if not hasattr(self, "_start_h"):
self._start_h = self.h
if not hasattr(self, "_start_left"):
self._start_left = self.left
if not hasattr(self, "_start_top"):
self._start_top = self.top
def create_internal(self):
self.w, self.h = self.GetSizeTuple()
self.left, self.top = self.GetPositionTuple()
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(max(1, size.width), max(1, size.height))
def bind_events_default(self):
self.Bind(wx.EVT_KEY_DOWN, self.action_move)
self.Bind(wx.EVT_CHAR_HOOK, self.action_inflate)
self.Bind(wx.EVT_IDLE, self.action_idle)
self.Bind(wx.EVT_LEFT_DOWN, self.action_mouse_left_down)
self.Bind(wx.EVT_LEFT_UP, self.action_mouse_left_up)
self.Bind(wx.EVT_SET_FOCUS, self.action_unfocused)
self.Bind(wx.EVT_KILL_FOCUS, self.action_unfocused)
self.Bind(wx.EVT_MOTION, self.action_dragged)
def action_mouse_left_up(self, ev):
if self.HasCapture():
self.ReleaseMouse()
self.delta = None
def action_dragged(self, ev):
if ev.Dragging() and ev.LeftIsDown() and self.delta:
pos_wrt_self = ev.GetPosition()
pos_wrt_screen = self.ClientToScreen(pos_wrt_self)
pos_wrt_parent = self.GetParent().ScreenToClient(pos_wrt_screen)
pos = pos_wrt_parent
newPos = (pos.x - self.delta.x, pos.y - self.delta.y)
self.Move(newPos)
self.left, self.top = self.GetPositionTuple()
self.update = True
def action_move(self, ev):
keyText = chr(ev.GetUnicodeKey()).upper()
# print "keyText= " + str(keyText)
if keyText == "W":
self.top -= 5
print "moving up"
if keyText == "A":
self.left -= 5
print "moving left"
if keyText == "S":
self.top += 5
print "moving down"
if keyText == "D":
self.left += 5
print "moving right"
self.update = True
ev.Skip()
return True
def action_inflate(self, ev):
keyText = ev.GetKeyCode() # .upper()
# print "char= " + str(keyText)
tmp_perc = None
if keyText == wx.WXK_ADD or keyText == wx.WXK_NUMPAD_ADD:
tmp_perc = self.perc
print "Inflating"
if keyText == wx.WXK_SUBTRACT or keyText == wx.WXK_NUMPAD_SUBTRACT:
tmp_perc = -self.perc
print "Deflating"
if not (tmp_perc is None):
new_w = self.w * (1 + tmp_perc)
new_h = self.h * (1 + tmp_perc)
new_left = self.left - (new_w - self.w) / 2
new_top = self.top - (new_h - self.h) / 2
print "old_w, old_h" + str((self.w, self.h))
print "new_w, new_h" + str((new_w, new_h))
print "old_left, old_top" + str((self.left, self.top))
print "new_left, new_top" + str((new_left, new_top))
print ""
self.left, self.top = new_left, new_top
self.w, self.h = new_w, new_h
self.update = True
ev.Skip()
return True
@property
def center(self):
return (self.left + self.w / 2), (self.top + self.h / 2)
def action_idle(self, ev):
if self.update:
self.SetPosition((self.left, self.top))
self.SetSizeWH(self.w, self.h)
size = self.GetClientSize()
self.buffer = wx.EmptyBitmap(
max(1, size.width), max(1, size.height))
self.GetParent().Refresh()
self.update = False
def action_mouse_left_down(self, ev):
self.SetFocus()
self.CaptureMouse()
pos_wrt_self = ev.GetPosition()
pos_wrt_screen = self.ClientToScreen(pos_wrt_self)
pos_wrt_parent = self.GetParent().ScreenToClient(pos_wrt_screen)
pos = pos_wrt_parent
origin = self.GetPosition()
self.delta = wx.Point(pos.x - origin.x, pos.y - origin.y)
def action_focused(self, ev):
self.Refresh()
def action_unfocused(self, ev):
self.Refresh()
@register_sprite_panel
class RectPanel(CanvasPanel):
"""docstring for RectPanel"""
game_shape_class = "Rect"
list_panel_inst = []
def __init__(self, *arg, **kwargs):
tmp_center = kwargs["center"]
tmp_size = kwargs["size"]
kwargs.pop("center")
kwargs.pop("color")
kwargs["pos"] = (
(tmp_center[0] - tmp_size[0] / 2), (tmp_center[1] - tmp_size[1] / 2))
super(RectPanel, self).__init__(*arg, **kwargs)
self.brush = wx.Brush("Green")
self.list_panel_inst.append(self)
def get_props(self):
return {
"game_class": self.user_data["class"],
"game_shape_class": self.game_shape_class,
"config": {
"center": self.center,
"size": (self.w, self.h),
"color": None,
}
}
def bind_events_default(self):
super(RectPanel, self).bind_events_default()
self.Bind(wx.EVT_PAINT, self.action_paint_rect)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.action_clear_none)
@property
def pen_focused(self):
if not hasattr(self, "_pen_focused"):
self._pen_focused = wx.Pen(
"Blue", width=3, style=wx.PENSTYLE_LONG_DASH)
self._pen_focused.SetCap(wx.CAP_BUTT)
self._pen_focused.SetJoin(wx.JOIN_ROUND)
return self._pen_focused
@pen_focused.setter
def pen_focused(self, val):
self._pen_focused = val
def action_paint_rect(self, ev):
dc = wx.BufferedPaintDC(self, self.buffer)
dc.SetBackground(wx.Brush(wx.Colour(150, 150, 150, 100)))
dc.Clear()
if self.HasFocus():
self.pen = self.pen_focused
else:
self.pen = wx.NullPen
dc.SetBrush(self.brush)
dc.SetPen(self.pen)
dc.DrawRectangle(0, 0, self.w, self.h)
# self.SetBackgroundColour("green")
def action_clear_none(self, ev):
wx.BufferedDC(None, self.buffer)
@register_sprite_panel
class CirclePanel(CanvasPanel):
"""docstring for CirclePanel"""
game_shape_class = "Circle"
list_panel_inst = []
def __init__(self, *arg, **kwargs):
tmp_center = kwargs["center"]
tmp_radius = kwargs["radius"]
kwargs.pop("color")
kwargs["pos"] = (
(tmp_center[0] - tmp_radius), (tmp_center[1] - tmp_radius))
kwargs.pop("center")
kwargs["size"] = (tmp_radius * 2, tmp_radius * 2)
kwargs.pop("radius")
super(CirclePanel, self).__init__(*arg, **kwargs)
self.brush = wx.Brush("Green")
self.list_panel_inst.append(self)
def bind_events_default(self):
super(CirclePanel, self).bind_events_default()
self.Bind(wx.EVT_PAINT, self.action_paint_circle)
self.Bind(wx.EVT_ERASE_BACKGROUND, self.action_clear_none)
@property
def pen_focused(self):
if not hasattr(self, "_pen_focused"):
self._pen_focused = wx.Pen(
"Blue", width=3, style=wx.PENSTYLE_LONG_DASH)
self._pen_focused.SetCap(wx.CAP_BUTT)
self._pen_focused.SetJoin(wx.JOIN_ROUND)
return self._pen_focused
@pen_focused.setter
def pen_focused(self, val):
self._pen_focused = val
def action_paint_circle(self, ev):
dc = wx.BufferedPaintDC(self, self.buffer)
dc.SetBackground(wx.Brush(wx.Colour(150, 150, 150, 100)))
dc.Clear()
if self.HasFocus():
self.pen = self.pen_focused
else:
self.pen = wx.NullPen
dc.SetBrush(self.brush)
dc.SetPen(self.pen)
dc.DrawCircle(self.w / 2, self.h / 2, self.w / 2)
def action_clear_none(self, ev):
wx.BufferedDC(None, self.buffer)
def get_props(self):
return {
"class": self.user_data["class"],
"game_shape_class": self.game_shape_class,
"config": {
"center": self.center,
"radius": self.w / 2,
"color": None,
}
}
def get_start_props(self):
return {
"class": self.user_data["class"],
"game_shape_class": self.game_shape_class,
"config": {
"center": (self._start_left + self._start_w / 2, self._start_top + self._start_h / 2),
"radius": self._start_w / 2,
"color": None,
}
}
Binary file not shown.
+24
View File
@@ -0,0 +1,24 @@
import Circle
import Rect
import Img
# try..except saves from AttributeError during import
# => means import, -> means running line within that file
# why : sprite_types => Circle => sprite_types -> Circle.Circle
# this raises error, as Circle class not yet defined in Circle
# but when __main__ runs, after all successful imports, Circle.Circle is defined
try:
Circle = Circle.Circle
except:
pass
try:
Rect = Rect.Rect
except:
pass
try:
Img = Img.Img
except:
pass
BIN
View File
Binary file not shown.
+79
View File
@@ -0,0 +1,79 @@
from copy import deepcopy
from uniquelist import uniquelist
class StateClass(object):
"""State engine implementation"""
def __init__(self):
super(StateClass, self).__init__()
self._list_state = uniquelist()
self._current_state = None
self._dict_switch_func = []
self._current_dict = {}
def __getattribute__(self, name):
try:
return self._current_dict[name]
except KeyError:
raise AttributeError("'{self_class}' object has no attribute '{attr_name}'".format(
self_class=self.__class__, attr_name=name))
def __setattr__(self, name, val):
self._current_dict[name] = val
def add_state(self, state_name):
self._list_state.append(str(state_name))
def has_state(self, state_name):
return str(state_name) in self._list_state
def remove_state(self, state_name):
state_name = str(state_name)
self.check_state(state_name)
self._list_state.remove(state_name)
def check_state(self, state_name_or_list):
if isinstance(state_name_or_list, list):
for state_name in state_name_or_list:
self.check_state(state_name)
else:
state_name = state_name_or_list
if self.has_state(state_name):
return state_name
else:
raise ValueError("state {state_name} not registered".format(
state_name=state_name))
def add_switch_func(self, from_, to_, func_):
from_, to_ = str(from_), str(to_)
self.check_state([from_, to_])
if (from_, to_) not in self._dict_switch_func:
self._dict_switch_func[(from_, to_)] = []
self._dict_switch_func[(from_, to_)].append(func_)
def get_switch_func(self, from_, to_):
from_, to_ = str(from_), str(to_)
self.check_state([from_, to_])
return self._dict_switch_func.get((from_, to_))
def switch_state(self, from_, to_, call_func=True):
from_, to_ = str(from_), str(to_)
self.check_state([from_, to_])
# do call_func
if call_func:
switch_func = self.get_switch_func(from_, to_)
if switch_func:
self._current_dict = switch_func(self._current_dict)
else:
self._current_dict = {}
self._current_state = to_
# remove below
+39
View File
@@ -0,0 +1,39 @@
import base
import random
import sys
from base import pygame
tmp_fill_color = (156, 27, 210)
w = h = 200
is_test_ok = None
tmp_i = 0
class test_Game(base.fun_Game):
def __init__(self, *arg, **kwarg):
super(test_Game, self).__init__(*arg, **kwarg)
self.fps = 100000 # max_fps
def test_update(self):
self.screen.fill(tmp_fill_color)
tmp_px_array = pygame.PixelArray(self.screen)
is_test_ok = True
global tmp_i
if tmp_i < 1000:
tmp_i += 1
tmp_w = random.randrange(0, w)
tmp_h = random.randrange(0, h)
if tmp_px_array[tmp_w][tmp_h] != self.screen.map_rgb(tmp_fill_color):
is_test_ok = False
else:
if is_test_ok:
print "Test OK"
else:
print "Test Broken"
sys.exit()
a = test_Game(w, h)
a.run()
# Should display a purple window
+42
View File
@@ -0,0 +1,42 @@
import base
import sys
import random
from base import pygame
tmp_fill_color = (156, 27, 210)
w = random.randint(0, 1336)
h = random.randint(0, 768)
is_test_ok = None
tmp_i = 0
class test_Game(base.fun_Game):
def test_update(self):
tmp_px_array = pygame.PixelArray(self.screen)
is_test_ok = True
global tmp_i
self.screen.fill(tmp_fill_color)
if tmp_i:
for tmp_w in range(w):
for tmp_h in range(h):
tmp_i += 1
if tmp_px_array[tmp_w][tmp_h] != self.screen.map_rgb(tmp_fill_color):
is_test_ok = False
break
if not is_test_ok:
break
print "Test run for %s pixels" % (tmp_i - 1)
if is_test_ok:
print "Test OK"
else:
print "Test Broken"
sys.exit()
tmp_i += 1
a = test_Game(w, h)
a.run()
# Test made so that on first frame, screen is filled with purple.
# Rest of the test loop occurs on second frame
+39
View File
@@ -0,0 +1,39 @@
import base
import random
import sys
from base import pygame
tmp_fill_color = (156, 27, 210)
w = h = 200
is_test_ok = None
tmp_i = 0
class test_Game(base.fun_Game):
def test_update(self):
tmp_px_array = pygame.PixelArray(self.screen)
is_test_ok = True
global tmp_i
self.screen.fill(tmp_fill_color)
if tmp_i:
while tmp_i < 1000 and tmp_i:
tmp_i += 1
tmp_w = random.randrange(0, w)
tmp_h = random.randrange(0, h)
if tmp_px_array[tmp_w][tmp_h] != self.screen.map_rgb(tmp_fill_color):
is_test_ok = False
break
if is_test_ok:
print "Test OK"
else:
print "Test Broken"
sys.exit()
tmp_i += 1
a = test_Game(w, h)
a.run()
# Test made so that on first frame, screen is filled with purple.
# Rest of the test loop occurs on second frame
+12
View File
@@ -0,0 +1,12 @@
import base
# make fun_class with some action handlers, who just print for debug
# move to test
fun_Game.list_event.append(pygame.event.Event(KW_EVENTS_IB["JOY_BUTTON_UP"]))
fun_Game.list_event.append(pygame.event.Event(KW_EVENTS_IB["KEY_UP"]))
fun_Game.list_event.append(pygame.event.Event(KW_EVENTS_IB["KEY_DOWN"]))
fun_Game.process_event_list(fun_Game.list_event)
g = fun_Game(200, 200)
c = fun_Class(0, 0)
g.update_all_class()
+76
View File
@@ -0,0 +1,76 @@
from base import *
import pygame.locals as pygame_const
from sprite_types import Rect, Img, Circle
import event
g = fun_Game(800, 200, fps=30)
event.register_event_name("trIal")
def gen_TRIAL():
return event.Event("trial", dict_={"haha": "hihi"})
# event.register_custom_event_generator(gen_TRIAL)
@register_class(fun_Game)
class ball(fun_Class):
sprite_defaults = {
"type": Rect,
"params": {
"size": (80, 40),
"color": None
# "file_name_or_obj":r"C:\Users\Machine\Pictures\Flight by Twitter_2.jpg"
}
}
def __init__(self, *args, **kwargs):
super(ball, self).__init__(*args, **kwargs)
def action_begin_step(self, ev):
self.next_x, self.next_y = self.center
def action_key_press_right(self, ev):
if ev.dict["key_name"] == "right":
self.next_x += 5
if ev.dict["key_name"] == "left":
self.next_x -= 5
if ev.dict["key_name"] == "up":
self.next_y -= 5
if ev.dict["key_name"] == "down":
self.next_y += 5
def action_end_step(self, ev):
# if not self.collide(b, moved_center=(self.next_x, self.next_y)):
# if hasattr(self, "next_x"):
self.center = self.next_x, self.next_y
def action_key_press_p(self, ev):
if ev.dict["key_name"] == "p":
self.push_event_local(gen_TRIAL())
def action_trIal(self, ev):
print ev.ev_name, ev.dict
def action_instance_create(self, ev):
print "Instance created"
@register_class(fun_Game)
class wall(fun_Class):
sprite_defaults = {
"type": Rect,
"params": {
"size": (60, 40),
"color": None
}
}
if __name__ == "__main__":
a = ball(0, 80)
b = wall(450, 60)
g.run()
Binary file not shown.
+141
View File
@@ -0,0 +1,141 @@
from utils import KW_EVENTS, fuzzy_match_event_name
from functools import partial
import logging
logging.basicConfig(level=logging.DEBUG)
class fun_Class(object):
# dict_action_func -> dict of action funcs, key=event_numb like KEYDOWN
dict_action_func = {}
@classmethod
def register_event(cls, event_name=None, func_to_register=None):
'''
@fun_Class.register_event()
def event_key_down(ev):
pass
OR
@fun_Class.register_event(event_name) # event_name=KEYDOWN (or "key_down")
def whatever(ev):
pass
OR
fun_Class.register_event(event_name,func)
'''
if hasattr(func_to_register, "im_class"):
print("im_class=")
print func_to_register.im_class,func_to_register.imelf,
if (event_name is None) and (func_to_register is None):
# i.e No param passed, used as decorator (1st step of ex. 1)
logging.info("Nothing passed")
return cls.register_event
elif (not(event_name is None)) and (func_to_register is None):
# i.e. one param is passed, maybe func or (str or int)
logging.info("Event Name only passed")
if isinstance(event_name, int) or isinstance(event_name, str):
# i.e. 1st parm-> str or int, is event name, acts as decorator
# (2nd ex.)
# dont hardcode func name- use metaclass
logging.info("Event Name is event_name")
return partial(cls.register_event, event_name)
elif hasattr(event_name, "__call__"):
# first param is func, actually func_to_register.
# So get event_name from func_name (2nd step of 1st ex.)
logging.info("Event Name is actually func")
func_to_register = event_name
event_name = fuzzy_match_event_name(func_to_register.func_name)
return cls.register_event(event_name, func_to_register)
else:
raise TypeError("event_name must be (str or int) or func")
else:
# Both params present
logging.info("Both param passed")
if isinstance(event_name, str):
event_name = fuzzy_match_event_name(event_name)
event_numb = KW_EVENTS[event_name]
elif isinstance(event_name, int):
event_numb = event_name
else:
raise TypeError("event_name should be str or int")
logging.info("Registering func")
if not (event_numb in cls.dict_action_func):
cls.dict_action_func[event_numb] = []
cls.dict_action_func[event_numb].append(func_to_register)
# logging.debug(func_to_register)
return func_to_register
class child(fun_Class):
pass
@child.register_event("key_down")
def ev_arbit(self):
pass
logging.info(fun_Class.dict_action_func)
logging.info(child.dict_action_func)
class child2(fun_Class):
@fun_Class.register_event("key_down")
def ev_arbit_2(self):
pass
logging.info(fun_Class.dict_action_func)
logging.info(child2.dict_action_func)
# Test 1
# logging.info("\nRunning Test 1")
# @fun_Class.register_event("KEydown")
# def ev_arbit():
# pass
# logging.info(ev_arbit)
# Test 1.1
# logging.info("\nRunning Test 1.1")
# @fun_Class.register_event("KEydown")
# def ev_arbit_2():
# pass
# logging.info(fun_Class.dict_action_func)
# logging.info(ev_arbit_2)
# Test 2
# logging.info("\nRunning Test 2")
# @fun_Class.register_event
# def ev_key_up():
# pass
# logging.info(fun_Class.dict_action_func)
# logging.info(ev_key_up)
# Test 3
# logging.info("\nRunning Test 3")
# def test_mousemotion():
# pass
# test_mousemotion = fun_Class.register_event(test_mousemotion)
# logging.info(fun_Class.dict_action_func)
# logging.info(test_mousemotion)
# Test 4
# logging.info("\nRunning Test 4")
# def test_wat():
# pass
# test_wat = fun_Class.register_event("mousemotion", test_wat)
# logging.info(fun_Class.dict_action_func)
# logging.info(test_wat)
+33
View File
@@ -0,0 +1,33 @@
how @classmethod and @property works
how to call in python shell for debugging (import pdb;pdb.set_trace())
what are best-practises for writing classes that makes for better and flexible sub-classes
how __get__ works
Learnt:
1. Can define class functions and class properties (getter/setter) using metaclass.
IMP (Have to try):
import inspect
class meta(type):
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods=inspect.getmembers(temp_cls,inspect.ismethod)
for method in methods:
print inspect.getargspec(method[1])
class A(Object):
__metaclass__=meta
@doit(what_to_do)
def abc():
pass
def doit(what_to_do, main_func):
def abc(what_to_do=what_to_do,main_func=main_func):
pass
return "pass" function containing both params (and a special param to indicate doit-processed func)\
with default values set (default values are themself func).
What meta does ->
Identify funcs processed with doit and return main_func after invoking what_to_do
+114
View File
@@ -0,0 +1,114 @@
dx,dy for sprites
mouse.x,mouse.y
mouse_collision_events
is_focused func
(do) room
(Done) move by wasd
(Done) resize about center by +-
(Done) ---- resize Working, but problem with ints, need internal floats
(Done) show all instances
add, delete button
(Done) highlight on focus (?)
(Done differently) make fake instances, not classes
(Done) Create from game.py
(Done) all prev actions with mouse
(Done) export to json
** save ori game.py filename**
(Done) save original size and other props, which should be restored while loading after populating loaded shapes
(Done) Load from json, needs seperate inst creation logic
() saved map cant depend upon original game.py, reduces portability
needs some sort of update from existing map method, think later
Create map of certain dimension
** extracted from game.py **
** menu - load, new, export **
-- fake pygame module for faster map loading --
** color conversion **
-- Heavy code refactoring --
** grid snapping **
Serialize pygame.color
LATER
transparent panels
(think) timer
(later) UI
panel-ish things where x,y is diff from whole screen
panels dynamically resizable
extra events for focus, mouse click, keyboard tabbing and value change stuff
e.g. to have a score sidebar
(done for now) solve circular imports
DOWNLOAD pyqt/pyside books
Todo: make set of excel funcs with pyxll
dwnload sp1, vb book and ide
(drawing bug) with non-clearing rect aka contains condition
Use rects retuned from blit to display.update
(imp) gen_event_IB filters - modify ev_name and dict, eg below
IMP - learn how import works
(later) actual bitmap collision.
(later) move collisions to sep. module
INSTALL win32api and check boa
DOWNLOAD Editors such as wxDesigner, wxrcedit, XRCed and wxWorkshop
(todo, add warning) pygame.locals has pygame.Rect. So, importing that may overload sprite_types.Rect. fix this in base.py
state machine
fix tiltedrect,img, line,ellipse,point,tri
filters:
key_press - cnvrt "mod" to list,
mouse - cnvrt btn_id to btn_name,
mouse - mod get_btn_name to include 4 and 5 scroll ids.
look for more
(imp) draw_ext
add TEXT class, open all shape drawing and rect filling api
(think) all in_place operators should return self, i.e. chainable
(think) use from_container_obj classmethod for all sprite creation and cnstrctr for standalone use
(think) move key and mouse funcs from event.py to seperate modules
(think) asset management
(think) views
(think) physics
(think) brython
(think) use key_names instead of id, sort it out
(later) make fun_Game instances global
(later) make fun_Game instance singleton (??) or maybe needs no instantiation (seems better, everything class,ethod and classprop)
(later) some action plugins for common scenarios
(later) unregister classes
(Done) distance and angle, motion_add funcs
(Done, but draw-update rect solves both) blit at int(x),int(y)
(Done) default action_close
(Done) top-level custom event generator working
(Done) event XXgeneratorXX / pushing at XX(class) [Not sure how to implement]XX and instance level
(done) img - implement collision_mask with existing shapes,
(done)mouse_press events
(done) fix check_event-ish func (soln- moved to event), also old key_press_states
(done) Fixed rect,circle.
(done) *explicit blit print always showing, when more than 1 obj
(done) *not implemented completely.
knowing about others(Done)
(done) more collision like GM
(Done) in-built hspeed, vspeed, direction, speed,accln, x_prev, y_prev, x_start, y_start
(Done) Circle(params).update for not still_valid old_rects -> optimize, maybe save bbox in list instead of creating for each old one
(Done) fix putting "still_valid" within dict_update used for marking (added note, was actually a good idea, Done)
why the heck 60fps flickering -> in-built recording mechanism?
forum discussion=> display.flip fixes it
clear_rect+new_drawn_rect passed to update -> optimize? (for later, have to ask)
make graphical glitches by removing few updates_display :D
+19 -7
View File
@@ -1,20 +1,32 @@
# move it to utils.py
# also look at frozensets
# look at import collections - lot of good data structures
# learn about co-routines (returning generators from generators i.e. yield
# statement)
class uniquelist(list): class uniquelist(list):
''' A list whose every value is unique. ''' A list whose every value is unique.
uniquelist.append(val) or __setitem__(pos,val) i.e. uniquelist[pos]=val is ignored if val is already in uniquelist. uniquelist.append(val) or __setitem__(pos,val) i.e. uniquelist[pos]=val is ignored if val is already in uniquelist.
Returns True if the value is added, else returns False. ''' Returns True if the value is added, else returns False. '''
def __setitem__(self,pos,val):
def __setitem__(self, pos, val):
if val not in self: if val not in self:
super(uniquelist,self).__setitem__(pos,val) super(uniquelist, self).__setitem__(pos, val)
return True return True
else: else:
return False return False
def append(self,val):
def append(self, val):
if val not in self: if val not in self:
super(uniquelist,self).append(val) super(uniquelist, self).append(val)
return True return True
else: else:
return False return False
def extend(self,iterable):
for temp in iterable: # todo: use yield so that it is not copied into memory def extend(self, iterable):
# todo: use yield so that it is not copied into memory
for temp in iterable:
self.append(temp) self.append(temp)
# Todo: Allow for type checking by allowing a type_of_members to be set # Todo: Allow for type checking by allowing a type_of_members to be set
BIN
View File
Binary file not shown.
+268
View File
@@ -0,0 +1,268 @@
# Utility functions
# ToDo: Put everything in a class as staticmethods when imported, if
# name=__main__, keep them local
from functools import partial
import inspect
import logging
import types
import event
from uniquelist import uniquelist
from UncasedDict import UncasedDict
def register(list_to_register=None):
''' Used as decorator: Adds the function (or anything else) to list_to_register '''
def temp_func(what_to_register):
list_to_register.append(what_to_register)
return what_to_register
return temp_func
def fuzzy_match_event_name(string, event_or_action):
str_upper = string.upper()
if not (str_upper in event.dict_event_name):
event_or_action = event_or_action.lower()
if event_or_action.lower() == "event" or event_or_action.lower() == "action":
# STR_STARTER becomes event_ or action_
STR_STARTER = event_or_action.upper() + "_"
else:
raise AttributeError(
"event_or_action arg must be 'event' or 'action'.")
str_normalized = str_upper[
str_upper.find(STR_STARTER) + len(STR_STARTER):]
for tmp_event_name in event.dict_event_name:
# tmp event is the event_name, keys of KW_EVENTS
tmp_event_name = tmp_event_name.upper()
tmp_event_name_normalized = tmp_event_name.replace("_", "")
if str_normalized.startswith(tmp_event_name) or str_normalized.startswith(tmp_event_name_normalized):
return tmp_event_name
else:
return str_upper
class Action(object):
""" pygame.event.Action(type, dict): return Action
pygame.Action.Action(type, **attributes): return Action
"""
def __init__(self, type, *args, **kwargs):
super(Action, self).__init__()
self.type = type
_dict = {}
if len(args) == 1:
_dict.update(args[0])
elif len(args) > 1:
raise TypeError(
"Max one non-keyword argument allowed (which is set to dict)")
if kwargs:
_dict.update(kwargs)
if _dict:
self.dict = _dict
def copy_func(f, name=None):
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
f.func_defaults, f.func_closure)
def selfie_depreceated(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return partial(f, f)
def selfie(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return f.__get__(f, type(f))
def sync_func(func1, func2):
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
func1.func_code = func2.func_code
func1.func_defaults = func2.func_defaults
func1.func_dict = func2.func_dict
func1.func_doc = func2.func_doc
func1.func_name = func2.func_name
class meta_accessor_class(type):
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
temp_cls.list_instance = uniquelist()
temp_cls.list_check_func = uniquelist()
# dict_action_func -> dict of action funcs, key=event_numb like KEYDOWN
temp_cls.dict_action_func = UncasedDict()
methods = inspect.getmembers(temp_cls, inspect.ismethod)
for (method_name, method_obj) in methods:
if fuzzy_match_event_name(method_name, "action"):
temp_cls.register_action(method_obj)
return temp_cls
@selfie
def run_dec_on_meta(self, what_to_do):
'''Runs decorator (what_to_do) passed to it during meta with args, cls=>class and func=>function which this is used on'''
# make copies of this func and instead of params use .vars. Should accept
# *args,*kwargs to main_func. Next step: multiple funcs, think.
def inter_run_dec_on_meta(*args, **kwargs):
# this intermediate func is used to produce func_process_meta for each
# time
def func_process_meta(self, *args, **kwargs):
if not hasattr(self, "_process_meta"):
# changing own's state, should be restored at last step before
# meta-return
self._process_meta = False
#(below) unneccesary here
if not hasattr(self, "__old_args") and not hasattr(self, "__old_kwargs"):
self.__old_args = None
self.__old_kwargs = None
if not self._process_meta:
# as long as not being meta-processed
# its not really main_func, really its just what_to_do's param
if (self.__old_args or self.__old_kwargs):
self.what_to_do = partial(
self.what_to_do, *(self.__old_args), **(self.__old_kwargs))
self.__old_args = args
self.__old_kwargs = kwargs
return selfie(self)
else:
self.main_func = self.__old_args[0]
return self
func_process_meta.__old_args = args
func_process_meta.__old_kwargs = kwargs
func_process_meta.what_to_do = what_to_do
func_process_meta.selfie = True
func_process_meta = selfie(func_process_meta)
return func_process_meta
return inter_run_dec_on_meta
def run_func_on_meta(run_func):
'''Runs func (run_func) passed to it during meta with arg, cls.
run_func remains a method of the class.'''
run_func._run_meta = True
return run_func
def register_action(event_name=None, func_to_register=None, cls=None):
'''
@fun_Class.register_action() # @fun_Class.register_action === @fun_Class.register_action()
def event_key_down(ev):
pass
OR
# event_name=KEYDOWN (or "key_down")
@fun_Class.register_action(event_name)
def whatever(ev):
pass
OR
fun_Class.register_action(event_name,func)
'''
if (event_name is None) and (func_to_register is None):
# i.e No param passed, used as decorator (1st step of ex. 1)
logging.info("Nothing passed")
return register_action
elif (not(event_name is None)) and (func_to_register is None):
# i.e. one param is passed, maybe func or (str or int)
logging.info("Event Name only passed")
if isinstance(event_name, str):
# i.e. 1st parm-> str , is event name, acts as decorator
# (2nd ex.)
# dont hardcode func name- use metaclass
logging.info("Event Name is event_name")
return partial(cls.register_action, event_name)
elif hasattr(event_name, "__call__"):
# first param is func, actually func_to_register.
# So get event_name from func_name (2nd step of 1st ex.)
logging.info("Event Name is actually func")
func_to_register = event_name
event_name = fuzzy_match_event_name(
func_to_register.func_name, "action")
return register_action(event_name=event_name, func_to_register=func_to_register, cls=cls)
else:
raise TypeError("event_name must be str or func")
else:
# Both params present
logging.info("Both param passed")
if isinstance(event_name, str):
event_name = fuzzy_match_event_name(event_name, "action")
logging.info("Registering func")
if not (event_name in cls.dict_action_func):
cls.dict_action_func[event_name] = []
list_ = cls.dict_action_func[event_name]
if not (func_to_register in list_):
list_.append(func_to_register)
else:
raise Exception("func_to_register was already rgistered, skipping")
return func_to_register
def register_class(game_class, cls=None):
''' Register this class on mega_class.
Calls _regitser_class_ on mega_class with arg cls'''
if cls is None:
return partial(register_class, game_class)
game_class.register_class(cls)
cls.game_obj = game_class
return cls
def remove_from_list(list_, val, recursive=False):
if val in list_:
list_.remove(val)
if recursive:
while (val in list_):
list_.remove(val)
return list_
def rect_to_pygame_rect(rect):
if hasattr(rect, "bbox"):
rect = rect.bbox
return rect
class updater_list(list):
"""list which also calls a updater func on data change"""
def __init__(self, updater_func, *arg, **kwargs):
super(updater_list, self).__init__(*arg, **kwargs)
self.updater_func = updater_func
def insert(self, *arg, **kwargs):
to_return = super(updater_list, self).insert(*arg, **kwargs)
self.updater_func(self)
return to_return
def pop(self, *arg, **kwargs):
to_return = super(updater_list, self).pop(*arg, **kwargs)
self.updater_func(self)
return to_return
def append(self, *arg, **kwargs):
to_return = super(updater_list, self).append(*arg, **kwargs)
self.updater_func(self)
return to_return
def extend(self, *arg, **kwargs):
to_return = super(updater_list, self).extend(*arg, **kwargs)
self.updater_func(self)
return to_return
def __getitem__(self, *arg, **kwargs):
to_return = super(updater_list, self).__getitem__(*arg, **kwargs)
self.updater_func(self)
return to_return
def __setitem__(self, *arg, **kwargs):
to_return = super(updater_list, self).__setitem__(*arg, **kwargs)
self.updater_func(self)
return to_return
BIN
View File
Binary file not shown.
+247
View File
@@ -0,0 +1,247 @@
# Utility functions
# ToDo: Put everything in a class as staticmethods when imported, if
# name=__main__, keep them local
from pygame import locals as pygame_consts
from functools import partial
import inspect
import logging
import types
def register(list_to_register=None):
''' Used as decorator: Adds the function (or anything else) to list_to_register '''
def temp_func(what_to_register):
list_to_register.append(what_to_register)
return what_to_register
return temp_func
KW_EVENTS = {
"QUIT": pygame_consts.QUIT,
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
"KEY_DOWN": pygame_consts.KEYDOWN,
"KEY_UP": pygame_consts.KEYUP,
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
"USER_EVENT": pygame_consts.USEREVENT,
# think of begin_step, step and end_step
"BEGIN_STEP": pygame_consts.USEREVENT + 1,
"STEP": pygame_consts.USEREVENT + 2,
"END_STEP": pygame_consts.USEREVENT + 3
}
def fuzzy_match_event_name(string):
# print(string)
str_normalized = string.upper()
for tmp_event in KW_EVENTS:
# tmp event is the event_name, keys of KW_EVENTS
tmp_event_normalized = tmp_event.replace("_", "")
if (tmp_event in str_normalized) or (tmp_event_normalized in str_normalized):
return tmp_event
class Action(object):
""" pygame.event.Action(type, dict): return Action
pygame.Action.Action(type, **attributes): return Action
"""
def __init__(self, type, *args, **kwargs):
super(Action, self).__init__()
self.type = type
_dict = {}
if len(args) == 1:
_dict.update(args[0])
elif len(args) > 1:
raise TypeError(
"Max one non-keyword argument allowed (which is set to dict)")
if kwargs:
_dict.update(kwargs)
if _dict:
self.dict = _dict
def copy_func(f, name=None):
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
f.func_defaults, f.func_closure)
def selfie_depreceated(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return partial(f, f)
def selfie(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return f.__get__(f, type(f))
def sync_func(func1, func2):
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
func1.func_code = func2.func_code
func1.func_defaults = func2.func_defaults
func1.func_dict = func2.func_dict
func1.func_doc = func2.func_doc
func1.func_name = func2.func_name
class meta_accessor_class(type):
''' This metaclass allows class access to any function (or as extended use, to metaclasses)'''
# Using metaclass and decorator to allow class access during class creation time
# No method defined within the class should have "_process_meta" as arg
# Potential problems: Using closures, function.func_globals is read-only
# Doesnt get appropiate globals, maybe pass it (or the reqd global vars)
# as param on func defn
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
methods = inspect.getmembers(temp_cls, inspect.ismethod)
for (method_name, method_obj) in methods:
has_im_func = hasattr(method_obj, "im_func")
has_func = hasattr(method_obj, "func")
while has_im_func or has_func:
if has_im_func:
method_obj = method_obj.im_func
if has_func:
# cater for partials
method_obj = method_obj.func
has_im_func = hasattr(method_obj, "im_func")
has_func = hasattr(method_obj, "func")
if hasattr(method_obj, "_process_meta"):
method_obj._process_meta = True
# method_obj should return itself after setting main_func
if hasattr(method_obj,"selfie"):
method_obj = method_obj(method_obj)
else:
method_obj = method_obj()
what_to_do, main_func = method_obj.what_to_do, method_obj.main_func
# as we have resolved all im_funcs in
# partial,classmethod,boundmethods
f = method_obj
sync_func(f, main_func)
# func_to_register hardcoded
mod_func = what_to_do(f, cls=temp_cls)
sync_func(f, mod_func)
return temp_cls
@selfie
def run_dec_on_meta(self, what_to_do):
'''Runs decorator (what_to_do) passed to it during meta with args, cls=>class and func=>function which this is used on'''
# must be deepcopied bcoz multiple versions will edit main func
# syntax error to grab attention
# make copies of this func and instead of params use .vars. Should accept
# *args,*kwargs to main_func. Next step: multiple funcs, think.
def inter_run_dec_on_meta(*args,**kwargs):
# this intermediate func is used to produce func_process_meta for each time
def func_process_meta(self, *args, **kwargs):
if not hasattr(self, "_process_meta"):
# changing own's state, should be restored at last step before
# meta-return
self._process_meta = False
#(below) unneccesary here
if not hasattr(self,"__old_args") and not hasattr(self,"__old_kwargs"):
self.__old_args = None
self.__old_kwargs = None
if not self._process_meta:
# as long as not being meta-processed
# its not really main_func, really its just what_to_do's param
if (self.__old_args or self.__old_kwargs):
self.what_to_do = partial(self.what_to_do, *(self.__old_args), **(self.__old_kwargs))
self.__old_args = args
self.__old_kwargs = kwargs
return selfie(self)
else:
self.main_func = self.__old_args[0]
return self
func_process_meta.__old_args = args
func_process_meta.__old_kwargs = kwargs
func_process_meta.what_to_do = what_to_do
func_process_meta.selfie=True
func_process_meta = selfie(func_process_meta)
return func_process_meta
return inter_run_dec_on_meta
def run_func_on_meta(run_func):
'''Runs func (run_func) passed to it during meta with arg, cls.
run_func remains a method of the class.'''
def what_to_do(func, cls):
func(cls=cls)
return func
return run_dec_on_meta(what_to_do=what_to_do, main_func=run_func)
def register_event(event_name=None, func_to_register=None, cls=None):
'''
@fun_Class.register_event() # @fun_Class.register_event === @fun_Class.register_event()
def event_key_down(ev):
pass
OR
# event_name=KEYDOWN (or "key_down")
@fun_Class.register_event(event_name)
def whatever(ev):
pass
OR
fun_Class.register_event(event_name,func)
'''
if (event_name is None) and (func_to_register is None):
# i.e No param passed, used as decorator (1st step of ex. 1)
logging.info("Nothing passed")
return register_event
elif (not(event_name is None)) and (func_to_register is None):
# i.e. one param is passed, maybe func or (str or int)
logging.info("Event Name only passed")
if isinstance(event_name, int) or isinstance(event_name, str):
# i.e. 1st parm-> str or int, is event name, acts as decorator
# (2nd ex.)
# dont hardcode func name- use metaclass
logging.info("Event Name is event_name")
return partial(cls.register_event, event_name)
elif hasattr(event_name, "__call__"):
# first param is func, actually func_to_register.
# So get event_name from func_name (2nd step of 1st ex.)
logging.info("Event Name is actually func")
func_to_register = event_name
event_name = fuzzy_match_event_name(func_to_register.func_name)
return register_event(event_name=event_name, func_to_register=func_to_register, cls=cls)
else:
raise TypeError("event_name must be (str or int) or func")
else:
# Both params present
logging.info("Both param passed")
if isinstance(event_name, str):
event_name = fuzzy_match_event_name(event_name)
event_numb = KW_EVENTS[event_name]
elif isinstance(event_name, int):
event_numb = event_name
else:
raise TypeError("event_name should be str or int")
logging.info("Registering func")
if not (event_numb in cls.dict_action_func):
cls.dict_action_func[event_numb] = []
cls.dict_action_func[event_numb].append(func_to_register)
return func_to_register
##_register_event_ = register_event
##del register_event
# so that register event is actually delegated register
##register_event = run_dec_on_meta(_register_event_)
BIN
View File
Binary file not shown.
+322
View File
@@ -0,0 +1,322 @@
# Utility functions
# ToDo: Put everything in a class as staticmethods when imported, if
# name=__main__, keep them local
from pygame import locals as pygame_consts
from functools import partial
import inspect
import logging
import types
import pygame
from uniquelist import uniquelist
def register(list_to_register=None):
''' Used as decorator: Adds the function (or anything else) to list_to_register '''
def temp_func(what_to_register):
list_to_register.append(what_to_register)
return what_to_register
return temp_func
KW_EVENTS_IB = {
"QUIT": pygame_consts.QUIT,
"ACTIVE_EVENT": pygame_consts.ACTIVEEVENT,
"KEY_DOWN": pygame_consts.KEYDOWN,
"KEY_UP": pygame_consts.KEYUP,
"MOUSE_MOTION": pygame_consts.MOUSEMOTION,
"MOUSE_BUTTON_UP": pygame_consts.MOUSEBUTTONUP,
"MOUSE_BUTTON_DOWN": pygame_consts.MOUSEBUTTONDOWN,
"JOY_AXIS_MOTION": pygame_consts.JOYAXISMOTION,
"JOY_BALL_MOTION": pygame_consts.JOYBALLMOTION,
"JOY_HAT_MOTION": pygame_consts.JOYHATMOTION,
"JOY_BUTTON_UP": pygame_consts.JOYBUTTONUP,
"JOY_BUTTOND_OWN": pygame_consts.JOYBUTTONDOWN,
"VIDEO_RESIZE": pygame_consts.VIDEORESIZE,
"VIDEO_EXPOSE": pygame_consts.VIDEOEXPOSE,
# "USER_EVENT": pygame_consts.USEREVENT,
# think of begin_step, step and end_step
}
# Make kw_events_user automatically
LIST_EVENTS_USER = ["BEGIN_STEP", "STEP", "DRAW", "END_STEP"]
KW_EVENTS_USER = {}
KW_EVENTS_ALL = {}
def populate_KW_EVENTS_USER(LIST_EVENTS_USER=LIST_EVENTS_USER):
'''Populates KW_EVENTS_USER and also updates KW_EVENTS_ALL'''
tmp_event_numb = pygame_consts.USEREVENT
for tmp_event_name in LIST_EVENTS_USER:
KW_EVENTS_USER[tmp_event_name] = tmp_event_numb
tmp_event_numb += 1
global KW_EVENTS_ALL
KW_EVENTS_ALL = {}
for tmp_event_name in KW_EVENTS_IB:
KW_EVENTS_ALL[tmp_event_name] = KW_EVENTS_IB[tmp_event_name]
for tmp_event_name in KW_EVENTS_USER:
KW_EVENTS_ALL[tmp_event_name] = KW_EVENTS_USER[tmp_event_name]
# populated by default, may be repopulated later
populate_KW_EVENTS_USER()
CUE_EVENTS_IB = "unordered IB events here"
LIST_EVENTS_ORDERED = [KW_EVENTS_USER["BEGIN_STEP"], CUE_EVENTS_IB, KW_EVENTS_USER["STEP"],
KW_EVENTS_USER["DRAW"], KW_EVENTS_USER["END_STEP"]]
def sort_events(ev1, ev2):
ev_args = [ev1, ev2]
args_pos = [None, None]
# fix next line
for tmp_index in range(len(ev_args)):
tmp_ev = ev_args[tmp_index]
if (tmp_ev.type in KW_EVENTS_IB.values()):
args_pos[tmp_index] = LIST_EVENTS_ORDERED.index(CUE_EVENTS_IB)
elif (tmp_ev.type in KW_EVENTS_USER.values()):
args_pos[tmp_index] = LIST_EVENTS_ORDERED.index(tmp_ev.type)
tmp_diff = args_pos[0] - args_pos[1]
# convert -ve to -1, 0 to 0, +ve to +1
if tmp_diff == 0:
tmp_diff_unit = 0
else:
tmp_diff_unit = tmp_diff / abs(tmp_diff)
return tmp_diff_unit
def append_user_events(list_):
for temp_ev_name in LIST_EVENTS_USER:
temp_ev_numb = KW_EVENTS_USER[temp_ev_name]
list_.append(pygame.event.Event(temp_ev_numb))
return list_
def fuzzy_match_event_name(string, event_or_action):
str_upper = string.upper()
if not (str_upper in KW_EVENTS_ALL):
event_or_action = event_or_action.lower()
if event_or_action.lower() == "event" or event_or_action.lower() == "action":
# STR_STARTER becomes event_ or action_
STR_STARTER = event_or_action.upper() + "_"
else:
raise AttributeError(
"event_or_action arg must be 'event' or 'action'.")
str_normalized = str_upper[
str_upper.find(STR_STARTER) + len(STR_STARTER):]
for tmp_event_name in KW_EVENTS_ALL:
# tmp event is the event_name, keys of KW_EVENTS
tmp_event_name_normalized = tmp_event_name.replace("_", "")
if str_normalized.startswith(tmp_event_name) or str_normalized.startswith(tmp_event_name_normalized):
return tmp_event_name
else:
return str_upper
class Action(object):
""" pygame.event.Action(type, dict): return Action
pygame.Action.Action(type, **attributes): return Action
"""
def __init__(self, type, *args, **kwargs):
super(Action, self).__init__()
self.type = type
_dict = {}
if len(args) == 1:
_dict.update(args[0])
elif len(args) > 1:
raise TypeError(
"Max one non-keyword argument allowed (which is set to dict)")
if kwargs:
_dict.update(kwargs)
if _dict:
self.dict = _dict
def copy_func(f, name=None):
return types.FunctionType(f.func_code, f.func_globals, name or f.func_name,
f.func_defaults, f.func_closure)
def selfie_depreceated(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return partial(f, f)
def selfie(f):
"""Decorate function `f` to pass a reference to the function
as the first argument"""
return f.__get__(f, type(f))
def sync_func(func1, func2):
'''Makes the 1st param (func) equivalent to 2nd param (func).'''
func1.func_code = func2.func_code
func1.func_defaults = func2.func_defaults
func1.func_dict = func2.func_dict
func1.func_doc = func2.func_doc
func1.func_name = func2.func_name
class meta_accessor_class(type):
''' This metaclass allows class access to any function (or as extended use, to metaclasses)'''
# Using metaclass and decorator to allow class access during class creation time
# No method defined within the class should have "_process_meta" as arg
# Potential problems: Using closures, function.func_globals is read-only
# Doesnt get appropiate globals, maybe pass it (or the reqd global vars)
# as param on func defn
def __new__(cls, name, base, clsdict):
temp_cls = type.__new__(cls, name, base, clsdict)
temp_cls.list_instance = uniquelist()
temp_cls.list_check_func = uniquelist()
# dict_action_func -> dict of action funcs, key=event_numb like KEYDOWN
temp_cls.dict_action_func = {}
methods = inspect.getmembers(temp_cls, inspect.ismethod)
for (method_name, method_obj) in methods:
if fuzzy_match_event_name(method_name, "action"):
temp_cls.register_event(method_obj)
return temp_cls
@selfie
def run_dec_on_meta(self, what_to_do):
'''Runs decorator (what_to_do) passed to it during meta with args, cls=>class and func=>function which this is used on'''
# make copies of this func and instead of params use .vars. Should accept
# *args,*kwargs to main_func. Next step: multiple funcs, think.
def inter_run_dec_on_meta(*args, **kwargs):
# this intermediate func is used to produce func_process_meta for each
# time
def func_process_meta(self, *args, **kwargs):
if not hasattr(self, "_process_meta"):
# changing own's state, should be restored at last step before
# meta-return
self._process_meta = False
#(below) unneccesary here
if not hasattr(self, "__old_args") and not hasattr(self, "__old_kwargs"):
self.__old_args = None
self.__old_kwargs = None
if not self._process_meta:
# as long as not being meta-processed
# its not really main_func, really its just what_to_do's param
if (self.__old_args or self.__old_kwargs):
self.what_to_do = partial(
self.what_to_do, *(self.__old_args), **(self.__old_kwargs))
self.__old_args = args
self.__old_kwargs = kwargs
return selfie(self)
else:
self.main_func = self.__old_args[0]
return self
func_process_meta.__old_args = args
func_process_meta.__old_kwargs = kwargs
func_process_meta.what_to_do = what_to_do
func_process_meta.selfie = True
func_process_meta = selfie(func_process_meta)
return func_process_meta
return inter_run_dec_on_meta
def run_func_on_meta(run_func):
'''Runs func (run_func) passed to it during meta with arg, cls.
run_func remains a method of the class.'''
run_func._run_meta = True
return run_func
def register_event(event_name=None, func_to_register=None, cls=None):
'''
@fun_Class.register_event() # @fun_Class.register_event === @fun_Class.register_event()
def event_key_down(ev):
pass
OR
# event_name=KEYDOWN (or "key_down")
@fun_Class.register_event(event_name)
def whatever(ev):
pass
OR
fun_Class.register_event(event_name,func)
'''
if (event_name is None) and (func_to_register is None):
# i.e No param passed, used as decorator (1st step of ex. 1)
logging.info("Nothing passed")
return register_event
elif (not(event_name is None)) and (func_to_register is None):
# i.e. one param is passed, maybe func or (str or int)
logging.info("Event Name only passed")
if isinstance(event_name, str):
# i.e. 1st parm-> str , is event name, acts as decorator
# (2nd ex.)
# dont hardcode func name- use metaclass
logging.info("Event Name is event_name")
return partial(cls.register_event, event_name)
elif hasattr(event_name, "__call__"):
# first param is func, actually func_to_register.
# So get event_name from func_name (2nd step of 1st ex.)
logging.info("Event Name is actually func")
func_to_register = event_name
event_name = fuzzy_match_event_name(
func_to_register.func_name, "action")
return register_event(event_name=event_name, func_to_register=func_to_register, cls=cls)
else:
raise TypeError("event_name must be str or func")
else:
# Both params present
logging.info("Both param passed")
if isinstance(event_name, str):
event_name = fuzzy_match_event_name(event_name, "action")
logging.info("Registering func")
if not (event_name in cls.dict_action_func):
cls.dict_action_func[event_name] = []
cls.dict_action_func[event_name].append(func_to_register)
return func_to_register
def register_class(game_class, cls=None):
''' Register this class on mega_class.
Calls _regitser_class_ on mega_class with arg cls'''
if cls is None:
return partial(register_class, game_class)
game_class.register_class(cls)
cls.Game = game_class
return cls
def remove_from_list(list_, val, recursive=False):
if val in list_:
list_.remove(val)
if recursive:
while (val in list_):
list_.remove(val)
return list_
def rect_to_pygame_rect(rect):
if hasattr(rect, "bbox"):
rect = rect.bbox
return rect
# _register_event_ = register_event
# del register_event
# so that register event is actually delegated register
# register_event = run_dec_on_meta(_register_event_)
# Move to test
##import pygame
# pygame.init()
##evs = []
# evs.append(pygame.event.Event(KW_EVENTS_IB["KEY_DOWN"]))
# evs.append(pygame.event.Event(KW_EVENTS_IB["JOY_AXIS_MOTION"]))
# evs.append(pygame.event.Event(KW_EVENTS_IB["KEY_UP"]))
# evs.append(pygame.event.Event(KW_EVENTS_IB["MOUSE_BUTTON_UP"]))
# evs.append(pygame.event.Event(KW_EVENTS_USER["DRAW"]))
# evs.append(pygame.event.Event(KW_EVENTS_USER["BEGIN_STEP"]))
# evs.append(pygame.event.Event(KW_EVENTS_USER["END_STEP"]))
# evs.append(pygame.event.Event(KW_EVENTS_USER["STEP"]))
# evs.sort(sort_events)
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB