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,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
|
||||
Reference in New Issue
Block a user