Got animated sprites working, but its mirrored.

This commit is contained in:
The Wobbler 2024-07-18 17:21:05 +02:00
parent 8a40f24d65
commit e7daca1d8c
7 changed files with 131 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 179 B

View file

@ -1,6 +1,6 @@
#!/usr/bin/python3 #!/usr/bin/python3
import pygame.draw
import os
from settings import * from settings import *
@ -21,6 +21,15 @@ class Cache:
layer_array = self.get_layer_array(attrs) layer_array = self.get_layer_array(attrs)
self.run_prerender(object_name, layer_array, attrs) self.run_prerender(object_name, layer_array, attrs)
for object_name in ANIMATED_SPRITE_ATTRS:
self.stacked_sprite_cache[object_name] = {
"frames": {}
}
attrs = ANIMATED_SPRITE_ATTRS[object_name]
frames = self.get_frame_dict(attrs)
self.run_animation_prerender(object_name, frames, attrs)
def run_prerender(self, object_name, layer_array, attrs): def run_prerender(self, object_name, layer_array, attrs):
outline = attrs.get("outline", True) outline = attrs.get("outline", True)
@ -29,7 +38,7 @@ class Cache:
surface = pygame.transform.rotate(surface, angle * self.viewing_angle) surface = pygame.transform.rotate(surface, angle * self.viewing_angle)
sprite_surface = pygame.Surface([ sprite_surface = pygame.Surface([
surface.get_width(), surface.get_width(),
surface.get_height() + attrs["num_layers"] * attrs["scale"] surface.get_height() + attrs["layers"] * attrs["scale"]
]) ])
sprite_surface.fill(TRANSP_COLOR) sprite_surface.fill(TRANSP_COLOR)
@ -47,15 +56,51 @@ class Cache:
image = pygame.transform.flip(sprite_surface, True, True) image = pygame.transform.flip(sprite_surface, True, True)
self.stacked_sprite_cache[object_name]["rotated_sprites"][angle] = image self.stacked_sprite_cache[object_name]["rotated_sprites"][angle] = image
def get_layer_array(self, attrs): def run_animation_prerender(self, object_name, frames, attrs):
outline = attrs.get("outline", True)
for angle in range(NUM_ANGLES):
surface = pygame.Surface(list(frames.items())[0][1][0].get_size())
surface = pygame.transform.rotate(surface, angle * self.viewing_angle)
surface_default = pygame.Surface([
surface.get_width(),
surface.get_height() + attrs["layers"] * attrs["scale"]
])
for frame_name, layer_array in frames.items():
sprite_surface = surface_default
sprite_surface.fill(TRANSP_COLOR)
sprite_surface.set_colorkey(TRANSP_COLOR)
for i, layer in enumerate(layer_array):
layer = pygame.transform.rotate(layer, angle * self.viewing_angle)
sprite_surface.blit(layer, (0, i * attrs["scale"]))
# get outline
if outline:
outline_coords = pygame.mask.from_surface(sprite_surface).outline()
pygame.draw.polygon(sprite_surface, "black", outline_coords, self.outline_thickness)
image = pygame.transform.flip(sprite_surface, True, True)
if not frame_name in self.stacked_sprite_cache[object_name]["frames"]:
self.stacked_sprite_cache[object_name]["frames"][frame_name] = {"rotated_sprites": {}}
self.stacked_sprite_cache[object_name]["frames"][frame_name]["rotated_sprites"][angle] = image
def get_layer_array(self, attrs, path=None):
if not path is None:
attrs["path"] = path
# load sprite sheet # load sprite sheet
sprite_sheet = pygame.image.load(attrs["path"]).convert_alpha() sprite_sheet = pygame.image.load(attrs["path"]).convert_alpha()
# scaling # scaling
sprite_sheet = pygame.transform.scale(sprite_sheet, vec2(sprite_sheet.get_size()) * attrs["scale"]) sprite_sheet = pygame.transform.scale(sprite_sheet, vec2(sprite_sheet.get_size()) * attrs["scale"])
sheet_width, sheet_height = sprite_sheet.get_size() sheet_width, sheet_height = sprite_sheet.get_size()
sprite_width = sheet_width // attrs["num_layers"] sprite_width = sheet_width // attrs["layers"]
# new width to prevent error # new width to prevent error
sheet_width = sprite_width * attrs["num_layers"] sheet_width = sprite_width * attrs["layers"]
# get sprites # get sprites
layer_array = [] layer_array = []
@ -64,3 +109,14 @@ class Cache:
layer_array.append(sprite) layer_array.append(sprite)
return layer_array return layer_array
def get_frame_dict(self, attrs):
frames = {}
for path, folders, files in os.walk(attrs["path"]): # loop through all frames and add them to the sheet list
for file in files:
# use the name of the file without the file format specifier (the part before the dot) as the frame name
# and store the layer array
frames[file.split(".")[0]] = self.get_layer_array(attrs, f"{path}/{file}")
return frames

View file

@ -4,7 +4,7 @@ from stacked_sprite import *
from random import uniform from random import uniform
P = "player" P = "player"
A, B = "Robot", "Building" A, B, C = "Robot", "Building", "Bla"
MAP = [ MAP = [
[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
@ -13,7 +13,7 @@ MAP = [
[0, 0, A, A, 0, B, B, B, B], [0, 0, A, A, 0, B, B, B, B],
[0, 0, A, A, P, B, B, B, B], [0, 0, A, A, P, B, B, B, B],
[0, 0, A, A, 0, B, B, B, B], [0, 0, A, A, 0, B, B, B, B],
[0, 0, 0, 0, 0, B, B, B, B], [0, 0, 0, 0, C, B, B, B, B],
[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0],
] ]
@ -39,4 +39,8 @@ class Scene:
self.app.player.offset = pos * TILE_SIZE self.app.player.offset = pos * TILE_SIZE
elif name: elif name:
if name == "Bla":
AnimatedStackedSprite(self.app, name=name, pos=rand_pos(pos), rot=rand_rot())
else:
StackedSprite(self.app, name=name, pos=rand_pos(pos), rot=rand_rot()) StackedSprite(self.app, name=name, pos=rand_pos(pos), rot=rand_rot())

View file

@ -18,14 +18,20 @@ TRANSP_COLOR = (43, 64, 36)
SPRITE_ATTRS = { SPRITE_ATTRS = {
"Robot": { "Robot": {
"path": "../assets/stacked_sprites/Robot.png", "path": "../assets/stacked_sprites/Robot.png",
"num_layers": 16, "layers": 16,
"scale": 8, "scale": 8
"y_offset": -8
}, },
"Building": { "Building": {
"path": "../assets/stacked_sprites/Building.png", "path": "../assets/stacked_sprites/Building.png",
"num_layers": 80, "layers": 80,
"scale": 4, "scale": 4
"y_offset": -40 }
}
ANIMATED_SPRITE_ATTRS = {
"Bla": {
"path": "../assets/stacked_sprites/animated/bla/",
"layers": 3,
"scale": 16
} }
} }

View file

@ -3,7 +3,6 @@ import pygame
from settings import * from settings import *
import math import math
from wobbl_tools import pg
class StackedSprite(pygame.sprite.Sprite): class StackedSprite(pygame.sprite.Sprite):
@ -16,7 +15,7 @@ class StackedSprite(pygame.sprite.Sprite):
super().__init__(self.group) super().__init__(self.group)
self.attrs = SPRITE_ATTRS[name] self.attrs = SPRITE_ATTRS[name]
self.y_offset = vec2(0, -self.attrs["num_layers"] / 2 * self.attrs["scale"]) self.y_offset = vec2(0, -self.attrs["layers"] / 2 * self.attrs["scale"])
self.cache = self.app.cache.stacked_sprite_cache self.cache = self.app.cache.stacked_sprite_cache
self.viewing_angle = app.cache.viewing_angle self.viewing_angle = app.cache.viewing_angle
self.rotated_sprites = self.cache[name]["rotated_sprites"] self.rotated_sprites = self.cache[name]["rotated_sprites"]
@ -45,3 +44,52 @@ class StackedSprite(pygame.sprite.Sprite):
def get_image(self): def get_image(self):
self.image = self.rotated_sprites[self.angle] self.image = self.rotated_sprites[self.angle]
self.rect = self.image.get_rect(center=self.screen_position + self.y_offset) self.rect = self.image.get_rect(center=self.screen_position + self.y_offset)
class AnimatedStackedSprite(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 = ANIMATED_SPRITE_ATTRS[name]
self.attrs["animated"] = True
self.y_offset = vec2(0, -self.attrs["layers"] / 2 * self.attrs["scale"])
self.cache = self.app.cache.stacked_sprite_cache
self.viewing_angle = app.cache.viewing_angle
self.frame = list(self.cache[name]["frames"].keys())[0]
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):
self.frame = str(round(self.app.time) * 4 % 3)
print(self.frame)
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()