def _produce_statics_for_mid_grids(mid_grid, tileset_seq, grid_width, grid_height): # To get proper depth, we need to sort and render each full 'object' separately. # This function automatically produces objects, one for each set of horizontally touching tiles. # list of uneaten tiles uneaten = [] for layer_name, layer_grid in mid_grid.iteritems(): for y in range(grid_height): for x in range(grid_width): if layer_grid[y][x] != -1: uneaten.append((x, y, int(layer_name[3:] or '0'), layer_grid[y][x])) # find groups of horizontally touching tiles touching = {} for x, y, d, t in uneaten: eaten = False r = rect.Rect((x * TILE_SIZE, y * TILE_SIZE), (TILE_SIZE, TILE_SIZE)) for maybe_rect, maybe_friends in touching.iteritems(): # horizontal touching! if rect.Rect(*maybe_rect).inflate(2, 0).colliderect(r): eaten = (maybe_rect, maybe_friends) break if eaten: del touching[maybe_rect] maybe_friends.append((x, y, d, t)) touching[rect.Rect( *maybe_rect).union(r).to_tuple()] = maybe_friends else: touching[r.to_tuple()] = [(x, y, d, t)] # TODO: tiles might not be joined optimally. e.g. consider block growing left and block # growing right - even though they're touching, they started out not touching, so they # are separate in the list. # produce StaticObjects from groups of touching tiles static_objects = [] for k, v in touching.iteritems(): r = rect.Rect(*k) static_objects.append( static_object.StaticObject( r.x, r.y, r.width, r.height, _render_static(r, v, tileset_seq, grid_width, grid_height))) return static_objects
def check_object_click(self, pos, typ, button=None): if typ == 'down': if pos[0] > LEVEL_WIDTH or pos[1] > LEVEL_HEIGHT: # don't check for object outside of level area return for o_name, o in self.game.objects.iteritems(): if o == self.game.cursor: continue st = SELECTION_TOLERANCE temp_rect = rect.Rect((o.coord[0] - st, o.coord[1] - st), (o.dimensions[0] + 2*st, o.dimensions[1] + 2*st)) if temp_rect.collidepoint(self.game.camera.undo_camera(pos)): if self.object_capture_request: self.object_capture_request = False self.object_capture_function(o_name) elif isinstance(o, character.Character): self.game.disp_object_stats = True self.game.object_stats = o.info_sheet self.game.selected_object = o if self.game.state == EDITOR: self.game.editor.handle_object_click(o_name) self.interaction_this_click = True return self.game.selected_object = None self.game.disp_object_stats = False self.game.object_stats = None self.game.editor.object_to_edit_selected(None)
def create_new_zone(self): trig = self.drop_lists['triggers'].selected if trig is None: return zone = rect.Rect((0, 0), (1, 1)) trig.add_zone(zone) self.drop_lists['zones'].refresh() self.drop_lists['zones'].set_to_value(zone)
def draw_torch(self): # TODO: do this in a sane/clever way ppos = (self.game.players['player1'].coord[0] + self.game.players['player1'].dimensions[0] // 2, self.game.players['player1'].coord[1] + self.game.players['player1'].dimensions[1] // 2) hole = rect.Rect( self.game.camera.apply_camera((ppos[0] - self.light_size[0] // 2, ppos[1] - self.light_size[1] // 2)), self.light_size) hole.width *= self.game.camera.zoom hole.height *= self.game.camera.zoom self.light.scale_x = (200 / self.light.image.height) * self.game.camera.zoom self.light.scale_y = (200 / self.light.image.height) * self.game.camera.zoom self.light.position = hole.bottomleft self.game.screen_objects_to_draw.append( primitives.RectPrimitive(x=0, y=0, width=hole.right, height=hole.bottom, color=(0, 0, 0, 255))) self.game.screen_objects_to_draw.append( primitives.RectPrimitive(x=hole.right, y=0, width=window.width - hole.right, height=hole.top, color=(0, 0, 0, 255))) self.game.screen_objects_to_draw.append( primitives.RectPrimitive(x=hole.left, y=hole.top, width=window.width - hole.left, height=window.height - hole.top, color=(0, 0, 0, 255))) self.game.screen_objects_to_draw.append( primitives.RectPrimitive(x=0, y=hole.bottom, width=hole.left, height=window.height - hole.bottom, color=(0, 0, 0, 255))) self.game.screen_objects_to_draw.append(self.light)
def _produce_collision(mid_layers, width, height): coll_grid = [[(False, None) for i in range(width)] for j in range(height)] for ml_name, ml in mid_layers.iteritems(): for y in range(height): for x in range(width): if ml[y][x] != -1: coll_grid[y][x] = (True, rect.Rect( (x * TILE_SIZE, y * TILE_SIZE), (TILE_SIZE, TILE_SIZE))) return coll_grid
def load_from_dict(self, d): self.options = json.loads(d[u'options']) self.object_references = d[u'object_references'] self.interaction_type = d[u'interaction_type'] zones = [] for tup_string in d[u'zones']: # expected format is json((x, y), (w, h)) tup = json.loads(tup_string) z = rect.Rect(tup[0], tup[1]) zones.append(z) self.zones = zones actions = json.loads(d[u'actions']) action_funcs = [trigger_functions_dict[a] for a in actions] for a in action_funcs: self.add_action(a) self.enable_for_objects()
def __init__(self, tile_type_grid, coll_grid, m, pos): x, y = pos tile_ref = tile_type_grid[y][x] if tile_ref != -1: self.tileset_coord = ((m.tileset_rows - 1) - tile_ref // m.tileset_cols, tile_ref % m.tileset_cols) else: self.tileset_coord = (m.tileset_rows - 1, 0) self.tile_ref = tile_ref self.rect = rect.Rect((x * TILE_SIZE, y * TILE_SIZE), (TILE_SIZE, TILE_SIZE)) if coll_grid and coll_grid[y][x]: self.walkable = False elif self.tile_ref == -1: self.walkable = False else: self.walkable = True
def __init__(self, game, object_refs, actions=None): Trigger.__init__(self, game, object_refs, actions) self._pos = (0, 0) self._size = (1, 1) self.zone = rect.Rect(self._pos, self._size)
def size(self, s): self._size = s self.zone = rect.Rect(self._pos, self._size)
def pos(self, p): self._pos = p self.zone = rect.Rect(self._pos, self._size)
def __init__(self, x, y, w, h, texture): self.rect = rect.Rect((x, y), (w, h)) self.sprite = sprite.Sprite(texture, x=x, y=y) self.coord = (x, y) self.flair = {}
def __init__(self, game_class, x, y, w, h, sprite_sheet=None, sprite_width=32, sprite_height=32): """ To add an object to a map: map.objects['object name'] = object Object states: Each state has a name (consider using integers if you want to advance through them sequentially) Each state is a dict of properties that the object will update to when state_index is changed to that state name Ensure that these properties are spelt correctly! To change state elsewhere, just set object.state_index = <state_name_here>, properties will automatically update Flair: Flair is a dict of 'name': (surface, position (relative to object centre)) to additionally render attached to sprite E.g. Hats, speech bubbles. Collision: Each object has a collision_weight. Objects can only push objects with equal or less weight. Objects can only push a chain of objects up to their own weight. If an objects' collision weight is 0, it does not collide with objects. Collision rectangle updates automatically if you change obj dimensions (or coord). """ self.game_class = game_class self.states = {'state1': {'max_speed': 1, 'fear_radius': 50}, 'state2': {'max_speed': 5, 'fear_radius': 150}} self._state_index = 'state1' self._coord = (x, y) # top left self._dimensions = (w, h) self.velocity = (0, 0) self.min_speed = 0 self.current_speed = 0 self.normal_speed = 0 self.feared_speed = 0 self.fear_radius = 50 self.scared_of = [] self.fears = FearsList(self) self.rect = rect.Rect(self.coord, self.dimensions) self.update_timer = 40 self.fear_timer = 0 self.scream_timer = 0 self.fear = 0 self.scream_thresh = 50 #variables for animation if sprite_sheet is not None: self.sprite_sheet_name = sprite_sheet else: self.sprite_sheet_name = 'DudeSheet.png' self.sprite_sheet = image.load(os.path.join(CHARACTERS_DIR, self.sprite_sheet_name)) # disable texture filtering texture = self.sprite_sheet.get_texture() gl.glBindTexture(texture.target, texture.id) gl.glTexParameteri(texture.target, gl.GL_TEXTURE_MAG_FILTER, gl.GL_NEAREST) gl.glBindTexture(texture.target, 0) self._animation_state = 0 self.sprite_height = sprite_height self.sprite_width = sprite_width self._animations = [] self._create_animations() self.sprite = sprite.Sprite(self._animations[self._animation_state], x=self._coord[0], y=self._coord[1]) #trigger functions self.has_touched_function = [] self.is_touched_function = [] self.has_untouched_function = [] self.is_untouched_function = [] self.move_up = False self.move_down = False self.move_left = False self.move_right = False self.highlight_radius = 20 self.flair = {} self.collision_weight = 1 # set to 0 for no collision, can only push things that are lighter, or same weight self.cutscene_controlling = [] self.path = []
def movePx(self, x_dir, y_dir): self.remove_self_from_touching_list() collision = False # collide againt map boundaries pro_pos = (self.coord[0] + x_dir, self.coord[1] + y_dir) pro_rect = rect.Rect(pro_pos, self.dimensions) if pro_pos[0] >= 0 and pro_pos[0] + self.dimensions[0] <= LEVEL_WIDTH and \ pro_pos[1] >= 0 and pro_pos[1] + self.dimensions[1] <= LEVEL_HEIGHT: pass else: collision = True # collision detection against map tiles # NOTE: assumes largest object w/ collision is 64x64 (i.e. 2x2 tiles) if pro_pos[0] >= 0 and pro_pos[1] >= 0: i = pro_pos[0] // TILE_SIZE # get the index of the lower left tile j = pro_pos[1] // TILE_SIZE else: i = 0 j = 0 # check collision against the 9 possible tiles surrounding object for ni in range(i, i + 2): for nj in range(j, j + 2): if 0 <= ni < LEVEL_WIDTH // TILE_SIZE and 0 <= nj < LEVEL_HEIGHT // TILE_SIZE: if self.game_class.map.coll_grid[nj][ni][0]: # pygame.draw.rect(self.game_class.surface, (200, 0, 0), self.rect) # pygame.draw.rect(self.game_class.surface, (0, 200, 0), self.game_class.map.grid[ni][nj].rect) # pygame.display.update() # time.sleep(0.1) # TODO: make collision use (row,col) if pro_rect.colliderect(self.game_class.map.coll_grid[nj][ni][1]): collision = True # print('collision!') search_rect = pro_rect.union(self.rect) # collision against other objects for o in set(self.game_class.object_collision_lookup.candidates_for(search_rect)): if not o is self: if o.collision_weight and self.collision_weight: # check if obj collides at all if pro_rect.colliderect(o.rect) and not self.rect.colliderect(o.rect): if 1 + self.collision_weight < o.collision_weight: # check if obj can be pushed by self collision = True else: # push object temp = o.collision_weight o.collision_weight = (self.collision_weight - o.collision_weight) or -1 # allows to push chain of objs collision = collision or o.movePx(x_dir, y_dir) # collsion of self is dependent on whether obj collided o.collision_weight = temp if not (self, o) in self.game_class.touching: self.game_class.touching.append((self, o)) # (toucher, touchee) if not collision: self.coord = pro_pos return collision
def dimensions(self, new): self._dimensions = new self.rect = rect.Rect(self.coord, self.dimensions)
def coord(self, new): self._coord = new self.rect = rect.Rect(self.coord, self.dimensions) self.sprite.position = new self.game_class.object_collision_lookup.update_for(self)