mirror of
https://github.com/bendtherules/pyFun.git
synced 2026-08-18 13:52:46 +00:00
summer update
This commit is contained in:
@@ -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")
|
||||||
@@ -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
Binary file not shown.
@@ -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
|
||||||
+258
File diff suppressed because one or more lines are too long
@@ -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
|
||||||
+298
@@ -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)
|
||||||
@@ -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
|
||||||
Binary file not shown.
+40
@@ -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))
|
||||||
@@ -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))
|
||||||
@@ -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))
|
||||||
+539
@@ -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
|
||||||
Binary file not shown.
+1005
File diff suppressed because it is too large
Load Diff
@@ -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))
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
@@ -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")
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
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):
|
def __init__(self, up_key, down_key, *args, **kwargs):
|
||||||
super(bat, self).__init__(*args, **kwargs)
|
super(bat, self).__init__(*args, **kwargs)
|
||||||
self.up_key = up_key
|
self.up_key = up_key
|
||||||
|
|||||||
+103
@@ -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)
|
||||||
Binary file not shown.
@@ -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
@@ -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
@@ -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()
|
||||||
Binary file not shown.
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"folders":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"follow_symlinks": true,
|
||||||
|
"path": "."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
+219
@@ -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()
|
||||||
@@ -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()
|
||||||
@@ -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.
@@ -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
|
||||||
Binary file not shown.
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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()
|
||||||
@@ -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.
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
+13
-1
@@ -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):
|
def extend(self, iterable):
|
||||||
for temp in iterable: # todo: use yield so that it is not copied into memory
|
# 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
|
||||||
Binary file not shown.
@@ -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
|
||||||
+247
@@ -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_)
|
||||||
Binary file not shown.
+322
@@ -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)
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.7 KiB |
Reference in New Issue
Block a user