parent
50dd040d52
commit
08cfd6ed9b
|
@ -0,0 +1,14 @@
|
||||||
|
class PositionScale:
|
||||||
|
def __init__(self, position=(0, 0), scale=(1, 1)):
|
||||||
|
self.position = position
|
||||||
|
self.scale = scale
|
||||||
|
|
||||||
|
def apply_scale_to_position(self):
|
||||||
|
return self.position[0] * self.scale[0], self.position[1] * self.scale[1]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def combine(a, b):
|
||||||
|
return PositionScale(
|
||||||
|
(a.position[0] + b.position[0], a.position[1] + b.position[1]),
|
||||||
|
(a.scale[0] * b.scale[0], a.scale[1] * b.scale[1])
|
||||||
|
)
|
|
@ -0,0 +1,93 @@
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from PositionScale import PositionScale
|
||||||
|
|
||||||
|
|
||||||
|
class Sprite:
|
||||||
|
def __init__(self, spritesheet):
|
||||||
|
self.spritesheet = spritesheet
|
||||||
|
|
||||||
|
self.animation_state = list(self.spritesheet.animations.keys())[0]
|
||||||
|
self.animation_frame = 0
|
||||||
|
self.animation_delay = 0
|
||||||
|
|
||||||
|
self.position_scale = PositionScale()
|
||||||
|
|
||||||
|
self.visible = True
|
||||||
|
self.animated = True
|
||||||
|
|
||||||
|
self.image = None
|
||||||
|
|
||||||
|
def tick(self, dt):
|
||||||
|
animation = self.spritesheet.animations[self.animation_state]
|
||||||
|
|
||||||
|
if self.animated:
|
||||||
|
self.animation_delay += dt
|
||||||
|
|
||||||
|
while self.animation_delay >= animation["delays"][self.animation_frame % len(animation["delays"])]:
|
||||||
|
self.animation_delay -= animation["delays"][self.animation_frame % len(animation["delays"])]
|
||||||
|
self.animation_frame = (self.animation_frame + 1) % len(animation["images"])
|
||||||
|
|
||||||
|
self.image = animation["images"][self.animation_frame % len(animation["images"])]
|
||||||
|
|
||||||
|
def set_animation_state(self, state):
|
||||||
|
if state in self.spritesheet.animations:
|
||||||
|
self.animation_state = state
|
||||||
|
self.animation_delay = 0
|
||||||
|
self.tick(0)
|
||||||
|
|
||||||
|
def set_animation_frame(self, frame):
|
||||||
|
self.animation_frame = frame
|
||||||
|
self.tick(0)
|
||||||
|
|
||||||
|
def draw(self, screen, screen_transform):
|
||||||
|
if not self.visible:
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.image is not None:
|
||||||
|
target_position = screen_transform.apply_scale_to_position()
|
||||||
|
|
||||||
|
target_scale = (
|
||||||
|
screen_transform.scale[0] * self.position_scale.scale[0],
|
||||||
|
screen_transform.scale[1] * self.position_scale.scale[1]
|
||||||
|
)
|
||||||
|
target_size = (
|
||||||
|
int(target_scale[0] * self.image.get_width()),
|
||||||
|
int(target_scale[1] * self.image.get_height())
|
||||||
|
)
|
||||||
|
|
||||||
|
target_image = self.get_scaled_image(self.image, target_size)
|
||||||
|
|
||||||
|
screen.blit(target_image, target_position)
|
||||||
|
|
||||||
|
def get_scaled_image(self, image, resize):
|
||||||
|
return pygame.transform.scale(image, resize)
|
||||||
|
|
||||||
|
def dump(self, file):
|
||||||
|
# re-attach all the images to a single surface and save it to a file
|
||||||
|
width = 0
|
||||||
|
height = 0
|
||||||
|
|
||||||
|
for animation in self.spritesheet.animations.values():
|
||||||
|
max_height = 0
|
||||||
|
total_width = 0
|
||||||
|
for image in animation["images"]:
|
||||||
|
total_width += image.get_width()
|
||||||
|
max_height = max(max_height, image.get_height())
|
||||||
|
width = max(width, total_width)
|
||||||
|
height += max_height
|
||||||
|
|
||||||
|
sheet = pygame.Surface((width, height))
|
||||||
|
|
||||||
|
x = 0
|
||||||
|
y = 0
|
||||||
|
for animation in self.spritesheet.animations.values():
|
||||||
|
max_height = 0
|
||||||
|
for image in animation["images"]:
|
||||||
|
sheet.blit(image, (x, y))
|
||||||
|
x += image.get_width()
|
||||||
|
max_height = max(max_height, image.get_height())
|
||||||
|
y += max_height
|
||||||
|
x = 0
|
||||||
|
|
||||||
|
pygame.image.save(sheet, file)
|
|
@ -0,0 +1,33 @@
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
|
||||||
|
class Spritesheet:
|
||||||
|
def __init__(self, sprites_dir, sprite_data):
|
||||||
|
self.sprite_id = sprite_data["id"]
|
||||||
|
self.subsheets = sprite_data["subsheets"]
|
||||||
|
|
||||||
|
self.sheet_file = sprites_dir + "/" + self.sprite_id + ".png"
|
||||||
|
self.sheet = pygame.image.load(self.sheet_file).convert_alpha()
|
||||||
|
|
||||||
|
self.animations = {}
|
||||||
|
self.load_animations()
|
||||||
|
|
||||||
|
def load_animations(self):
|
||||||
|
subsheet_y = 0
|
||||||
|
|
||||||
|
for subsheet_data in self.subsheets:
|
||||||
|
subsheet_id = subsheet_data["id"]
|
||||||
|
delays = subsheet_data["delays"]
|
||||||
|
subsheet_width = subsheet_data["width"]
|
||||||
|
subsheet_height = subsheet_data["height"]
|
||||||
|
subsheet_x = 0
|
||||||
|
|
||||||
|
subsheet_images = []
|
||||||
|
for i in range(len(delays)):
|
||||||
|
subsheet_image = pygame.Surface((subsheet_width, subsheet_height), pygame.SRCALPHA)
|
||||||
|
subsheet_image.blit(self.sheet, (0, 0), (subsheet_x, subsheet_y, subsheet_width, subsheet_height))
|
||||||
|
subsheet_images.append(subsheet_image)
|
||||||
|
subsheet_x += subsheet_width
|
||||||
|
|
||||||
|
subsheet_y += subsheet_height
|
||||||
|
self.animations[subsheet_id] = {"images": subsheet_images, "delays": delays}
|
|
@ -0,0 +1,26 @@
|
||||||
|
import pygame
|
||||||
|
import json
|
||||||
|
|
||||||
|
from Spritesheet import Spritesheet
|
||||||
|
|
||||||
|
|
||||||
|
# This class is used to load named sprite sheets from the img folder.
|
||||||
|
class SpritesheetManager:
|
||||||
|
def __init__(self, sprites_dir, config_file):
|
||||||
|
self.sprites_dir = sprites_dir
|
||||||
|
self.spritesheets = {}
|
||||||
|
self.load_from_config(config_file)
|
||||||
|
|
||||||
|
def load_from_config(self, config_file):
|
||||||
|
print("Loading sprites from sprite sheet config file", config_file)
|
||||||
|
config = json.load(open(config_file))
|
||||||
|
|
||||||
|
for sprite_data in config:
|
||||||
|
sprite_sheet = Spritesheet(self.sprites_dir, sprite_data)
|
||||||
|
self.spritesheets[sprite_sheet.sprite_id] = sprite_sheet
|
||||||
|
print("Loaded", len(self.spritesheets), "sprite sheet(s)")
|
||||||
|
|
||||||
|
def get_sheet(self, sheet):
|
||||||
|
if sheet not in self.spritesheets:
|
||||||
|
raise ValueError("Invalid/Missing sprite sheet " + sheet)
|
||||||
|
return self.spritesheets[sheet]
|
|
@ -0,0 +1,35 @@
|
||||||
|
import random
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
|
||||||
|
from PositionScale import PositionScale
|
||||||
|
from SpritesheetManager import SpritesheetManager
|
||||||
|
from Sprite import Sprite
|
||||||
|
|
||||||
|
pygame.init()
|
||||||
|
screen = pygame.display.set_mode((300, 300))
|
||||||
|
pygame.display.set_caption("PE GAME")
|
||||||
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
|
spritesheet_manager = SpritesheetManager("sprites", "sprites/sprites.json")
|
||||||
|
|
||||||
|
test_1_sprite = Sprite(spritesheet_manager.get_sheet("test_1"))
|
||||||
|
|
||||||
|
test_1_sprite.dump("debug.png")
|
||||||
|
|
||||||
|
while True:
|
||||||
|
clock.tick(5)
|
||||||
|
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
pygame.quit()
|
||||||
|
|
||||||
|
screen.fill((0, 0, 0))
|
||||||
|
|
||||||
|
test_1_sprite.tick(1)
|
||||||
|
test_1_sprite.draw(screen, PositionScale((40, 40), (3, 3)))
|
||||||
|
pygame.display.update()
|
||||||
|
|
||||||
|
if random.randint(1, 10) == 1:
|
||||||
|
test_1_sprite.set_animation_state(random.choice(["walk_r", "walk_l", "idle", "other_test"]))
|
||||||
|
print(test_1_sprite.animation_state)
|
|
@ -0,0 +1,51 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"id": "test_1",
|
||||||
|
"subsheets": [
|
||||||
|
{
|
||||||
|
"id": "walk_l",
|
||||||
|
"delays": [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"height": 16,
|
||||||
|
"width": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "idle",
|
||||||
|
"delays": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"height": 16,
|
||||||
|
"width": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "walk_r",
|
||||||
|
"delays": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"height": 16,
|
||||||
|
"width": 16
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "other_test",
|
||||||
|
"delays": [
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"height": 16,
|
||||||
|
"width": 16
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
Binary file not shown.
After Width: | Height: | Size: 714 B |
Loading…
Reference in New Issue