From 6330fad2810d6717232fbb281e17fcfad3cb4359 Mon Sep 17 00:00:00 2001 From: EKNr1 Date: Sun, 25 Feb 2024 21:32:34 +0100 Subject: [PATCH] Initial commit --- falling_sand.py | 192 ++++++++++++++++++++++++++++++++++++++++++++++++ settings.json | 1 + 2 files changed, 193 insertions(+) create mode 100644 falling_sand.py create mode 100644 settings.json diff --git a/falling_sand.py b/falling_sand.py new file mode 100644 index 0000000..5489736 --- /dev/null +++ b/falling_sand.py @@ -0,0 +1,192 @@ +#!/usr/bin/python3 + +import pygame +from pygame._sdl2 import Window +from dataclasses import dataclass +from wobbl_tools.data_file import load_dataclass_json, save_dataclass_json +from random import choice + + +def true_false_random(): + return choice([True, False]) + + +@dataclass +class Settings: + fps: int = 60 + window_size: tuple = (1000, 600) + + +class FallingSandParticle: + def __init__(self, app, start_pos: tuple): + self.app = app + self.pos = start_pos + self.color = (50, 50, 200) + self.not_moving = 0 + + x, y = start_pos + self.app.matrix[x, y] = self.color + + def update(self): + old_pos = self.pos + ox, oy = old_pos + + if oy >= self.app.sand_surface.get_height() - 4: + self.app.falling_sand_particles.remove(self) + return + + x, y = self.pos + + if self.app.matrix[ox, oy + 1] == self.app.sand_surface.map_rgb(self.app.gray): + y += 1 + + elif ( + self.app.matrix[ox - 1, oy + 2] == self.app.sand_surface.map_rgb(self.app.gray) + and self.app.matrix[ox + 1, oy + 2] == self.app.sand_surface.map_rgb(self.app.gray) + ): + if true_false_random(): + x -= 1 + y += 2 + + else: + x += 1 + y += 2 + + elif self.app.matrix[ox - 1, oy + 2] == self.app.sand_surface.map_rgb(self.app.gray): + x -= 1 + y += 2 + + elif self.app.matrix[ox + 1, oy + 2] == self.app.sand_surface.map_rgb(self.app.gray): + x += 1 + y += 2 + + else: + if self.not_moving == 16: + self.app.falling_sand_particles.remove(self) + return + + else: + self.not_moving += 1 + return + + self.not_moving = 0 + + self.pos = (x, y) + + self.app.matrix[ox, oy] = self.app.gray + self.app.matrix[x, y] = self.color + + +class FallingSand: + def __init__(self): + pygame.init() + + self.screen = pygame.display.set_mode((1000, 600), pygame.RESIZABLE) + pygame.display.set_caption("Game") + self.window = Window.from_display_module() + + self.loading_surface = self.generate_loading_surface() + self.screen.blit(self.loading_surface, (0, 0)) + pygame.display.update() + + self.settings = load_dataclass_json(Settings, "settings.json") + setattr(self.settings, "save", lambda: save_dataclass_json(self.settings, "settings.json")) + + self.fps = self.settings.fps + + self.falling_sand_particles = [] + + # colors + self.gray = (20, 20, 20) + + # pygame objects + self.clock = pygame.time.Clock() + self.mouse = pygame.mouse + self.sand_surface = pygame.Surface(self.screen.get_size()) + self.sand_surface.fill(self.gray) + self.matrix = pygame.PixelArray(self.sand_surface) + + # loading finished + self.window.size = self.settings.window_size + + self.running = True + + def generate_loading_surface(self): + default_font = pygame.font.SysFont("ubuntu", 32, True) + loading_text = default_font.render("Loading...", True, (240, 240, 240)) + + w, h = self.screen.get_size() + + loading_surface = pygame.Surface((w, h), flags=pygame.SRCALPHA) + + loading_surface.fill((40, 40, 40)) + loading_surface.blit(loading_text, (w // 2 - loading_text.get_width() // 2, h // 2 - loading_text.get_height() // 2)) + + return loading_surface + + def loop(self): + self.screen.fill(self.gray) + + self.matrix = pygame.PixelArray(self.sand_surface) + + mouse_pressed = self.mouse.get_pressed() + mouse_pos = self.mouse.get_pos() + if mouse_pressed[0]: + self.spawn_sand(mouse_pos) + + self.get_events() + if not self.running: + return + + for particle in self.falling_sand_particles: + particle.update() + + self.matrix.close() + + self.screen.blit(self.sand_surface, (0, 0)) + + if self.loading_surface.get_alpha() > 0: + self.screen.blit(self.loading_surface, (0, 0)) + self.loading_surface.set_alpha(self.loading_surface.get_alpha() - 4) + + pygame.display.update() + self.clock.tick(self.fps) + + def get_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + self.exit() + return + + elif event.type == pygame.VIDEORESIZE: + self.window_update(event.size) + + def exit(self): + self.running = False + + self.settings.save() + + print("Bye!") + + def window_update(self, size): + self.settings.window_size = size + + def spawn_sand(self, position): + x, y = position + + for ax in range(-4, 5): + for ay in range(-4, 5): + print(ax, ay) + bx, by = position + bx += ax + by += ay + + if self.matrix[bx, by] == self.sand_surface.map_rgb(self.gray): + self.falling_sand_particles.append(FallingSandParticle(self, (bx, by))) + + +if __name__ == "__main__": + sand = FallingSand() + + while sand.running: + sand.loop() diff --git a/settings.json b/settings.json new file mode 100644 index 0000000..67d7e4d --- /dev/null +++ b/settings.json @@ -0,0 +1 @@ +{"fps": 60, "window_size": [1000, 598]} \ No newline at end of file