def _check_for_collision(sprite1: Sprite, sprite2: Sprite) -> bool: """ Check for collision between two sprites. :param Sprite sprite1: Sprite 1 :param Sprite sprite2: Sprite 2 :returns: True if sprites overlap. :rtype: bool """ collision_radius_sum = sprite1.collision_radius + sprite2.collision_radius diff_x = sprite1.position[0] - sprite2.position[0] diff_x2 = diff_x * diff_x if diff_x2 > collision_radius_sum * collision_radius_sum: return False diff_y = sprite1.position[1] - sprite2.position[1] diff_y2 = diff_y * diff_y if diff_y2 > collision_radius_sum * collision_radius_sum: return False distance = diff_x2 + diff_y2 if distance > collision_radius_sum * collision_radius_sum: return False return are_polygons_intersecting(sprite1.get_adjusted_hit_box(), sprite2.get_adjusted_hit_box())
def set_entity(self, entity: AbstractEntity = None) -> None: self.entity = entity self.sprite_entity = Sprite(ASSETS.entities_textures[entity.entity_id], entity.texture_scale) self.sprite_entity.set_position(self.center_x, self.center_y) self.sprite_entity._points = None self.entity.used_in_step = False
def on_key_press(self, key, key_modifiers): """ Called when a key is pressed. Sets the state of holding an arrow key. :param key: The key that was pressed :param key_modifiers: Things like shift, ctrl, etc """ if key == arcade.key.LEFT or key == arcade.key.DOWN: self.player.change_x = -3 if key == arcade.key.RIGHT or key == arcade.key.UP: self.player.change_x = 3 if key == arcade.key.W or key == arcade.key.D: pass if key == arcade.key.S or key == arcade.key.A: pass if key == arcade.key.SPACE: bullet = Sprite(filename="game_piece_red.png", \ center_x=self.player.center_x, center_y=self.player.center_y) bullet.change_y = 30 bullet.scale = .25 self.bullets.append(bullet)
def dash( sprite: arcade.Sprite, dir_x: int, dir_y: int, collide_with: arcade.SpriteList, ) -> None: """Move sprite until it reaches something.""" sprite.bottom += 1 prev_x = sprite.left prev_y = sprite.bottom default_x = sprite.left default_y = sprite.bottom for x, y in zip_longest( range(floor(sprite.left), floor(sprite.left + dir_x), weird_sign(dir_x)), range(floor(sprite.bottom), floor(sprite.bottom + dir_y), weird_sign(dir_y)), ): sprite.left = x if x else prev_x sprite.bottom = y if y else prev_y if sprite.collides_with_list(collide_with): sprite.left = prev_x sprite.bottom = prev_y break if x: prev_x = x if y: prev_y = y
def _move_sprite(moving_sprite: arcade.Sprite, walls: arcade.SpriteList): # Rotate moving_sprite.angle += moving_sprite.change_angle hit_list = check_for_collision_with_list(moving_sprite, walls) if len(hit_list) > 0: # Resolve any collisions by this weird kludge _circular_check(moving_sprite, walls) # --- Move in the y direction moving_sprite.center_y += moving_sprite.change_y # Check for wall hit hit_list_x = check_for_collision_with_list(moving_sprite, walls) # print(f"Post-y move {hit_list_x}") # If we hit a wall, move so the edges are at the same point if len(hit_list_x) > 0: if moving_sprite.change_y > 0: while check_for_collision_with_list(moving_sprite, walls): moving_sprite.center_y -= 1 elif moving_sprite.change_y < 0: while check_for_collision_with_list(moving_sprite, walls): moving_sprite.center_y += 1 was_falling = (abs(moving_sprite.change_y) > abs( moving_sprite.engine.gravity_constant)) if was_falling: # they have been moving for more than one frame play_sound_effect('impact') moving_sprite.change_y = min(0.0, hit_list_x[0].change_y) moving_sprite.center_y = round(moving_sprite.center_y, 2) # --- Move in the x direction moving_sprite.center_x += moving_sprite.change_x check_again = True while check_again: check_again = False # Check for wall hit hit_list_y = check_for_collision_with_list(moving_sprite, walls) # If we hit a wall, move so the edges are at the same point if len(hit_list_y) > 0: change_x = moving_sprite.change_x if change_x > 0: while check_for_collision_with_list(moving_sprite, walls): moving_sprite.center_x -= 1 elif change_x < 0: while check_for_collision_with_list(moving_sprite, walls): moving_sprite.center_x += 1 else: raise AssertionError( "Error, x collision while player wasn't moving.\n" "Make sure you aren't calling multiple updates, like " "a physics engine update and an all sprites list update.")
def check_collisions(self, ships, base: Sprite): for ship in ships: if check_for_collision(ship, base): base.damage(ship.make_damage()) explosion = Explosion(self.explosion_texture) explosion.center_x = base.center_x explosion.center_y = base.center_y explosion.update() self.explosions_list.append(explosion) ship.remove_from_sprite_lists()
def __init__(self, components: list): self.components = components Sprite.__init__(self, components[0]) self.dying_sprite = load_texture(components[1]) self.cost = components[2] self.max_hp = components[3] self.damage = components[4] self.blow_damage = components[5] self.consumption = components[6] self.delta = 0 self.side = None
def setup(self): path = os.path.abspath(__file__) directory = os.path.dirname(path) spritefile = directory + '/static/ship_blue.png' self.player = Sprite(filename=spritefile, scale=0.6) self.player.center_x = self.WINDOW_W / 2 self.player.center_y = self.WINDOW_H / 2 self.speed = 0 self.rotation = 0 self.dangle = 0
def create_map_sprite(self, x, y): sprite = Sprite(center_x=x, center_y=y) try: terrain_type, index, rotation = self.nodes_data[(x, y)] t, i, r = set_terrain_texture(terrain_type, index, rotation) except KeyError: terrain_type = 'mud' t, i, r = set_terrain_texture(terrain_type) self.nodes_data[(x, y)] = terrain_type, i, r sprite.texture = t self.game.terrain_tiles.append(sprite)
def __setitem__(self, key: int, value: Sprite): self._vao1 = None item_to_be_removed = self.sprite_list[key] item_to_be_removed.sprite_lists.remove(self) if self._use_spatial_hash: self.spatial_hash.remove_object(item_to_be_removed) self.spatial_hash.insert_object_for_box(value) value.register_sprite_list(self) self.sprite_list[key] = value self.sprite_idx[value] = key
def __init__(self, filename: str = None, scale: float = 1, image_x: float = 0, image_y: float = 0, image_width: float = 0, image_height: float = 0, center_x: float = 0, center_y: float = 0, repeat_count_x=1, repeat_count_y=1): GraphicDrawable.__init__(self) ArcadeSprite.__init__(self, filename, scale, image_x, image_y, image_width, image_height, center_x, center_y, repeat_count_x, repeat_count_y)
def get_sprite(self) -> Sprite: _tex = arcade.Texture.create_empty( f"_error-{self.title}-{self.show_message}", (500, 200)) _icon_tex = arcade.Texture(f"_error_icon_{self._icon}", self.icon) sprite = Sprite(texture=_tex) _sprite_list = arcade.SpriteList() _sprite_list.append(sprite) with _sprite_list.atlas.render_into(_tex) as fbo: fbo.clear() arcade.draw_lrtb_rectangle_filled(0, 500, 200, 0, arcade.color.BLANCHED_ALMOND) arcade.draw_lrtb_rectangle_filled(0, 500, 200, 150, arcade.color.BRANDEIS_BLUE) arcade.draw_text(self.title, 50, 165, font_size=24, bold=True) arcade.draw_text(self.show_message, 5, 146, font_size=16, anchor_y="top", multiline=True, width=492, color=arcade.color.BLACK) arcade.draw_texture_rectangle(25, 175, 32, 32, _icon_tex) return sprite
def create_sprite(self, scale): self.sprite = Sprite('assets/images/brick.png', scale=scale * (self.width / 892), center_x=self.x * scale, center_y=self.y * scale) self.sprite.width = scale * self.width self.sprite.height = scale * self.height self.sprite.color = self.color
def __init__(self, width, height): """ Sets up the initial conditions of the game :param width: Screen width :param height: Screen height """ super().__init__(width, height) self.score = 0 self.player = Sprite(filename="demo_player.jpeg") self.player.center_x = SCREEN_WIDTH // 2 self.player.center_y = SCREEN_HEIGHT // 3 self.player.change_x = 3 self.bullets = [] arcade.set_background_color(arcade.color.BLACK_LEATHER_JACKET)
def create_sprite(self, scale): """ Create the sprite, the visuals of the bottle. """ pos_x, pos_y = self.get_pos() self.sprite = Sprite('assets/images/bottle.png', scale=scale * 2 * (self.radius / 948), center_x=pos_x * scale, center_y=pos_y * scale)
def on_key_press(self, key, modifiers): """ Called whenever a key is pressed. """ if key == arcade.key.UP: self.ship.change_y += 5 elif key == arcade.key.DOWN: self.ship.change_y -= 5 elif key == arcade.key.LEFT: self.ship.change_x -= 5 elif key == arcade.key.RIGHT: self.ship.change_x += 5 elif key == arcade.key.SPACE: particule = Sprite("../ressources/Life_Orb.png", center_x=self.ship.right, center_y=self.ship.center_y) particule.change_x = 3 self.particule_list.append(particule)
def create_sprite(self, scale): """ Create the sprite of the rock based on the scale. """ pos_x, pos_y = self.get_pos() self.sprite = Sprite('assets/images/brick.png', scale=scale * (self.width / 892), center_x=pos_x * scale, center_y=pos_y * scale) self.sprite.width = scale * self.width self.sprite.height = scale * self.height self.sprite.color = self.color
def generate_sprites(map_object, layer_name, scaling, base_directory=""): sprite_list = SpriteList() if layer_name not in map_object.layers_int_data: print(f"Warning, no layer named '{layer_name}'.") return sprite_list map_array = map_object.layers_int_data[layer_name] # Loop through the layer and add in the wall list for row_index, row in enumerate(map_array): for column_index, item in enumerate(row): if str(item) in map_object.global_tile_set: tile_info = map_object.global_tile_set[str(item)] filename = base_directory + tile_info.source my_sprite = Sprite(filename, scaling) my_sprite.right = column_index * (map_object.tilewidth * scaling) my_sprite.top = (map_object.height - row_index) * (map_object.tileheight * scaling) if tile_info.points is not None: my_sprite.set_points(tile_info.points) sprite_list.append(my_sprite) elif item != 0: print(f"Warning, could not find {item} image to load.") return sprite_list
def __init__(self, selected: PlayerEntity): selected.selection_marker = self self.position = selected.position self.selected = selected self.borders = Sprite() self.sprites = [] # not updated, used to cache and kill sprites only self.health = health = selected.health width, height, color = self.health_to_color_and_size(health) self.healthbar = healthbar = SpriteSolidColor(width, height, color) self.sprites = sprites = [self.borders, healthbar] self.game.selection_markers_sprites.extend(sprites)
def key_place_success(self, key_placed_successfully: bool, normal_key: arcade.Sprite, x_list: List[int], y_list: List[int]): """ Use recursion to check if key place is successful Attrs: key_placed_successfully(bool): break statement of the recursion function normal_key(arcade.Sprite): a key Sprite x_list: List[int]: all the x coordinates of the keys has been created y_list: List[int]: all the y coordinates of the keys has been created Return: the position of the key (x, y) """ if key_placed_successfully: return normal_key.center_x, normal_key.center_y normal_key.center_x = random.randrange(1500) normal_key.center_y = random.randrange(1500) # See if the key is hitting a wall, hitting another key, or too close from each other wall_hit_list = arcade.check_for_collision_with_list( normal_key, self.wall_list) key_hit_list = arcade.check_for_collision_with_list( normal_key, self.key_list) flag = True for item_x in x_list: if abs(int(item_x - normal_key.center_x)) < 30: flag = False for item_y in y_list: if abs(int(item_y - normal_key.center_y)) < 20: flag = False if len(wall_hit_list) == 0 and len(key_hit_list) == 0 and flag: key_placed_successfully = True return self.key_place_success(key_placed_successfully, normal_key, x_list, y_list)
def _pointAtTarget(self, shooter: Sprite, target: GamePiece, rotationAngle: int = 125): currentPoint: ArcadePoint = ArcadePoint(x=shooter.center_x, y=shooter.center_y) destinationPoint: ArcadePoint = ArcadePoint(x=target.center_x, y=target.center_y) normalAngle: float = self._computer.computeAngleToTarget( shooter=currentPoint, deadMeat=destinationPoint) shooter.angle = normalAngle + rotationAngle self._baseMediatorLogger.info(f'{normalAngle=} - {shooter.angle=}')
def _circular_check(player: arcade.Sprite, walls: arcade.SpriteList): """Guess our way out of a collision.""" original_x = player.center_x original_y = player.center_y vary = 1 while True: last_x = player.center_x last_y = player.center_y try_list = [ [original_x + vary, original_y], [original_x - vary, original_y], ] for my_item in try_list: x, y = my_item player.center_x = x player.center_y = y check_hit_list = check_for_collision_with_list(player, walls) if len(check_hit_list) == 0: return vary += 1 player.center_x = last_x player.center_y = last_y
def sprite_update(self, vec: Vector, spr: arcade.Sprite, tex: int): """ Updates pos, and tex_index """ spr.center_x = vec.x * self._scale spr.center_y = vec.y * self._scale spr.set_texture(tex) spr.width = self._scale spr.height = self._scale
def __init__(self, loaded_view: Optional[LoadableWindowView] = None, loading_text: str = 'Loading', background_name: Optional[str] = None): super().__init__() self.sprite_list = SpriteList() self.loading_text = loading_text self.progress = 0 self.progress_bar = self.create_progress_bar() self.loading_background = Sprite(background_name) if \ background_name is not None else None self.sprite_list.extend( [e for e in (self.progress_bar, self.loading_background) if e] ) self.set_updated_and_drawn_lists() self.loaded_view = loaded_view
def generate_sprites(map_object: TiledMap, layer_name: str, scaling: float, base_directory="") -> SpriteList: """ generate_sprites has been deprecated. Use arcade.tilemap.process_layer instead. Generate the sprites for a layer in a map. :param TiledMap map_object: Map previously read in from read_tiled_map function :param layer_name: Name of the layer we want to generate sprites from. Case sensitive. :param scaling: Scaling factor. :param base_directory: Directory to read images from. Defaults to current directory. :return: List of sprites :rtype: SpriteList """ sprite_list = SpriteList() if layer_name not in map_object.layers_int_data: print(f"Warning, no layer named '{layer_name}'.") return sprite_list map_array = map_object.layers_int_data[layer_name] # Loop through the layer and add in the wall list for row_index, row in enumerate(map_array): for column_index, item in enumerate(row): if str(item) in map_object.global_tile_set: tile_info = map_object.global_tile_set[str(item)] tmx_file = base_directory + tile_info.source my_sprite = Sprite(tmx_file, scaling) my_sprite.center_x = column_index * ( map_object.tilewidth * scaling) - map_object.tilewidth / 2 * scaling my_sprite.center_y = (map_object.height - row_index) * ( map_object.tileheight * scaling) - map_object.tileheight / 2 * scaling if tile_info.points is not None: my_sprite.set_points(tile_info.points) sprite_list.append(my_sprite) elif item != 0: print(f"Warning, could not find {item} image to load.") return sprite_list
def _move_sprite(moving_sprite: Sprite, walls: SpriteList, ramp_up: bool): # Rotate moving_sprite.angle += moving_sprite.change_angle hit_list = check_for_collision_with_list(moving_sprite, walls) if len(hit_list) > 0: # Resolve any collisions by this weird kludge _circular_check(moving_sprite, walls) # --- Move in the y direction moving_sprite.center_y += moving_sprite.change_y # Check for wall hit hit_list_x = check_for_collision_with_list(moving_sprite, walls) # print(f"Post-y move {hit_list_x}") complete_hit_list = hit_list_x # If we hit a wall, move so the edges are at the same point if len(hit_list_x) > 0: if moving_sprite.change_y > 0: while len(check_for_collision_with_list(moving_sprite, walls)) > 0: moving_sprite.center_y -= 1 # print(f"Spot X ({self.player_sprite.center_x}, {self.player_sprite.center_y})" # f" {self.player_sprite.change_y}") elif moving_sprite.change_y < 0: # Reset number of jumps for item in hit_list_x: while check_for_collision(moving_sprite, item): # self.player_sprite.bottom = item.top <- Doesn't work for ramps moving_sprite.center_y += 0.25 if item.change_x != 0: moving_sprite.center_x += item.change_x # print(f"Spot Y ({self.player_sprite.center_x}, {self.player_sprite.center_y})") else: pass # TODO: The code below can't execute, as "item" doesn't # exist. In theory, this condition should never be arrived at. # Collision while player wasn't moving, most likely # moving platform. # if self.player_sprite.center_y >= item.center_y: # self.player_sprite.bottom = item.top # else: # self.player_sprite.top = item.bottom moving_sprite.change_y = min(0.0, hit_list_x[0].change_y) # print(f"Spot D ({self.player_sprite.center_x}, {self.player_sprite.center_y})") moving_sprite.center_y = round(moving_sprite.center_y, 2) # print(f"Spot Q ({self.player_sprite.center_x}, {self.player_sprite.center_y})") # --- Move in the x direction moving_sprite.center_x += moving_sprite.change_x check_again = True while check_again: check_again = False # Check for wall hit hit_list_y = check_for_collision_with_list(moving_sprite, walls) complete_hit_list = hit_list_x for sprite in hit_list_y: if sprite not in complete_hit_list: complete_hit_list.append(sprite) # If we hit a wall, move so the edges are at the same point if len(hit_list_y) > 0: change_x = moving_sprite.change_x if change_x > 0: if ramp_up: for _ in hit_list_y: # print(f"Spot 1 ({self.player_sprite.center_x}, {self.player_sprite.center_y})") # See if we can "run up" a ramp moving_sprite.center_y += change_x if len( check_for_collision_with_list( moving_sprite, walls)) > 0: # No, ramp run-up doesn't work. moving_sprite.center_y -= change_x moving_sprite.center_x -= 1 # print(f"Spot R ({self.player_sprite.center_x}, {self.player_sprite.center_y})") check_again = True break # else: # print("Run up ok 1") # print(f"Spot 2 ({self.player_sprite.center_x}, {self.player_sprite.center_y})") else: while len( check_for_collision_with_list( moving_sprite, walls)) > 0: moving_sprite.center_x -= 1 elif change_x < 0: if ramp_up: for item in hit_list_y: # See if we can "run up" a ramp moving_sprite.center_y -= change_x if len( check_for_collision_with_list( moving_sprite, walls)) > 0: # Can't run up the ramp, reverse moving_sprite.center_y += change_x moving_sprite.left = max(item.right, moving_sprite.left) # print(f"Reverse 1 {item.right}, {self.player_sprite.left}") # Ok, if we were shoved back to the right, we need to check this whole thing again. check_again = True break # print(f"Spot 4 ({self.player_sprite.center_x}, {self.player_sprite.center_y})") else: while len( check_for_collision_with_list( moving_sprite, walls)) > 0: moving_sprite.center_x += 1 else: print( "Error, x collision while player wasn't moving.\n" "Make sure you aren't calling multiple updates, like " "a physics engine update and an all sprites list update.") # print(f"Spot E ({self.player_sprite.center_x}, {self.player_sprite.center_y})") return complete_hit_list
def _create_sprite_from_tile(map_object, tile: pytiled_parser.objects.Tile, scaling, base_directory: str = None): if base_directory: tmx_file = base_directory + tile.image.source else: tmx_file = tile.image.source if not os.path.exists(tmx_file): tmx_file = Path(map_object.parent_dir, tile.image.source) if not os.path.exists(tmx_file): print(f"Warning: can't file {tmx_file} ") return None # print(f"Creating tile: {tmx_file}") if tile.animation: # my_sprite = AnimatedTimeSprite(tmx_file, scaling) my_sprite: Sprite = AnimatedTimeBasedSprite(tmx_file, scaling) else: image_x = 0 image_y = 0 if tile.tileset.image is not None: row = tile.id_ // tile.tileset.columns image_y = row * tile.tileset.max_tile_size.height col = tile.id_ % tile.tileset.columns image_x = col * tile.tileset.max_tile_size.width if tile.image.size: # Individual image, use image width and height width = tile.image.size.width height = tile.image.size.height else: # Sprite sheet, use max width/height from sheet width = tile.tileset.max_tile_size.width height = tile.tileset.max_tile_size.height my_sprite = Sprite(tmx_file, scaling, image_x, image_y, width, height) if tile.properties is not None and len(tile.properties) > 0: for my_property in tile.properties: my_sprite.properties[my_property.name] = my_property.value # print(tile.image.source, my_sprite.center_x, my_sprite.center_y) if tile.objectgroup is not None: if len(tile.objectgroup) > 1: print( f"Warning, only one hit box supported for tile with image {tile.image.source}." ) for hitbox in tile.objectgroup: points: List[Point] = [] if isinstance(hitbox, pytiled_parser.objects.RectangleObject): if hitbox.size is None: print( f"Warning: Rectangle hitbox created for without a " f"height or width for {tile.image.source}. Ignoring.") continue # print(my_sprite.width, my_sprite.height) sx = hitbox.location[0] - (my_sprite.width / (scaling * 2)) sy = -(hitbox.location[1] - (my_sprite.height / (scaling * 2))) ex = (hitbox.location[0] + hitbox.size[0]) - (my_sprite.width / (scaling * 2)) ey = -((hitbox.location[1] + hitbox.size[1]) - (my_sprite.height / (scaling * 2))) # print(f"Size: {hitbox.size} Location: {hitbox.location}") p1 = [sx, sy] p2 = [ex, sy] p3 = [ex, ey] p4 = [sx, ey] # print(f"w:{my_sprite.width:.1f}, h:{my_sprite.height:.1f}", end=", ") points = [p1, p2, p3, p4] # for point in points: # print(f"({point[0]:.1f}, {point[1]:.1f}) ") # print() elif isinstance(hitbox, pytiled_parser.objects.PolygonObject) \ or isinstance(hitbox, pytiled_parser.objects.PolylineObject): for point in hitbox.points: adj_x = point[0] + hitbox.location[0] - my_sprite.width / ( scaling * 2) adj_y = -(point[1] + hitbox.location[1] - my_sprite.height / (scaling * 2)) adj_point = [adj_x, adj_y] points.append(adj_point) # If we have a polyline, and it is closed, we need to # remove the duplicate end-point if points[0][0] == points[-1][0] and points[0][1] == points[ -1][1]: points.pop() elif isinstance(hitbox, pytiled_parser.objects.ElipseObject): if hitbox.size is None: print( f"Warning: Ellipse hitbox created for without a height " f"or width for {tile.image.source}. Ignoring.") continue # print(f"Size: {hitbox.size} Location: {hitbox.location}") hw = hitbox.size[0] / 2 hh = hitbox.size[1] / 2 cx = hitbox.location[0] + hw cy = hitbox.location[1] + hh acx = cx - (my_sprite.width / (scaling * 2)) acy = cy - (my_sprite.height / (scaling * 2)) # print(f"acx: {acx} acy: {acy} cx: {cx} cy: {cy} hh: {hh} hw: {hw}") total_steps = 8 angles = [ step / total_steps * 2 * math.pi for step in range(total_steps) ] for angle in angles: x = (hw * math.cos(angle) + acx) y = (-(hh * math.sin(angle) + acy)) point = [x, y] points.append(point) # for point in points: # print(f"({point[0]:.1f}, {point[1]:.1f}) ") # print() else: print(f"Warning: Hitbox type {type(hitbox)} not supported.") my_sprite.points = points if tile.animation is not None: key_frame_list = [] for frame in tile.animation: frame_tile = _get_tile_by_id(map_object, tile.tileset, frame.tile_id) if frame_tile: frame_tile.image.source = Path(map_object.parent_dir, frame_tile.image.source) if not os.path.exists(tmx_file): print(f"Warning: can't file {tmx_file} ") return None key_frame = AnimationKeyframe(frame.tile_id, frame.duration, frame_tile.image) key_frame_list.append(key_frame) # print(f"Add tile {frame.tile_id} for keyframe. Source: {frame_tile.image.source}") cast(AnimatedTimeBasedSprite, my_sprite).frames = key_frame_list return my_sprite
def _create_sprite_from_tile(map_object: pytiled_parser.objects.TileMap, tile: pytiled_parser.objects.Tile, scaling: float = 1.0, base_directory: str = None, hit_box_algorithm="Simple", hit_box_detail: float = 4.5): """ Given a tile from the parser, see if we can create a sprite from it """ # --- Step 1, find a reference to an image this is going to be based off of map_source = map_object.tmx_file map_directory = os.path.dirname(map_source) image_file = _get_image_source(tile, base_directory, map_directory) # print(f"Creating tile: {tmx_file}") if tile.animation: # my_sprite = AnimatedTimeSprite(tmx_file, scaling) my_sprite: Sprite = AnimatedTimeBasedSprite(image_file, scaling) else: image_x, image_y, width, height = _get_image_info_from_tileset(tile) my_sprite = Sprite(image_file, scaling, image_x, image_y, width, height, flipped_horizontally=tile.flipped_horizontally, flipped_vertically=tile.flipped_vertically, flipped_diagonally=tile.flipped_diagonally, hit_box_algorithm=hit_box_algorithm, hit_box_detail=hit_box_detail) if tile.properties is not None and len(tile.properties) > 0: for my_property in tile.properties: my_sprite.properties[my_property.name] = my_property.value if tile.type_: my_sprite.properties['type'] = tile.type_ # print(tile.image.source, my_sprite.center_x, my_sprite.center_y) if tile.objectgroup is not None: if len(tile.objectgroup) > 1: print( f"Warning, only one hit box supported for tile with image {tile.image.source}." ) for hitbox in tile.objectgroup: points: List[Point] = [] if isinstance(hitbox, pytiled_parser.objects.RectangleObject): if hitbox.size is None: print( f"Warning: Rectangle hitbox created for without a " f"height or width for {tile.image.source}. Ignoring.") continue # print(my_sprite.width, my_sprite.height) sx = hitbox.location[0] - (my_sprite.width / (scaling * 2)) sy = -(hitbox.location[1] - (my_sprite.height / (scaling * 2))) ex = (hitbox.location[0] + hitbox.size[0]) - (my_sprite.width / (scaling * 2)) ey = -((hitbox.location[1] + hitbox.size[1]) - (my_sprite.height / (scaling * 2))) # print(f"Size: {hitbox.size} Location: {hitbox.location}") p1 = [sx, sy] p2 = [ex, sy] p3 = [ex, ey] p4 = [sx, ey] # print(f"w:{my_sprite.width:.1f}, h:{my_sprite.height:.1f}", end=", ") points = [p1, p2, p3, p4] # for point in points: # print(f"({point[0]:.1f}, {point[1]:.1f}) ") # print() elif isinstance(hitbox, pytiled_parser.objects.PolygonObject) \ or isinstance(hitbox, pytiled_parser.objects.PolylineObject): for point in hitbox.points: adj_x = point[0] + hitbox.location[0] - my_sprite.width / ( scaling * 2) adj_y = -(point[1] + hitbox.location[1] - my_sprite.height / (scaling * 2)) adj_point = [adj_x, adj_y] points.append(adj_point) # If we have a polyline, and it is closed, we need to # remove the duplicate end-point if points[0][0] == points[-1][0] and points[0][1] == points[ -1][1]: points.pop() elif isinstance(hitbox, pytiled_parser.objects.ElipseObject): if hitbox.size is None: print( f"Warning: Ellipse hitbox created for without a height " f"or width for {tile.image.source}. Ignoring.") continue # print(f"Size: {hitbox.size} Location: {hitbox.location}") hw = hitbox.size[0] / 2 hh = hitbox.size[1] / 2 cx = hitbox.location[0] + hw cy = hitbox.location[1] + hh acx = cx - (my_sprite.width / (scaling * 2)) acy = cy - (my_sprite.height / (scaling * 2)) # print(f"acx: {acx} acy: {acy} cx: {cx} cy: {cy} hh: {hh} hw: {hw}") total_steps = 8 angles = [ step / total_steps * 2 * math.pi for step in range(total_steps) ] for angle in angles: x = (hw * math.cos(angle) + acx) y = (-(hh * math.sin(angle) + acy)) point = [x, y] points.append(point) # for point in points: # print(f"({point[0]:.1f}, {point[1]:.1f}) ") # print() else: print(f"Warning: Hitbox type {type(hitbox)} not supported.") my_sprite.set_hit_box(points) if tile.animation is not None: # Animated image key_frame_list = [] # Loop through each frame for frame in tile.animation: # Get the tile for the frame frame_tile = _get_tile_by_id(map_object, tile.tileset, frame.tile_id) if frame_tile: image_file = _get_image_source(frame_tile, base_directory, map_directory) # Does the tile have an image? if frame_tile.image: # Yes, use it texture = load_texture(image_file) else: # No image for tile? Pull from tilesheet image_x, image_y, width, height = _get_image_info_from_tileset( frame_tile) texture = load_texture(image_file, image_x, image_y, width, height) key_frame = AnimationKeyframe(frame.tile_id, frame.duration, texture) key_frame_list.append(key_frame) # If this is the first texture in the animation, go ahead and # set it as the current texture. if len(key_frame_list) == 1: my_sprite.texture = key_frame.texture # print(f"Add tile {frame.tile_id} for keyframe. Source: {frame_tile.image.source}") cast(AnimatedTimeBasedSprite, my_sprite).frames = key_frame_list return my_sprite
class SpriteGame(arcade.Window): player : object def __init__(self, width=800, height=660, title="SpriteGame"): super().__init__(width,height,title) self.WINDOW_H = height self.WINDOW_W = width self.ddx = 0 self.ddy = 0 self.dx = 0 self.dy = 0 def setup(self): path = os.path.abspath(__file__) directory = os.path.dirname(path) spritefile = directory + '/static/ship_blue.png' self.player = Sprite(filename=spritefile, scale=0.6) self.player.center_x = self.WINDOW_W/2 self.player.center_y = self.WINDOW_H/2 self.speed = 0 self.force = 0 self.rotation = 0 self.dangle = 0 def run(self): arcade.run() def on_key_press(self, key, modifiers): if key == arcade.key.W: self.force += 10 if key == arcade.key.S: self.force += -5 if key == arcade.key.A: self.dangle += 10 if key == arcade.key.D: self.dangle += -10 def on_key_release(self, key, modifiers): if key == arcade.key.W: self.force -= 10 if key == arcade.key.S: self.force -= -5 if key == arcade.key.A: self.dangle -= 10 if key == arcade.key.D: self.dangle -= -10 def on_update(self, deltatime): # 0 - 360 self.rotation += self.dangle ddx = -math.sin(math.radians(self.rotation)) ddy = math.cos(math.radians(self.rotation)) self.dx = arcade.lerp(self.dx, ddx, 0.05) self.dy = arcade.lerp(self.dy, ddy, 0.05) self.speed = arcade.lerp(self.speed, self.force, 0.05) self.player.change_x = self.dx * self.speed self.player.change_y = self.dy * self.speed self.player.angle = self.rotation self.player.update() def on_draw(self): arcade.start_render() self.player.draw()
def _move_sprite(moving_sprite: Sprite, walls: SpriteList, ramp_up: bool): # start_time = time.time() # See if we are starting this turn with a sprite already colliding with us. if len(check_for_collision_with_list(moving_sprite, walls)) > 0: _circular_check(moving_sprite, walls) original_x = moving_sprite.center_x original_y = moving_sprite.center_y original_angle = moving_sprite.angle # --- Rotate rotating_hit_list = [] if moving_sprite.change_angle: # Rotate moving_sprite.angle += moving_sprite.change_angle # Resolve collisions caused by rotating rotating_hit_list = check_for_collision_with_list(moving_sprite, walls) if len(rotating_hit_list) > 0: max_distance = (moving_sprite.width + moving_sprite.height) / 2 # Resolve any collisions by this weird kludge _circular_check(moving_sprite, walls) if get_distance(original_x, original_y, moving_sprite.center_x, moving_sprite.center_y) > max_distance: # Ok, glitched trying to rotate. Reset. moving_sprite.center_x = original_x moving_sprite.center_y = original_y moving_sprite.angle = original_angle # --- Move in the y direction moving_sprite.center_y += moving_sprite.change_y # Check for wall hit hit_list_x = check_for_collision_with_list(moving_sprite, walls) # print(f"Post-y move {hit_list_x}") complete_hit_list = hit_list_x # If we hit a wall, move so the edges are at the same point if len(hit_list_x) > 0: if moving_sprite.change_y > 0: while len(check_for_collision_with_list(moving_sprite, walls)) > 0: moving_sprite.center_y -= 1 # print(f"Spot X ({self.player_sprite.center_x}, {self.player_sprite.center_y})" # f" {self.player_sprite.change_y}") elif moving_sprite.change_y < 0: # Reset number of jumps for item in hit_list_x: while check_for_collision(moving_sprite, item): # self.player_sprite.bottom = item.top <- Doesn't work for ramps moving_sprite.center_y += 0.25 if item.change_x != 0: moving_sprite.center_x += item.change_x # print(f"Spot Y ({self.player_sprite.center_x}, {self.player_sprite.center_y})") else: pass # TODO: The code below can't execute, as "item" doesn't # exist. In theory, this condition should never be arrived at. # Collision while player wasn't moving, most likely # moving platform. # if self.player_sprite.center_y >= item.center_y: # self.player_sprite.bottom = item.top # else: # self.player_sprite.top = item.bottom moving_sprite.change_y = min(0.0, hit_list_x[0].change_y) # print(f"Spot D ({self.player_sprite.center_x}, {self.player_sprite.center_y})") moving_sprite.center_y = round(moving_sprite.center_y, 2) # print(f"Spot Q ({self.player_sprite.center_x}, {self.player_sprite.center_y})") # end_time = time.time() # print(f"Move 1 - {end_time - start_time:7.4f}") # start_time = time.time() loop_count = 0 # --- Move in the x direction if moving_sprite.change_x: # Keep track of our current y, used in ramping up almost_original_y = moving_sprite.center_y # Strip off sign so we only have to write one version of this for # both directions direction = math.copysign(1, moving_sprite.change_x) cur_x_change = abs(moving_sprite.change_x) upper_bound = cur_x_change lower_bound = 0 cur_y_change = 0 exit_loop = False while not exit_loop: loop_count += 1 # print(f"{cur_x_change=}, {upper_bound=}, {lower_bound=}, {loop_count=}") # Move sprite and check for collisions moving_sprite.center_x = original_x + cur_x_change * direction collision_check = check_for_collision_with_list( moving_sprite, walls) # Update collision list for sprite in collision_check: if sprite not in complete_hit_list: complete_hit_list.append(sprite) # Did we collide? if len(collision_check) > 0: # We did collide. Can we ramp up and not collide? if ramp_up: cur_y_change = cur_x_change moving_sprite.center_y = original_y + cur_y_change collision_check = check_for_collision_with_list( moving_sprite, walls) if len(collision_check) > 0: cur_y_change -= cur_x_change else: while (len(collision_check) == 0) and cur_y_change > 0: # print("Ramp up check") cur_y_change -= 1 moving_sprite.center_y = almost_original_y + cur_y_change collision_check = check_for_collision_with_list( moving_sprite, walls) cur_y_change += 1 collision_check = [] if len(collision_check) > 0: # print(f"Yes @ {cur_x_change}") upper_bound = cur_x_change - 1 if upper_bound - lower_bound <= 1: cur_x_change = lower_bound exit_loop = True # print(f"Exit 2 @ {cur_x_change}") else: cur_x_change = (upper_bound + lower_bound) / 2 else: exit_loop = True # print(f"Exit 1 @ {cur_x_change}") else: # No collision. Keep this new position and exit lower_bound = cur_x_change if upper_bound - lower_bound <= 1: # print(f"Exit 3 @ {cur_x_change}") exit_loop = True else: # print(f"No @ {cur_x_change}") cur_x_change = (upper_bound + lower_bound) / 2 # print(cur_x_change * direction, cur_y_change) moving_sprite.center_x = original_x + cur_x_change * direction moving_sprite.center_y = almost_original_y + cur_y_change # print(f"({moving_sprite.center_x}, {moving_sprite.center_y}) {cur_x_change * direction}, {cur_y_change}") # Add in rotating hit list for sprite in rotating_hit_list: if sprite not in complete_hit_list: complete_hit_list.append(sprite) # end_time = time.time() # print(f"Move 2 - {end_time - start_time:7.4f} {loop_count}") return complete_hit_list