mirror of
https://github.com/bendtherules/pytry.git
synced 2026-08-18 13:53:01 +00:00
All the previous files
This commit is contained in:
+814
@@ -0,0 +1,814 @@
|
||||
# only for python 2.x
|
||||
from uniquelist import * # imports uniquelist
|
||||
import pygame
|
||||
import pygame.gfxdraw
|
||||
from pygame.locals import * # imports the constants
|
||||
from math import *
|
||||
#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
|
||||
list_state_all_buttons=[] # A sequence of boolean representing the state of every key
|
||||
list_state_all_buttons_old=[] # A sequence of boolean representing the state of every key of previous step
|
||||
def __init__(self,width,height,fps=30):
|
||||
pygame.init()
|
||||
self.fps=fps
|
||||
self.clock=pygame.time.Clock()
|
||||
self.width=width
|
||||
self.height=height
|
||||
|
||||
def update_all_class(self):
|
||||
for temp_cls in fun_Game.list_class:
|
||||
for temp_count in temp_cls.list_instance:
|
||||
temp_count.update()
|
||||
|
||||
def _cache_event_list(self):
|
||||
''' Cache event_list in every step.
|
||||
All events in fun_Game.list_event have a "type" property which are the usual constants. '''
|
||||
fun_Game.list_event_old=fun_Game.list_event # move current list to old list
|
||||
fun_Game.list_state_all_buttons_old=fun_Game.list_state_all_buttons
|
||||
|
||||
fun_Game.list_event=pygame.event.get()
|
||||
fun_Game.list_state_all_buttons=pygame.key.get_pressed() #Returns a sequence of boolean representing the state of every key. Use key constant values for indexing.
|
||||
#print fun_Game.list_event # debug message
|
||||
# control access to list_event
|
||||
# with getter, do something crazy for filtering
|
||||
# or a filtering function
|
||||
|
||||
def run(self):
|
||||
self.screen=pygame.display.set_mode([self.width,self.height])
|
||||
while True:
|
||||
self._cache_event_list() # Todo: Add other update-related functions
|
||||
self.update_all_class()
|
||||
# VERY IMPORTANT: Do a spare first step so that every variable / list gets initialised 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)
|
||||
self.screen.fill([50,100,150]) # Todo: Remove this debug statement
|
||||
pygame.display.flip() # debug statement
|
||||
#print(event)
|
||||
#print(fun_Game.list_event_old)
|
||||
# Todo - Add crazy functions to allow other objects and instances finding like GM
|
||||
|
||||
#class fun_Game ends here
|
||||
|
||||
class meta_fun_Class(type):
|
||||
def __new__(cls,name,base,clsdict):
|
||||
temp_class=type.__new__(cls,name,base,clsdict)
|
||||
fun_Game.list_class.append(temp_class)
|
||||
cls.priority_order=cls.depth=len(fun_Game.list_class) #by default, priority_order and depth depends on "when class was defined"
|
||||
return temp_class
|
||||
|
||||
class fun_Class(object):
|
||||
__metaclass__=meta_fun_Class
|
||||
list_instance=uniquelist()
|
||||
#list_update_functions stores the list of functions to call in the given order.
|
||||
#It can be used for injecting custom user functions (remember order).
|
||||
list_update_functions=uniquelist() #action_draw not added as it depends on depth
|
||||
list_check_functions=uniquelist() # all the check functions added here. what they do: if event_<event_name>: action_<event_name>
|
||||
|
||||
def __init__(self,x,y,img=None):
|
||||
self.x=0
|
||||
self.y=0
|
||||
self.img=img #img should be a fun_Image, but lets do that later
|
||||
fun_Class.list_instance.append(self)
|
||||
self.action_create()
|
||||
|
||||
def update(self):
|
||||
'''calls all functions in list_update_functions in the given order'''
|
||||
temp=None
|
||||
for temp in fun_Class.list_update_functions:
|
||||
temp(self)
|
||||
|
||||
def draw(self):
|
||||
# do some blitting depending on self.img
|
||||
pass
|
||||
|
||||
def register(list_to_register=None):
|
||||
''' Used as decorator: Adds the function to list_to_register '''
|
||||
def temp_func(what_to_register):
|
||||
list_to_register.append(what_to_register)
|
||||
return what_to_register
|
||||
return temp_func
|
||||
|
||||
@register(list_update_functions)
|
||||
def action_begin_step(self):
|
||||
pass
|
||||
@register(list_update_functions)
|
||||
def action_step(self):
|
||||
tmp=self.event_mouse_click()
|
||||
if tmp:
|
||||
print tmp
|
||||
print(self.mouse_get_focused())
|
||||
@register(list_update_functions)
|
||||
def action_end_step(self):
|
||||
pass
|
||||
# creation and destroy event
|
||||
def action_create(self):
|
||||
''' Better to use this function than overloading __init__() '''
|
||||
pass
|
||||
def action_destroy(self):
|
||||
''' Executed when the instance is destroyed '''
|
||||
pass
|
||||
def destroy(self):
|
||||
action_destroy(self)
|
||||
|
||||
# checks for all standard events -- functions named like check_<event>
|
||||
# what they do: if event_<event_name>: action_<event_name>
|
||||
# so lets define event_<event_name>,action_<event_name>,check_<event_name> for each <event_name>
|
||||
|
||||
# keyboard handling (later move to keyboard module)
|
||||
|
||||
# occurs if the key was held down continously since the last step
|
||||
def event_key_pressed(self,key_value):#check if it works
|
||||
if get_event_list(list_to_get=fun_Game.list_state_all_buttons)[key_value] \
|
||||
and get_event_list(list_to_get=fun_Game.list_state_all_buttons_old)[key_value]\
|
||||
and (not get_event_list(event_types=KEYUP,further_check_variable_name="key",further_check_value=key_value))\
|
||||
and (not get_event_list(event_types=KEYUP,further_check_variable_name="key",further_check_value=key_value,list_to_get=fun_Game.list_event_old)):
|
||||
return True
|
||||
|
||||
def action_key_pressed(self,key_value):
|
||||
pass
|
||||
def check_key_pressed(self):
|
||||
pass # Todo: think about how to do it
|
||||
|
||||
# occurs if the key is held at the moment (live)
|
||||
def event_key_pressed_live(self,key_value):#check if it works
|
||||
''' Returns True if the key (represented by key_code) is currently pressed.
|
||||
Problem is that this function is live. Returns True if the key is pressed at that moment.
|
||||
So, for example, two calls in two consecutive steps may return True although the key has been left in the meantime. '''
|
||||
temp_all_buttons=get_event_list(list_to_get=fun_Game.list_state_all_buttons) #Returns a sequence of boolean representing the state of every key. Use key constant values for indexing.
|
||||
if temp_all_buttons[key_value]: # indexing by key_value
|
||||
return True
|
||||
def action_key_pressed_live(self,key_value):
|
||||
pass
|
||||
def check_key_pressed_live(self):
|
||||
temp_all_buttons=get_event_list(list_to_get=fun_Game.list_state_all_buttons) #Returns a sequence of boolean representing the state of every key. Use key constant values for indexing.
|
||||
for temp in range(len(temp_all_buttons)): # temp represents the key code in numbers as it is the index of list_state_all_buttons indirectly
|
||||
if temp_all_buttons[temp]:
|
||||
self.action_key_pressed_live(temp) #temp is the keycode
|
||||
|
||||
# occurs if a key press occurs (i.e. pushed down)
|
||||
# key repetations may occur as the list is cached per step and there might be multiple (same key)press per step.
|
||||
def event_key_down(self,key=None):
|
||||
if key == None:
|
||||
return get_event_list(KEYDOWN)
|
||||
else:
|
||||
return get_event_list(KEYDOWN,"key",key)
|
||||
def action_key_down(self,key):
|
||||
pass
|
||||
def check_key_down(self):
|
||||
for temp in get_event_list(KEYDOWN):
|
||||
action_key_down(self,temp.key)
|
||||
|
||||
|
||||
#probably wierd thing to do - define all <>_key_down as equivalent to <>_key_press
|
||||
event_key_press = event_key_down
|
||||
action_key_press = action_key_down
|
||||
check_key_press = check_key_down
|
||||
|
||||
# occurs if key is released
|
||||
def event_key_up(self,key=None):
|
||||
if key==None:
|
||||
return get_event_list(KEYUP)
|
||||
else:
|
||||
return get_event_list(KEYUP,"key",key)
|
||||
def action_key_up(self,key):
|
||||
pass
|
||||
def check_key_up(self):
|
||||
for temp in get_event_list(KEYUP):
|
||||
action_key_up(self,temp.key)
|
||||
# Todo: Do other key and keyboard related functions (look at GM for related functions)
|
||||
# Mouse handling (later move it to mouse module)
|
||||
#Mouse constants (defined at top - move them to a constants module, which will be imported in the global namespace)
|
||||
#mouse click
|
||||
def event_mouse_click(self,button=None):
|
||||
if button==None:
|
||||
return get_event_list(event_types=MOUSEBUTTONDOWN)
|
||||
else:
|
||||
return get_event_list(event_types=MOUSEBUTTONDOWN,further_check_variable_name="button",further_check_value=button)
|
||||
def action_mouse_click(self,button):
|
||||
pass
|
||||
def check_mouse_click(self):
|
||||
list_temp=get_event_list(event_types=MOUSEBUTTONDOWN)
|
||||
for temp in list_temp:
|
||||
action_mouse_click(temp.button)
|
||||
#mouse get pressed
|
||||
def event_mouse_get_pressed(self,button=None):
|
||||
''' event_mouse_get_pressed() -> tuple looking like (1,0,0) i.e. ( left_click_state, middle_click_state, right_click_state ).
|
||||
Use an index which is (corresponding_constant - 1). For eg event_mouse_get_pressed()[0] returns left click state.
|
||||
event_mouse_get_pressed(button) -> Returns 0 or 1 depending on pressed or not. '''
|
||||
if button==None:
|
||||
return pygame.mouse.get_pressed()
|
||||
else:
|
||||
return pygame.mouse.get_pressed()[button-1] # because the tuple returned has o-based indexing
|
||||
# end of mouse handling
|
||||
# other mouse-based functions
|
||||
def mouse_get_focused(self):
|
||||
return pygame.mouse.get_focused()
|
||||
def mouse_set_visible(self,bool_value):
|
||||
return pygame.mouse.set_visible(bool_value)
|
||||
def mouse_get_rel(self):
|
||||
''' Returns relative movement of the mouse since the last call to this function.
|
||||
mouse_get_rel() -> (x,y) '''
|
||||
return pygame.mouse.get_rel()
|
||||
def mouse_set_cursor_image(self,image=None):
|
||||
pass # todo: complete after the image part is done
|
||||
# implement mouse_pos as variable
|
||||
@property
|
||||
def mouse_pos(self):
|
||||
''' mouse_pos -> (x,y)
|
||||
mouse_pos = [x,y] -> Sets cursor position '''
|
||||
return pygame.mouse.get_pos()
|
||||
@mouse_pos.setter
|
||||
def mouse_pos(self,val):
|
||||
''' val should be a list [x,y] '''
|
||||
if not isinstance(val,list):
|
||||
raise TypeError("val should be a list [x,y]")
|
||||
pygame.mouse.set_pos(val)
|
||||
|
||||
# implement mouse_x as variable
|
||||
@property
|
||||
def mouse_x(self):
|
||||
''' mouse_x -> x
|
||||
mouse_x = some_x -> Sets cursor x position '''
|
||||
return pygame.mouse.get_pos()[0] # get_pos -> (x,y)
|
||||
@mouse_x.setter
|
||||
def mouse_x(self,x):
|
||||
pygame.mouse.set_pos([x,mouse_y])
|
||||
|
||||
# implement mouse_y as variable
|
||||
@property
|
||||
def mouse_y(self):
|
||||
''' mouse_y -> y
|
||||
mouse_y = some_y -> Sets cursor y position '''
|
||||
return pygame.mouse.get_pos()[1] # get_pos -> (x,y)
|
||||
@mouse_y.setter
|
||||
def mouse_y(self,y):
|
||||
pygame.mouse.set_pos([mouse_x,y])
|
||||
# end of mouse-related function
|
||||
#other various events
|
||||
|
||||
def event_intersect_room_boundary(self): # todo: test after image part is done
|
||||
''' Checks if the object (its image bounding box) is intersecting the room boundary, but not totally outside the room.
|
||||
Returns direction constants like TOP, LEFT, BOTTOM, RIGHT. '''
|
||||
if (self.x+self.image.bbox.width/2)>fun_Game.room_width and not (self.x-self.image.bbox.width/2)>fun_Game.room_width:
|
||||
return RIGHT # all constants defined at global level
|
||||
elif (self.y+self.image.bbox.height/2)>fun_Game.room_height and not (self.y-self.image.bbox.height/2)>fun_Game.room_height:
|
||||
return BOTTOM
|
||||
elif (self.x-self.image.bbox.width/2)<0 and not (self.x+self.image.bbox.width/2)<0:
|
||||
return LEFT
|
||||
elif (self.y-self.image.bbox.height/2)<0 and not (self.y+self.image.bbox.height/2)<0:
|
||||
return TOP
|
||||
def action_intersect_room_boundary(self):
|
||||
pass
|
||||
def check_intersect_room_boundary(self):
|
||||
if event_intersect_room_boundary(self):
|
||||
action_intersect_room_boundary(self)
|
||||
|
||||
def event_outside_room_boundary(self):
|
||||
''' Checks if the object (its image bounding box) is totally outside room.
|
||||
Returns direction constants like TOP, LEFT, BOTTOM, RIGHT. '''
|
||||
if (self.x-self.image.bbox.width/2)>fun_Game.room_width:
|
||||
return RIGHT # all constants defined at global level
|
||||
elif (self.y-self.image.bbox.height/2)>fun_Game.room_height:
|
||||
return BOTTOM
|
||||
elif (self.x+self.image.bbox.width/2)<0:
|
||||
return LEFT
|
||||
elif (self.y+self.image.bbox.height/2)<0:
|
||||
return TOP
|
||||
|
||||
# end of fun_Class
|
||||
# Other classes
|
||||
class Circle(object):
|
||||
def __init__(self,(x,y),radius,color=None):
|
||||
self.center=[x,y]
|
||||
self.radius=radius
|
||||
self.color=color
|
||||
|
||||
@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 bbox(self):
|
||||
left=self.center_x-self.radius
|
||||
top=self.center_y-self.radius
|
||||
width=self.radius*2
|
||||
height=self.radius*2
|
||||
return pygame.Rect(left, top, 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 Circle((self.center_x,self.center_y),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
|
||||
|
||||
def inflate(self,inflate_radius):
|
||||
return Circle((self.center_x,self.center_y),self.radius+inflate_radius,self.color)
|
||||
|
||||
def inflate_ip(self,inflate_radius):
|
||||
self.radius+=inflate_radius
|
||||
|
||||
def is_inside(self,another_circle):
|
||||
''' Checks if this circle is fully inside another_circle '''
|
||||
return distance( self.center, another_circle.center )<self.radius
|
||||
|
||||
def is_inside_mutual(self,another_circle):
|
||||
''' Checks if this circle is fully inside another_circle and also the opposite.
|
||||
2x Faster than using is_inside for both of them. '''
|
||||
return (distance( self.center, another_circle.center ) < max( self.radius, another_circle.radius) )
|
||||
|
||||
def collide_circle(self,another_circle):
|
||||
''' Checks if this circle intersects with another_circle. '''
|
||||
return (distance( self.center, another_circle.center ) <= (self.radius + another_circle.radius) )
|
||||
|
||||
def collide_point(self, (point_x, point_y)):
|
||||
''' Checks if (point_x, point_y) is inside this circle. '''
|
||||
return (distance(self.center, (point_x,point_y) ) <= self.radius )
|
||||
|
||||
def collide_list_circle(self, list_circle):
|
||||
''' Checks if this circle intersects with any of the circles in circle_list. '''
|
||||
for circle in list_circle:
|
||||
if collide_circle(self,circle):
|
||||
return True
|
||||
else: #else of the for loop
|
||||
return False
|
||||
|
||||
def collide_list_all_circle(self,list_circle):
|
||||
''' Checks if this circle intersects with all of the circles in circle_list. '''
|
||||
for circle in list_circle:
|
||||
if not collide_circle(self,circle):
|
||||
return False
|
||||
else: #else of the for loop
|
||||
return True
|
||||
|
||||
def collide_rect(self,another_rect):
|
||||
''' Checks if this circle collides with another_rect. '''
|
||||
return 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 )
|
||||
|
||||
def collide_list_rect(self,list_rect):
|
||||
''' Returns True if collides with any of the rect in the list. '''
|
||||
for temp_rect in list_rect:
|
||||
if collide_rect(self,temp_rect):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def collide_list_all_rect(self,list_rect):
|
||||
''' Returns True if collides with all the rect in the list. '''
|
||||
for temp_rect in list_rect:
|
||||
if not collide_rect(self,temp_rect):
|
||||
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)
|
||||
import math
|
||||
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 (as it's not a square)
|
||||
import math
|
||||
return cls(another_rect.center,min(another_rect.width,another_rect.height))
|
||||
|
||||
# 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
|
||||
|
||||
def _unionall(self,circle_1,seq_circle): # list_circle_params : [((x1,y1),radius_1), ((x2,y2),radius_2), ...]
|
||||
''' 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
|
||||
|
||||
# draw functions
|
||||
def draw(self,surface,(x,y)=(None,None),color=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
|
||||
if not color:
|
||||
if self.color:
|
||||
color=self.color
|
||||
else:
|
||||
color=pygame.Color("blue")
|
||||
|
||||
if not use_antialiasing:
|
||||
pygame.draw.circle(surface, color,(x,y), self.radius, width)
|
||||
else:
|
||||
pygame.gfxdraw.aacircle(surface, x, y, self.radius, color)
|
||||
|
||||
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
|
||||
#start of tiltedRect class
|
||||
class tiltedRect(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,(left,top),(width,height),angle,centered_coords=False,color=None):
|
||||
''' Angle in degrees.
|
||||
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 tiltedRect'''
|
||||
self.angle=angle
|
||||
self.color=color
|
||||
if centered_coords==True:
|
||||
left=left-width/2
|
||||
top=top-height/2
|
||||
super(tiltedRect,self).__init__((left,top),(width,height))
|
||||
def __copy__(self):
|
||||
return tiltedRect((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((left,top),(width,height))
|
||||
def move(self,x,y):
|
||||
return self.create_from_rect(super(tiltedRect,self).move(x,y),self.angle)
|
||||
def inflate(self,x,y):
|
||||
return self.create_from_rect(super(tiltedRect,self).inflate(x,y),self.angle)
|
||||
def normalize(self): # not sure what this one does - ask others
|
||||
return self.create_from_rect(super(tiltedRect,self).normalize(),self.angle)
|
||||
def rotate(self,some_angle):
|
||||
temp_return=self.__copy__()
|
||||
temp_return.angle+=some_angle
|
||||
return temp_return
|
||||
def rotate_ip(self,some_angle):
|
||||
self.angle+=some_angle
|
||||
|
||||
def rotate_point_relative(self,x,y,theta=None):#generalise the parameters to accept x1,y1,x2,y2,rot_angle
|
||||
''' 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==None:
|
||||
theta=self.angle
|
||||
return self.rotate_point(x,y,self.centerx,self.centery,theta)
|
||||
|
||||
@classmethod
|
||||
def rotate_point(cls,x,y,origin_x,origin_y,theta): # to be allowed as rotate_point(class)
|
||||
''' 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=-y_diff # -y_diff because of the inverted nature of y co-ordinate system in pygame
|
||||
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==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_relative(temp[0],temp[1])
|
||||
@property
|
||||
def topleft_rotated(self):
|
||||
temp=self.topleft
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def bottomright_rotated(self):
|
||||
temp=self.bottomright
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def topright_rotated(self):
|
||||
temp=self.topright
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def midleft_rotated(self):
|
||||
temp=self.midleft
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def midright_rotated(self):
|
||||
temp=self.midright
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def midtop_rotated(self):
|
||||
temp=self.midtop
|
||||
return self.rotate_point_relative(temp[0],temp[1])
|
||||
@property
|
||||
def midbottom_rotated(self):
|
||||
temp=self.midbottom
|
||||
return self.rotate_point_relative(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=floor(min(list_x))
|
||||
max_x=ceil(max(list_x))
|
||||
min_y=floor(min(list_y))
|
||||
max_y=ceil(max(list_y))
|
||||
return pygame.Rect((min_x,min_y),(max_x-min_x,max_y-min_y))
|
||||
@property
|
||||
def bbox_fixed(self):
|
||||
diagonal=sqrt(self.width**2+self.height**2)
|
||||
diagonal=ceil(diagonal)
|
||||
return pygame.Rect((floor(self.centerx-diagonal/2),floor(self.centery-diagonal/2)),(diagonal+1,diagonal+1)) #diagonal+1 is used to redue corner issues, which still might be here.
|
||||
# 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):
|
||||
Circle.get_incircle_from_rect(self.bbox)
|
||||
|
||||
# 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==None or temp_y==None:
|
||||
raise TypeError("argument must contain two numbers")
|
||||
return pygame.Rect((self.left,self.top),(self.width,self.height)).collidepoint(self.rotate_point_relative(temp_x,temp_y))
|
||||
|
||||
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 draw(self,surface,(x,y)=(None,None),color=None,width=1,centered=False,use_antialiasing=False,blend=True):
|
||||
''' Draws this tiltedRect on surf_to_draw_on. It must be of width and height greater or equal to its bbox.
|
||||
(x,y)->co-ordinates whether the lefttop point of its bbox should be drawn on the surface. Use centered=True to provide co-ords of the center instead.
|
||||
If centered=True, by default, it draws at the center of the surface provided.
|
||||
width argument doesnt work with antialiasing. width=0 makes it filled.
|
||||
blend argument works only with antialiasing. The boolean blend argument set to true will blend the shades with existing shades instead of overwriting them.
|
||||
color falls back first to tiltedRect.color (if present) and then to blue color.'''
|
||||
if not centered:
|
||||
if (x,y)==(None,None):
|
||||
(x,y)=(0,0)
|
||||
iter_corners=[(temp[0]+x-self.bbox.left,temp[1]+y-self.bbox.top) for temp in self.corners]
|
||||
else:
|
||||
if (x,y)==(None,None):
|
||||
x,y=surface.get_width()/2,surface.get_height()/2
|
||||
iter_corners=[(temp[0]+x,temp[1]+y) for temp in self.corners_relative]
|
||||
if not color:
|
||||
if self.color:
|
||||
color=self.color
|
||||
else:
|
||||
color=pygame.Color("blue")
|
||||
if not use_antialiasing:
|
||||
pygame.draw.polygon(surface, color, iter_corners, width)
|
||||
#pygame.gfxdraw.polygon(surface, iter_corners, color)#gfxdraw module doesnt work
|
||||
else:
|
||||
pygame.draw.aalines(surface, color, True, iter_corners, blend)
|
||||
def get_surface(self,surface=None,flags=0,fixed=False):
|
||||
''' Returns a new surface with dimensions of (tiltedRect.bbox.width,tiltedRect.bbox.width) and other properties as surface.
|
||||
This tiltedRect can be safely drawn on it.'''
|
||||
if not fixed:
|
||||
width,height=self.bbox.width,self.bbox.height
|
||||
else:
|
||||
width,height=self.bbox_fixed.width,self.bbox_fixed.height
|
||||
|
||||
return pygame.Surface((width,height),flags,surface)
|
||||
def get_surface_drawn(self,(x,y)=(None,None),color=None,width=1,fixed=False,use_antialiasing=False,blend=True,surface=None,flags=0):
|
||||
''' Returns a surface which has the tiltedRect drwan on it. '''
|
||||
temp_surf=self.get_surface(surface,flags,fixed)
|
||||
if not fixed:
|
||||
self.draw(temp_surf,(x,y),color,width,False,use_antialiasing,blend)
|
||||
else:
|
||||
self.draw(temp_surf,(x,y),color,width,True,use_antialiasing,blend)
|
||||
return temp_surf
|
||||
|
||||
def collide_tiltedRect(self,another_tiltedRect):
|
||||
'''Checks whether this tiltedRect collides with another_titltedrect, which must be a instance of titledRect. '''
|
||||
# Rotates both tiltedRect by -another_tiltedRect.angle. So, another_tiltedRect becomes a Rect called temp_Rect.
|
||||
# Then check if the rotated version of this tiltedRect (temp_tiltedRect) collides with the obtained Rect.
|
||||
temp_tiltedRect=self.rotate(-another_tiltedRect.angle)
|
||||
temp_Rect=another_tiltedRect.get_rect()
|
||||
return temp_tiltedRect.colliderect(temp_Rect)
|
||||
|
||||
# functions outside all classes
|
||||
def get_event_list(event_types=None,further_check_variable_name=None,further_check_value=None,list_to_get=None):#list_to_get is attached to a constant list here
|
||||
''' 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==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__"):
|
||||
event_types=[event_types] # if not iterable, make a list out of it
|
||||
def func_filter():
|
||||
list_return=[]
|
||||
if not event_types:
|
||||
return list_to_get
|
||||
for temp_1 in list_to_get: # all events in fun_Game.list_event have a "type" property
|
||||
for temp_2 in event_types:
|
||||
if temp_1.type==temp_2:
|
||||
list_return.append(temp_1)
|
||||
return list_return
|
||||
def further_check_filter(temp_list): # returns part of temp_list which passes further_check
|
||||
list_return=[]
|
||||
if further_check_enabled:
|
||||
for temp in temp_list:
|
||||
if getattr(temp,further_check_variable_name)==further_check_value:# may raise error if further_check_variable_name is not present for all members of the list
|
||||
list_return.append(temp)
|
||||
else:
|
||||
list_return=temp_list
|
||||
return list_return
|
||||
return further_check_filter(func_filter()) # returns elements common in fun_Game.list_events and events which are accepted after further_check
|
||||
# end of get_event_list()
|
||||
|
||||
def distance((x1,y1),(x2,y2)): # Maybe make a non-square rooted function for comparison (faster)
|
||||
import math
|
||||
return(math.sqrt((x2-x1)**2+(y2-y1)**2))
|
||||
|
||||
#following constants are required for the next function
|
||||
UNION=1
|
||||
INTERSECTION=2
|
||||
DIFFERENCE=3
|
||||
ADD=4
|
||||
MAKE_IT_VARIABLE_LIST=5 # for each member (usually objects) in the list, it is replaced by one of its variables
|
||||
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==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==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==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==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
|
||||
def make_it_variable_list(): # for each member (usually objects) in the list, it is replaced by one of its variables
|
||||
if variable_name==None:
|
||||
raise TypeError("variable_name should be a string")
|
||||
if not list2==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()
|
||||
#Todo: see below
|
||||
# 1. Allow rect-like and circle-like constructs wherever rect and circle are expected.
|
||||
# 2. Do all sort of type-checking.
|
||||
# Design tips I will use later
|
||||
# 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
|
||||
Reference in New Issue
Block a user