From 9114238ef8a34fab4745b4a64fead1334b102599 Mon Sep 17 00:00:00 2001 From: nejdetckenobi Date: Sat, 17 Oct 2026 18:02:09 +0300 Subject: [PATCH] Restructures project --- run.py | 6 ++ components.py => src/components.py | 0 src/game.py | 85 +++++++++++++++++++++++ helpers.py => src/helpers.py | 21 ++---- src/state.py | 11 +++ systems.py => src/systems.py | 12 ++-- src/world.py | 34 +++++++++ test.py | 2 +- ui.py | 106 ----------------------------- 9 files changed, 150 insertions(+), 127 deletions(-) create mode 100644 run.py rename components.py => src/components.py (100%) create mode 100644 src/game.py rename helpers.py => src/helpers.py (86%) create mode 100644 src/state.py rename systems.py => src/systems.py (88%) create mode 100644 src/world.py delete mode 100644 ui.py diff --git a/run.py b/run.py new file mode 100644 index 0000000..b181d0e --- /dev/null +++ b/run.py @@ -0,0 +1,6 @@ +from src.game import Game + +if __name__ == "__main__": + game = Game() + + game.run() diff --git a/components.py b/src/components.py similarity index 100% rename from components.py rename to src/components.py diff --git a/src/game.py b/src/game.py new file mode 100644 index 0000000..8430654 --- /dev/null +++ b/src/game.py @@ -0,0 +1,85 @@ +from dataclasses import dataclass, field +from random import randint +from typing import cast + +import pyglet +from pyglet.window import Window +from pyglet.window.mouse import LEFT +from pyglet.shapes import Circle, Line +from src.components import ( + PlanetMarker, + Position, + Radius, + SpaceShipMarker, + Vector2D, +) +from src.helpers import generate_random_planet +from src.world import world +from settings import FPS, FULLSCREEN, SCREEN_WIDTH, SCREEN_HEIGHT + + +class Game(Window): + def __init__(self, *args, **kwargs) -> None: + super(Game, self).__init__( + caption="SpaceTrader", + width=SCREEN_WIDTH, + height=SCREEN_HEIGHT, + fullscreen=FULLSCREEN, + ) + self.world = world + for _ in range(12): + generate_random_planet(self.world) + + def on_draw(self): + self.clear() + for _, line in self.world.state.routes.items(): + line.draw() + + for _, component_storage in self.world.query(SpaceShipMarker): + component_storage[Circle].draw() + + for _, component_storage in self.world.query(PlanetMarker): + component_storage[Circle].draw() + + def on_mouse_release(self, x, y, button, modifiers): + if button != LEFT: + return + closest_entity, component_storage = min( + self.world.query(PlanetMarker), + key=lambda p: abs(p[1][Position] - Vector2D(x, y)), + ) + pos = component_storage[Position] + if component_storage[Radius].value < abs(pos - Vector2D(x, y)): + print("DESELECT") + self.world.state.selected_planet = None + elif self.world.state.selected_planet is None: + print("SELECT") + self.world.state.selected_planet = closest_entity + elif self.world.state.selected_planet != closest_entity: + first_planet, second_planet = ( + (self.world.state.selected_planet, closest_entity) + if self.world.state.selected_planet > closest_entity + else (closest_entity, self.world.state.selected_planet) + ) + fpos: Position = self.world.get_components(first_planet)[Position] + spos: Position = self.world.get_components(second_planet)[Position] + route_key = (first_planet, second_planet) + if route_key in self.world.state.routes: + print("ROUTE DELETE") + self.world.state.routes.pop(route_key) + else: + print("ROUTE CREATE") + self.world.state.routes[route_key] = Line( + x=fpos.x, + y=fpos.y, + x2=spos.x, + y2=spos.y, + ) + self.world.state.selected_planet = None + + def on_update(self, dt): + self.world.tick(dt=dt) + + def run(self): + pyglet.clock.schedule_interval(self.on_update, 1 / FPS) + pyglet.app.run() diff --git a/helpers.py b/src/helpers.py similarity index 86% rename from helpers.py rename to src/helpers.py index c02ce8f..bad3c38 100644 --- a/helpers.py +++ b/src/helpers.py @@ -2,8 +2,8 @@ from dataclasses import dataclass, field from typing import cast from pyglet.shapes import Circle, Line -from libs.ecs.world import World -from components import ( +from libs.ecs.world import BaseWorld +from src.components import ( Color, PlanetMarker, Position, @@ -22,17 +22,10 @@ from settings import ( SPACESHIP_PATH_COLOR, SPACESHIP_RADIUS, ) -from libs.ecs.state import BaseGameState - - -@dataclass -class GameState(BaseGameState): - selected_planet: int | None = None - routes: dict[tuple[int, int], "Line"] = field(default_factory=dict) def create_planet( - world: World, + world: BaseWorld, x: float, y: float, radius: int, @@ -48,7 +41,7 @@ def create_planet( def create_spaceship( - world: World, + world: BaseWorld, src_x: float, src_y: float, dest_x: float, @@ -69,7 +62,7 @@ def create_spaceship( ) -def generate_random_planet(world: World) -> int: +def generate_random_planet(world: BaseWorld) -> int: radius: int = randint(MIN_PLANET_RADIUS, MAX_PLANET_RADIUS) x: float = float(randint(radius, SCREEN_WIDTH - radius)) y: float = float(randint(radius, SCREEN_HEIGHT - radius)) @@ -79,7 +72,7 @@ def generate_random_planet(world: World) -> int: def create_travelling_spaceship( - world: World, + world: BaseWorld, src_planet: int, dest_planet: int, ): @@ -103,7 +96,7 @@ def create_travelling_spaceship( ) -def generate_random_spaceship(world: World) -> int: +def generate_random_spaceship(world: BaseWorld) -> int: planets = [entity for entity, _ in world.query(PlanetMarker)] _planet_sample = sample(planets, 2) diff --git a/src/state.py b/src/state.py new file mode 100644 index 0000000..a4207a5 --- /dev/null +++ b/src/state.py @@ -0,0 +1,11 @@ +from dataclasses import dataclass, field + +from pyglet.shapes import Line + +from libs.ecs.state import BaseGameState + + +@dataclass +class GameState(BaseGameState): + selected_planet: int | None = None + routes: dict[tuple[int, int], "Line"] = field(default_factory=dict) diff --git a/systems.py b/src/systems.py similarity index 88% rename from systems.py rename to src/systems.py index df2af80..abb7d91 100644 --- a/systems.py +++ b/src/systems.py @@ -1,7 +1,7 @@ from pyglet.shapes import Circle -from libs.ecs.world import World -from components import ( +from libs.ecs.world import BaseWorld +from src.components import ( PlanetMarker, Position, Color, @@ -15,7 +15,7 @@ from settings import SPACESHIP_COLOR, SPACESHIP_RADIUS, SPACESHIP_SPEED class PlanetRenderSyncSystem: @classmethod - def process(cls, world: World, **args): + def process(cls, world: BaseWorld, **args): for _, component_storage in world.query(PlanetMarker): pos: Position = component_storage[Position] color: Color = component_storage[Color] @@ -28,7 +28,7 @@ class PlanetRenderSyncSystem: class SpaceShipRenderSyncSystem: @classmethod - def process(cls, world: World, **args): + def process(cls, world: BaseWorld, **args): for _, component_storage in world.query(SpaceShipMarker): pos: Position = component_storage[Position] circle: Circle = component_storage[Circle] @@ -39,7 +39,7 @@ class SpaceShipRenderSyncSystem: class SpaceShipKillSystem: @classmethod - def process(cls, world: World, **args): + def process(cls, world: BaseWorld, **args): marked_for_death = [] for entity, component_storage in world.query(SpaceShipMarker): pos: Position = component_storage[Position] @@ -53,7 +53,7 @@ class SpaceShipKillSystem: class SpaceShipTravelSystem: @classmethod - def process(cls, world: World, **args): + def process(cls, world: BaseWorld, **args): for _, component_storage in world.query(SpaceShipMarker): pos: Position = component_storage[Position] target: Destination = component_storage[Destination] diff --git a/src/world.py b/src/world.py new file mode 100644 index 0000000..501e69a --- /dev/null +++ b/src/world.py @@ -0,0 +1,34 @@ +from dataclasses import dataclass, field + +from pyglet.shapes import Line + +from libs.ecs.world import BaseWorld +from libs.ecs.state import BaseGameState +from src.systems import ( + PlanetRenderSyncSystem, + SpaceShipKillSystem, + SpaceShipRenderSyncSystem, + SpaceShipTravelSystem, +) + + +@dataclass +class GameState(BaseGameState): + selected_planet: int | None = None + routes: dict[tuple[int, int], "Line"] = field(default_factory=dict) + + +@dataclass +class World(BaseWorld): + state: GameState = field(default_factory=GameState) + + +world = World() +world.systems.extend( + ( + SpaceShipKillSystem, + PlanetRenderSyncSystem, + SpaceShipRenderSyncSystem, + SpaceShipTravelSystem, + ) +) diff --git a/test.py b/test.py index f4bcd54..47f21e0 100644 --- a/test.py +++ b/test.py @@ -1,4 +1,4 @@ -from helpers import normalize_name, load_items +from src.helpers import normalize_name, load_items if __name__ == "__main__": items = load_items("assets/goods.txt") diff --git a/ui.py b/ui.py deleted file mode 100644 index b3dbc47..0000000 --- a/ui.py +++ /dev/null @@ -1,106 +0,0 @@ -from dataclasses import dataclass, field -from random import randint -from typing import cast - -import pyglet -from pyglet.window.mouse import LEFT -from pyglet.shapes import Circle, Line -from components import ( - PlanetMarker, - Position, - Radius, - SpaceShipMarker, - Vector2D, -) -from helpers import ( - GameState, - generate_random_planet, -) -from libs.ecs.world import World -from systems import ( - PlanetRenderSyncSystem, - SpaceShipKillSystem, - SpaceShipRenderSyncSystem, - SpaceShipTravelSystem, -) -from settings import FPS, FULLSCREEN, SCREEN_WIDTH, SCREEN_HEIGHT - -game_state = GameState() -world = World() -world.systems.extend( - ( - SpaceShipKillSystem, - PlanetRenderSyncSystem, - SpaceShipRenderSyncSystem, - SpaceShipTravelSystem, - ) -) - - -window = pyglet.window.Window( - caption="SpaceTrader", - width=SCREEN_WIDTH, - height=SCREEN_HEIGHT, - fullscreen=FULLSCREEN, -) - -for _ in range(12): - generate_random_planet(world) - - -@window.event -def on_draw(): - window.clear() - for _, line in game_state.routes.items(): - line.draw() - - for _, component_storage in world.query(SpaceShipMarker): - component_storage[Circle].draw() - - for _, component_storage in world.query(PlanetMarker): - component_storage[Circle].draw() - - -@window.event -def on_mouse_release(x, y, button, modifiers): - if button != LEFT: - return - closest_entity, component_storage = min( - world.query(PlanetMarker), - key=lambda p: abs(p[1][Position] - Vector2D(x, y)), - ) - pos = component_storage[Position] - if component_storage[Radius].value < abs(pos - Vector2D(x, y)): - print("DESELECT") - game_state.selected_planet = None - elif game_state.selected_planet is None: - print("SELECT") - game_state.selected_planet = closest_entity - elif game_state.selected_planet != closest_entity: - first_planet, second_planet = sorted( - (game_state.selected_planet, closest_entity) - ) - fpos: Position = cast(dict, world.get_components(first_planet))[Position] - spos: Position = cast(dict, world.get_components(second_planet))[Position] - route_key = (first_planet, second_planet) - if route_key in game_state.routes: - print("ROUTE DELETE") - game_state.routes.pop(route_key) - else: - print("ROUTE CREATE") - game_state.routes[route_key] = Line( - x=fpos.x, - y=fpos.y, - x2=spos.x, - y2=spos.y, - ) - game_state.selected_planet = None - - -def on_update(dt): - world.tick(dt=dt) - - -pyglet.clock.schedule_interval(on_update, 1 / FPS) - -pyglet.app.run()