Compare commits

...
2 Commits
Author SHA1 Message Date
nejdetckenobi 9114238ef8 Restructures project 2026-10-17 18:02:09 +03:00
nejdetckenobi 863f39c2d2 Bumps ECS 2026-10-17 18:01:59 +03:00
10 changed files with 151 additions and 128 deletions

No files matched your search

Submodule libs/ecs updated: 8ad4106b36...ce5eedbea2.
+6
View File
@@ -0,0 +1,6 @@
from src.game import Game
if __name__ == "__main__":
game = Game()
game.run()
View File
File renamed without changes.
+85
View File
@@ -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()
+7 -14
View File
@@ -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)
+11
View File
@@ -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)
+6 -6
View File
@@ -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]
+34
View File
@@ -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,
)
)
+1 -1
View File
@@ -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")
-106
View File
@@ -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()