def update(self, image, basePos, width, height): xb, yb = basePos if self.ship.armor != self.hp1: if abs(self.ship.armor - self.hp1) > 5: # new damage self.hp2 = self.hp1 self.hp1 = self.ship.armor self.t = 0 else: self.hp1 = self.ship.armor if self.t < self.maxT1: if self.t + self.dt >= self.maxT1: self.dhp = (self.hp1 - self.hp2) / (self.maxT2 - self.maxT1) elif self.t < self.maxT2: self.hp2 += self.dhp * self.dt else: self.hp2 = self.hp1 self.t += self.dt hp1, hp2 = self.hp1, self.hp2 rect = Rect((0, 0), (width, hp1/config.MaxArmor * height)) rect.bottomleft = (xb, yb) pygame.draw.rect(image, self.HPColor, rect) if hp1 < hp2: rect.size = (width, (hp2 - hp1)/config.MaxArmor * height) rect.bottomleft = (xb,1 + yb - hp1/config.MaxArmor * height) pygame.draw.rect(image, self.HPColorDamage, rect)
def replace_draw(self, screen, camera_offset=(0, 0)): if self.image is None: return if self.ignore_offset: x = self._draw_position[0] y = self._draw_position[1] else: x = self._draw_position[0] - camera_offset[0] y = self._draw_position[1] - camera_offset[1] camera_offset = camera_offset[0], camera_offset[1] rect = self.image.get_rect(topleft=self._draw_position) rect.move_ip(0, 0) screen_rect = screen.get_rect(topleft=camera_offset) overlap = screen_rect.clip(rect) overlap.move_ip(-camera_offset[0], -camera_offset[1]) #0 is to left #> is to right corner = overlap.topleft area = Rect(0, 0, 0, 0) area.size = overlap.size if corner[0] == 0: area.x = -x else: area.x = 0 if corner[1] == 0: area.y = -y else: area.y = 0 screen.blit(self.image, overlap, area)
def view_port(self): w, h = pygame.display.get_surface().get_size() width = 5000 / self.zoom_level height = width*(h/w) view_port = Rect(0, 0, 0, 0) view_port.size = (width+1, height+1) # +1 to prevent white bars at the bottom or right view_port.center = self.pos return view_port
def get_object_global_rect(self, obj: BoardObject): """.""" if not hasattr(obj.original, "image"): return None rect = Rect((0, 0, 0, 0)) rect.size = math2d.v_mul(obj.original.image.get_size(), 1 / self.__scale) rect.center = self.to_global(obj.position) return rect
def test_size(self): "Changing the size resizes the rect from the top-left corner" r = Rect(1, 2, 3, 4) new_size = (10, 20) old_topleft = r.topleft r.size = new_size self.assertEqual(new_size, r.size) self.assertEqual(old_topleft, r.topleft)
def test_size( self ): "Changing the size resizes the rect from the top-left corner" r = Rect( 1, 2, 3, 4 ) new_size = (10,20) old_topleft = r.topleft r.size = new_size self.assertEqual( new_size, r.size ) self.assertEqual( old_topleft, r.topleft )
def _update (self, col, row, tile_type_id, tile_rect=None): if self._cache_graphic: if tile_type_id in self._cache: g = self._cache[tile_type_id] else: g = self._type_to_graphic(tile_type_id) self._cache[tile_type_id] = g else: g = self._type_to_graphic(tile_type_id) dest = self._orig_sfc if tile_rect is None: tile_rect = self.grid.tile_rect(col, row) if isinstance(g, (Graphic, pg.Surface, basestring)): g = (g,) if (g is not None and isinstance(g[0], (Graphic, pg.Surface, basestring))): sfc = g[0] if isinstance(sfc, basestring): sfc = self._load_img(sfc) elif isinstance(sfc, Graphic): sfc = sfc.surface if len(g) == 1: alignment = rect = None else: if isinstance(g[1], int) or len(g[1]) == 2: alignment = g[1] rect = None else: alignment = None rect = g[1] if len(g) == 3: if rect is None: rect = g[2] else: alignment = g[2] if alignment is None: alignment = 0 if rect is None: rect = sfc.get_rect() # clip rect to fit in tile_rect dest_rect = Rect(rect) dest_rect.center = tile_rect.center fit = dest_rect.clip(tile_rect) rect = Rect(rect) rect.move_ip(fit.x - dest_rect.x, fit.y - dest_rect.y) rect.size = dest_rect.size # copy rect to tile_rect with alignment pos = gameutil.align_rect(rect, tile_rect, alignment) dest.blit(sfc, pos, rect) else: if g is None: g = (0, 0, 0, 0) # now we have a colour dest.fill(gameutil.normalise_colour(g), tile_rect) return tile_rect
def on_msg(self, data): msgtype, name = data['msg_type'], data['name'] global myname, mybox if msgtype == 'welcome': for state in data['pellets']: # create all pellets left, top, width, height = tuple(state) pellets.append(Rect(left, top, width, height)) for pname, state in data['players'].items(): # create all players left, top, width, height = tuple(state) players[pname] = Rect(left, top, width, height) myname, mybox = name, players[name] elif msgtype == 'join' and name != myname: # ignore my join message left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) elif msgtype == 'leave': del players[name] elif msgtype == 'move' and name != myname: # ignore my move messages if players[name]: # other player is not dead locally left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) elif msgtype == 'eat_pellet': if players[name]: # None if I haven't receive his die msg yet players[name].size = tuple(data['size']) pellets[data['pellet_index']] = data['new_pellet'] elif msgtype == 'grow': players[name].size = tuple(data['size']) elif msgtype == 'die': left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) if name == myname: mybox = players[myname]
def on_msg(self, data): msgtype, name = data['msg_type'], data['name'] global myname, mybox if msgtype == 'welcome': for state in data['pellets']: # create all pellets left, top, width, height = tuple(state) pellets.append(Rect(left, top, width, height)) for pname, state in data['players'].items(): # create all players left, top, width, height = tuple(state) players[pname] = Rect(left, top, width, height) myname, mybox = name, players[name] elif msgtype == 'join' and name != myname: # ignore my join message left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) elif msgtype == 'leave': del players[name] elif msgtype == 'move' and name != myname: # ignore my move messages if players[name]: # other player is not dead locally left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) elif msgtype == 'eat_pellet': if players[name]: # None if I haven't receive their die msg yet players[name].size = tuple(data['size']) pellets[data['pellet_index']] = data['new_pellet'] elif msgtype == 'grow': players[name].size = tuple(data['size']) elif msgtype == 'die': left, top, width, height = tuple(data['state']) players[name] = Rect(left, top, width, height) if name == myname: mybox = players[myname]
def __init__(self, game_objects, rect: pygame.Rect, image: pygame.Surface = None): super().__init__() self.rect = rect if image: rect.size = image.get_rect().size else: image = pygame.Surface(rect.size) self.image = image self.area = None self.components = dict() self.real_x = self.rect.x self.real_y = self.rect.y self.game_objects = game_objects
scale /= 1.1 else: redraw = False if redraw: if scale < screen_size[0]/env_size[0]: scale = screen_size[0]/env_size[0] if scale > 16000/env_size[0]: scale = 16000/env_size[0] size = (int(env_size[0]*scale), int(env_size[1]*scale)) background = Surface(size) pygame.draw.rect(background, (255,255,255), Rect((0,0), size)) tree.draw(background, pygame.font.SysFont("Calibri", int(11*scale)), size, scale) mouse_pose = pygame.mouse.get_pos() background_mouse_pose = (mouse_pose[0]-background_dimensions.left, mouse_pose[1]-background_dimensions.top) current_scale = scale/prev_scale background_dimensions.move_ip(int(-background_mouse_pose[0]*(current_scale-1)), int(-background_mouse_pose[1]*(current_scale-1))) background_dimensions.size = size x = background_dimensions.width-2000 y = background_dimensions.height-750 background_dimensions.clamp_ip(Rect(-x, -y, 2000+2*x, 750+2*y)) screen.blit(background, background_dimensions) pygame.display.update() prev_scale = scale pygame.quit()
class Camera(Component, IDrawer): """ Class that represents a camera in game. This class is a initial simple camera. In future, hopefully, this will have lots of more features. A camera is used to draw just a portion of a level or object. A scene can have multiple Cameras. A camera will draw all objects that it is on sight (inside the rect that represents this camera). The camera itself doesn't have to fill all screen (it does by default), it can fill just a portion of the screen by changing its size and position. """ def __init__(self, size=(0, 0)): super(Camera, self).__init__() self._rect = Rect() self._rect.size(size) def in_sight(self, game_object): """ Validate if a game object is visible by this camera. :param game_object: Game object to validate if it is on sight :return: True if it is visible. False otherwise. """ return game_object.get_component(IDrawable) is not None and self.transform.collidedict( game_object.get_component(IDrawable).get_rect) def update(self): self._rect.x = self.transform.x self._rect.y = self.transform.y def draw(self): """ Draws a game object (only when 'in_camera' is true) using this camera. """ game_objects_drawable = Game.instance().scene.get_drawables for game_object in game_objects_drawable: self.draw_game_object(game_object, True) def draw_game_object(self, game_object, validate_in_camera=True): """ Draw a game object using this camera. :param game_object: Game object to be draw. :param validate_in_camera: If true, only draws the object if 'in_sight' is True. """ if not validate_in_camera and self.in_sight(game_object) and game_object.get_component(IDrawable).is_drawing: pass Game.instance().surface.blit(game_object.get_component(IDrawable).drawable, game_object.get_component(IDrawable).get_rect, game_object.get_component(IDrawable).get_rect.clip(self._rect)) @property def size(self): return self._rect.size @size.setter def size(self, size): self._rect = size def full_surface(self): self.transform.x = 0 self.transform.y = 0 self.transform.width = Configuration.instance().screen_size.width self.transform.height = Configuration.instance().screen_size.height
def main(): init() running = True size = 1000, 1000 # these are the width and height of the simulation grid grid_x, grid_y = int(argv[1]), int(argv[2]) # this is how many pixels per cell in the simulation grid # We need to use the grid factor because the pygame window is not # the same width and height of the simulation grid size. Therefore, # we scale the pygame window down to fit the simulation size grid_factor_x, grid_factor_y = 1000 / grid_x, 1000 / grid_y screen = display.set_mode(size) # used to track either the setting of the topleft of a rectangle, # or the bottom right (if bottom right, the rectangle is completed) num_clicks_patch = 0 num_clicks_patch_temp = 0 num_clicks_exit = 0 num_clicks_exit_temp = 0 # the position of the mouse when the left or right mouse button is clicked mouse_pos_patch = () mouse_pos_exit = () # the position of the patch's top left corner in pixels patch_tl = () # the position of the patch's bottom right corner in pixels patch_br = () # the position of the exits's top left corner in pixels exit_tl = () # the position of the exits's bottom right corner in pixels exit_br = () patch_temp = Rect(-1, -1, 0, 0) exit_temp = Rect(-1, -1, 0, 0) # a list of patches as pygame rectangles that are being displayed # on screen patch_list = [] # a list of patches removed from the screen. The user can recall these # with a keybind patch_discard_list = [] # a list of exits as pygame rectangles that are being displayed # on screen exit_list = [] # a list of exits removed from the screen. The user can recall these # with a keybind exit_discard_list = [] # a list of 1 pixel-wide pygame rectangles that are drawn to the screen # to create grid lines gridline_list = [] # populate `gridline_list` gridline_list = populate_gridline_list(gridline_list, grid_x, grid_y, grid_factor_x, grid_factor_y) # main game loop will run until the user clicks the exit button in the top right corner (Windows) while running: # event loop for pygame_event in event.get(): # if the user hits the window's exit button, stop the app if pygame_event.type == QUIT: running = False # if the user hits the mouse button in the app window if pygame_event.type == MOUSEBUTTONDOWN and mouse.get_focused(): # return a list of booleans for the three major buttons on a mouse: # left mouse, right mouse, and middle mouse. If an element is True, # the corresponding button is pressed mouse_depressed = mouse.get_pressed(num_buttons=3) # if the user clicks ONLY the left mouse button, they are creating # a patch. if mouse_depressed[0] and not mouse_depressed[2]: # get the mouse's position with respect to the window mouse_pos_patch = mouse.get_pos() num_clicks_patch += 1 num_clicks_patch_temp = num_clicks_patch # if the user clicks ONLY the right mouse button, they are creating # an exit. if mouse_depressed[2] and not mouse_depressed[0]: mouse_pos_exit = mouse.get_pos() num_clicks_exit += 1 num_clicks_exit_temp = num_clicks_exit if pygame_event.type == KEYDOWN and key.get_focused(): # return a list of booleans for all the keys on the keyboard # If an element is True, the corresponding key is pressed keys_depressed = key.get_pressed() # if the user presses CTRL+Z, remove the previously added patches # from most recent to least recent if keys_depressed[K_LCTRL] and keys_depressed[ K_z] and not keys_depressed[K_LSHIFT]: # if the user has begun to create a new patch, they can # cancel it by hitting CTRL+Z. Otherwise, CTRL+Z removes a # patch that has already been drawn if patch_list and num_clicks_patch == 0: patch_discard_list.append(patch_list.pop()) print("Number of patches:", len(patch_list)) else: patch_tl = () num_clicks_patch = 0 num_clicks_patch_temp = 0 print("Undid patch topleft!") # if the user pressed CTRL+SHIFT+Z, remove the previously added exits # from most recent to least recent elif keys_depressed[K_LSHIFT] and keys_depressed[ K_LCTRL] and keys_depressed[K_z]: # if the user has begun to create a new exit, they can # cancel it by hitting CTRL+SHIFT+Z. Otherwise, CTRL+SHIFT+Z removes a # exit that has already been drawn if exit_list and num_clicks_exit == 0: exit_discard_list.append(exit_list.pop()) print("Number of exits:", len(exit_list)) else: exit_tl = () num_clicks_exit = 0 num_clicks_exit_temp = 0 print("Undid exit topleft!") # if the user presses CTRL+Y, restore the previously removed patch # from the discard patch list from most recent to least recent if keys_depressed[K_LCTRL] and keys_depressed[ K_y] and not keys_depressed[K_LSHIFT]: # the user can only restore a deleted patch if they haven't # started drawing another one. Easy fix for this: press CTRL+Z # to undo the topleft of the already-begun patch, then do CTRL+Y if patch_discard_list and num_clicks_patch == 0: patch_list.append(patch_discard_list.pop()) print("Number of patches:", len(patch_list)) # if the user pressed CTRL+SHIFT+Y, restore the previously removed exit # from the discard exit list from most recent to least recent elif keys_depressed[K_LSHIFT] and keys_depressed[ K_LCTRL] and keys_depressed[K_y]: # the user can only restore a deleted exit if they haven't # started drawing another one. Easy fix for this: press CTRL+SHIFT+Z # to undo the topleft of the already-begun exit, then do CTRL+SHIFT+Y if exit_discard_list and num_clicks_exit == 0: exit_list.append(exit_discard_list.pop()) print("Number of exits:", len(exit_list)) # if the user has clicked the mouse once, store the mouse position # as the top left of the rectangle to be drawn if num_clicks_patch_temp == 1: patch_tl = mouse_pos_patch num_clicks_patch_temp = 0 patch_temp.topleft = patch_tl print("Patch topleft set at", patch_tl) # if the user has clicked the mouse for the second time, elif num_clicks_patch_temp == 2: patch_br = mouse_pos_patch patch_list.append( Rect(patch_tl[0], patch_tl[1], patch_br[0] - patch_tl[0], patch_br[1] - patch_tl[1])) num_clicks_patch = 0 num_clicks_patch_temp = 0 print("Number of patches:", len(patch_list)) # if the user has clicked the mouse once, store the mouse position # as the top left of the rectangle to be drawn if num_clicks_exit_temp == 1: exit_tl = mouse_pos_exit num_clicks_exit_temp = 0 exit_temp.topleft = exit_tl print("Exit topleft set at", exit_tl) # if the user has clicked the mouse for the second time, elif num_clicks_exit_temp == 2: exit_br = mouse_pos_exit exit_list.append( Rect(exit_tl[0], exit_tl[1], exit_br[0] - exit_tl[0], exit_br[1] - exit_tl[1])) num_clicks_exit = 0 num_clicks_exit_temp = 0 print("Number of exits:", len(exit_list)) # first blacken the screen screen.fill("black") # draw the grid lines for gridline in gridline_list: draw.rect(screen, "blue", gridline) # draw the patches on top of the grid lines for patch in patch_list: patch.normalize() draw.rect(screen, "white", patch, width=1) # then draw the exits over the grid lines and patches for exit in exit_list: exit.normalize() draw.rect(screen, "red", exit) # if the user has clicked to begin drawing either a patch # or an exit, display the box growing and shrinking as they # move their mouse so they can see what the patch/exit will look # like when it's drawn if num_clicks_patch == 1: patch_temp.size = tuple( map(sub, mouse.get_pos(), patch_temp.topleft)) # we'll use `patch_temp_copy` to display a proper rectangle if the user defines # `patch_temp`'s topleft and then moves the mouse above or farther left than # that point. Doing so creates a negative width/height in the rectangle which # does not draw to the screen without glitching. Normalizing the rectangle # removes the negative width/height and reassigns the topleft point in the process. # Without using a copy of `patch_temp`, its top left would change every game loop, # and the rectangle would not change with mouse movement correctly. If this # description doesn't make sense, just trust me. If you're the kind of person # who likes to define the bottom right corner first, this code lets you see # that normalized (looks like a rectangle, not a cross road) rectangle change # size as your mouse moves around :D patch_temp_copy = Rect(-1, -1, 0, 0) # I have to define `patch_temp_copy` like this instead of `patch_temp_copy = patch_temp` # since that would just make `patch_temp_copy` an alias of `patch_temp` patch_temp_copy.topleft = patch_temp.topleft patch_temp_copy.size = patch_temp.size patch_temp_copy.normalize() draw.rect(screen, "white", patch_temp_copy, width=1) print(patch_temp_copy.size, " ", end='\r') if num_clicks_exit == 1: # same theory as with `patch_temp_copy` so I'm not gonna repeat it... exit_temp.size = tuple(map(sub, mouse.get_pos(), exit_temp.topleft)) exit_temp_copy = Rect(-1, -1, 0, 0) exit_temp_copy.topleft = exit_temp.topleft exit_temp_copy.size = exit_temp.size exit_temp_copy.normalize() draw.rect(screen, "red", exit_temp_copy) print(exit_temp_copy.size, " ", end='\r') # this updates the contents of the surface display.flip() # if the user has clicked the exit button, ask them if they either want to create # the terrain or completely exit the editor. Give them a second chance if they # want to quit. That way they don't accidentally lose their progress. if not running: response = input( "Would you like to create the terrain with this model? (y/n) ") if response == 'y': # create the terrain grid from the rectangles drawn in the pygame window terrain_grid = create_terrain_grid(patch_list, exit_list, grid_x, grid_y, grid_factor_x, grid_factor_y) # draw converted rectangles to the .txt file output_to_file(grid_x, grid_y, terrain_grid) # save the pygame screen as a .png to use as the background image of the simulation # visualization .gif save_screen_as_bkgr(screen) # update the patches document in the `params.json` file update_patches(patch_list, grid_factor_x, grid_factor_y) elif response == 'n': second_response = input("Are you sure? (Y/N) ") if second_response == "Y": print("Quitting terrain editor.") elif second_response == "N": running = True print("Continuing terrain editor.") else: running = True print( "Invalid response ('Y' or 'N' only, please). Continuing terrain editor." ) else: running = True print( "Invalid response ('y' or 'n' only, please). Continuing terrain editor." ) quit()