#!/usr/bin/python3 import pygame from settings import * import math class StackedSprite(pygame.sprite.Sprite): def __init__(self, app, name, pos, rot=0): self.app = app self.name = name self.pos = vec2(pos) * TILE_SIZE self.player = self.app.player self.group = self.app.main_group super().__init__(self.group) self.attrs = SPRITE_ATTRS[name] # get attributes if not "scale" in self.attrs: self.attrs["scale"] = DEFAULT_SCALE self.y_offset = vec2(0, -self.attrs["layers"] / 2 * self.attrs["scale"]) # calculate the y offset because the - # images position in pygame is the position of the top left corner of the image and we use the bottom position self.cache = self.app.cache.stacked_sprite_cache self.viewing_angle = app.cache.viewing_angle self.rotated_sprites = self.cache[name]["rotated_sprites"] self.angle = 0 self.screen_position = vec2(0) self.rot = (rot % 360) // self.viewing_angle def transform(self): # recalculate position and rotation pos = self.pos - self.player.offset pos = pos.rotate_rad(self.player.angle) self.screen_position = pos + CENTER def change_layer(self): # calculate the layer to draw over the things behind it and not the other way self.group.change_layer(self, self.screen_position.y) def get_angle(self): # calculate the angle to draw the right sprite self.angle = -math.degrees(self.player.angle) // self.viewing_angle + self.rot self.angle = int(self.angle % NUM_ANGLES) def update(self): self.transform() self.get_angle() self.get_image() self.change_layer() def get_image(self): self.image = self.rotated_sprites[self.angle] self.rect = self.image.get_rect(center=self.screen_position + self.y_offset) class AnimatedStackedSprite(pygame.sprite.Sprite): # stacked sprite class for animated sprites, works nearly the same def __init__(self, app, name, pos, rot=0): self.app = app self.name = name self.pos = vec2(pos) * TILE_SIZE self.player = self.app.player self.group = self.app.main_group super().__init__(self.group) self.attrs = ANIMATED_SPRITE_ATTRS[name] if not "scale" in self.attrs: self.attrs["scale"] = DEFAULT_SCALE self.attrs["animated"] = True # set the animated attribute to true so that the cache knows that this sprite - self.y_offset = vec2(0, -self.attrs["layers"] / 2 * self.attrs["scale"]) # is animated self.cache = self.app.cache.stacked_sprite_cache self.viewing_angle = app.cache.viewing_angle self.frame = list(self.cache[name]["frames"].keys())[0] # set the frame to the first frame self.rotated_sprites = self.cache[name]["frames"][self.frame]["rotated_sprites"] self.angle = 0 self.screen_position = vec2(0) self.rot = (rot % 360) // self.viewing_angle def transform(self): pos = self.pos - self.player.offset pos = pos.rotate_rad(self.player.angle) self.screen_position = pos + CENTER def change_layer(self): self.group.change_layer(self, self.screen_position.y) def get_angle(self): self.angle = -math.degrees(self.player.angle) // self.viewing_angle + self.rot self.angle = int(self.angle % NUM_ANGLES) def animate(self): # change the layer to display another frame self.frame = str(round(self.app.time) * 4 % 3) self.rotated_sprites = self.cache[self.name]["frames"][self.frame]["rotated_sprites"] def get_image(self): self.image = self.rotated_sprites[self.angle] self.rect = self.image.get_rect(center=self.screen_position + self.y_offset) def update(self): self.transform() self.get_angle() self.animate() self.get_image() self.change_layer()