Got the engine working.

This commit is contained in:
The Wobbler 2024-07-18 10:53:51 +02:00
commit 8a40f24d65
8 changed files with 297 additions and 0 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,66 @@
#!/usr/bin/python3
import pygame.draw
from settings import *
class Cache:
def __init__(self):
self.stacked_sprite_cache = {}
self.viewing_angle = 360 // NUM_ANGLES
self.outline_thickness = 4
self.get_stacked_sprite_cache()
def get_stacked_sprite_cache(self):
for object_name in SPRITE_ATTRS:
self.stacked_sprite_cache[object_name] = {
"rotated_sprites": {}
}
attrs = SPRITE_ATTRS[object_name]
layer_array = self.get_layer_array(attrs)
self.run_prerender(object_name, layer_array, attrs)
def run_prerender(self, object_name, layer_array, attrs):
outline = attrs.get("outline", True)
for angle in range(NUM_ANGLES):
surface = pygame.Surface(layer_array[0].get_size())
surface = pygame.transform.rotate(surface, angle * self.viewing_angle)
sprite_surface = pygame.Surface([
surface.get_width(),
surface.get_height() + attrs["num_layers"] * attrs["scale"]
])
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)
self.stacked_sprite_cache[object_name]["rotated_sprites"][angle] = image
def get_layer_array(self, attrs):
# load sprite sheet
sprite_sheet = pygame.image.load(attrs["path"]).convert_alpha()
# scaling
sprite_sheet = pygame.transform.scale(sprite_sheet, vec2(sprite_sheet.get_size()) * attrs["scale"])
sheet_width, sheet_height = sprite_sheet.get_size()
sprite_width = sheet_width // attrs["num_layers"]
# new width to prevent error
sheet_width = sprite_width * attrs["num_layers"]
# get sprites
layer_array = []
for x in range(0, sheet_width, sprite_width):
sprite = sprite_sheet.subsurface((x, 0, sprite_width, sheet_height))
layer_array.append(sprite)
return layer_array

View file

@ -0,0 +1,53 @@
#!/usr/bin/python3
import sys
from settings import *
from stacked_sprite import StackedSprite
from cache import Cache
from player import Player
from scene import Scene
class App:
def __init__(self):
self.screen = pygame.display.set_mode(RES)
self.clock = pygame.time.Clock()
self.time = 0
self.delta_time = 0.01
# groups
self.main_group = pygame.sprite.LayeredUpdates()
# game objects
self.cache = Cache()
self.player = Player(self)
self.scene = Scene(self)
def update(self):
self.main_group.update()
pygame.display.set_caption(f"{self.clock.get_fps(): .1f}")
self.delta_time = self.clock.tick(60)
def draw(self):
self.screen.fill(BG_COLOR)
self.main_group.draw(self.screen)
pygame.display.flip()
def check_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
sys.exit()
def get_time(self):
self.time = pygame.time.get_ticks() * 0.001
def run(self):
while True:
self.check_events()
self.get_time()
self.update()
self.draw()
if __name__ == "__main__":
app = App()
app.run()

View file

@ -0,0 +1,58 @@
#!/usr/bin/python3
from settings import *
import math
class Player(pygame.sprite.Sprite):
def __init__(self, app):
self.app = app
self.group = app.main_group
super().__init__(self.group)
self.group.change_layer(self, CENTER.y)
size = vec2([50, 50])
self.image = pygame.Surface(size, pygame.SRCALPHA)
pygame.draw.circle(self.image, "red", size / 2, size[0] / 2)
self.rect = self.image.get_rect(center=CENTER)
self.offset = vec2(0)
self.inc = vec2(0)
self.angle = 0
self.diag_move_corr = 1 / math.sqrt(2)
def control(self):
self.inc = vec2(0)
speed = PLAYER_SPEED * self.app.delta_time
rot_speed = PLAYER_ROT_SPEED * self.app.delta_time
key_state = pygame.key.get_pressed()
if key_state[pygame.K_LEFT]:
self.angle -= rot_speed
if key_state[pygame.K_RIGHT]:
self.angle += rot_speed
if key_state[pygame.K_w]:
self.inc += vec2(0, -speed).rotate_rad(-self.angle)
if key_state[pygame.K_s]:
self.inc += vec2(0, speed).rotate_rad(-self.angle)
if key_state[pygame.K_a]:
self.inc += vec2(-speed, 0).rotate_rad(-self.angle)
if key_state[pygame.K_d]:
self.inc += vec2(speed, 0).rotate_rad(-self.angle)
if self.inc.x and self.inc.y:
self.inc *= self.diag_move_corr
def update(self):
self.control()
self.move()
def move(self):
self.offset += self.inc

View file

@ -0,0 +1,42 @@
#!/usr/bin/python3
from stacked_sprite import *
from random import uniform
P = "player"
A, B = "Robot", "Building"
MAP = [
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 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, 0, B, B, B, B],
[0, 0, 0, 0, 0, B, B, B, B],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0],
]
MAP_SIZE = MAP_WIDTH, MAP_HEIGHT = vec2(len(MAP), len(MAP[0]))
MAP_CENTER = MAP_SIZE / 2
class Scene:
def __init__(self, app):
self.app = app
self.load_scene()
def load_scene(self):
rand_rot = lambda: uniform(0, 360)
rand_pos = lambda pos: pos + vec2(uniform(-0.25, 0.25))
for j, row in enumerate(MAP):
for i, name in enumerate(row):
pos = vec2(i, j) + vec2(0.5)
if name == "player":
self.app.player.offset = pos * TILE_SIZE
elif name:
StackedSprite(self.app, name=name, pos=rand_pos(pos), rot=rand_rot())

View file

@ -0,0 +1,31 @@
#!/usr/bin/python3
import pygame
vec2 = pygame.math.Vector2
RES = WIDTH, HEIGHT = vec2(1400, 800)
CENTER = H_WIDTH, H_HEIGHT = RES // 2
TILE_SIZE = 250
PLAYER_SPEED = 0.4
PLAYER_ROT_SPEED = 0.0015
BG_COLOR = "olivedrab"
NUM_ANGLES = 180 # multiple of 360
TRANSP_COLOR = (43, 64, 36)
SPRITE_ATTRS = {
"Robot": {
"path": "../assets/stacked_sprites/Robot.png",
"num_layers": 16,
"scale": 8,
"y_offset": -8
},
"Building": {
"path": "../assets/stacked_sprites/Building.png",
"num_layers": 80,
"scale": 4,
"y_offset": -40
}
}

View file

@ -0,0 +1,47 @@
#!/usr/bin/python3
import pygame
from settings import *
import math
from wobbl_tools import pg
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]
self.y_offset = vec2(0, -self.attrs["num_layers"] / 2 * self.attrs["scale"])
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):
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 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)