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