Planet and spaceship creation, travel and destruction

This commit is contained in:
nejdetckenobi committed 2026-10-10 19:27:52 +03:00
1 parent ca9e8a2f19
commit 90e421909a
7 files changed
+307

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
.vscode
.venv
*.pyc
**__pycache__/
+67
View File
@@ -0,0 +1,67 @@
from dataclasses import dataclass, field
from random import randrange
def default_rotation():
return randrange(0, 359)
@dataclass
class Vector2D:
x: float
y: float
def __iadd__(self, other):
self.x += other.x
self.y += other.y
return self
def __add__(self, other):
return Vector2D(
x=self.x + other.x,
y=self.y + other.y,
)
def __sub__(self, other):
return Vector2D(
x=self.x - other.x,
y=self.y - other.y,
)
def __abs__(self):
return (self.x * self.x + self.y * self.y) ** 0.5
@dataclass
class Position(Vector2D):
pass
@dataclass
class Target(Vector2D):
pass
@dataclass
class Speed(Vector2D):
pass
@dataclass
class Color:
value: tuple[int, int, int, int]
@dataclass
class Radius:
value: int
@dataclass
class SpaceShipMarker:
pass
@dataclass
class PlanetMarker:
pass
+96
View File
@@ -0,0 +1,96 @@
from pyglet.shapes import Circle, Line
from libs.ecs import World
from components import (
Color,
PlanetMarker,
Position,
Radius,
SpaceShipMarker,
Target,
)
from random import randint, sample
from settings import (
MIN_PLANET_RADIUS,
MAX_PLANET_RADIUS,
SCREEN_WIDTH,
SCREEN_HEIGHT,
SPACESHIP_COLOR,
SPACESHIP_PATH_COLOR,
SPACESHIP_RADIUS,
)
def create_planet(
world: World,
x: int,
y: int,
radius: int,
color: tuple[int, int, int, int],
) -> int:
return world.spawn(
PlanetMarker(),
Position(x=x, y=y),
Color(value=color),
Circle(x=x, y=y, radius=radius, color=color),
Radius(radius),
)
def create_spaceship(
world: World,
src_x: int,
src_y: int,
dest_x: int,
dest_y: int,
approach_radius: int,
):
return world.spawn(
SpaceShipMarker(),
Position(x=src_x, y=src_y),
Target(x=dest_x, y=dest_y),
Radius(approach_radius),
Circle(x=src_x, y=src_y, radius=SPACESHIP_RADIUS, color=SPACESHIP_COLOR),
Line(x=src_x, y=src_y, x2=dest_x, y2=dest_y, color=SPACESHIP_PATH_COLOR),
)
def generate_random_planet(world: World) -> int:
radius: int = randint(MIN_PLANET_RADIUS, MAX_PLANET_RADIUS)
x: int = randint(radius, SCREEN_WIDTH - radius)
y: int = randint(radius, SCREEN_HEIGHT - radius)
color = (randint(0, 255), randint(0, 255), randint(0, 255), 255)
return create_planet(world, x, y, radius, color)
def create_travelling_spaceship(
world: World,
src_planet: int,
dest_planet: int,
):
src_planet_cs = world.get_components(src_planet)
if src_planet_cs is None:
raise Exception("invalid_planet")
dest_planet_cs = world.get_components(dest_planet)
if dest_planet_cs is None:
raise Exception("invalid_planet")
source_pos = src_planet_cs[Position]
dest_pos = dest_planet_cs[Position]
approach_radius = dest_planet_cs[Radius].value
return create_spaceship(
world,
src_x=source_pos.x,
src_y=source_pos.y,
dest_x=dest_pos.x,
dest_y=dest_pos.y,
approach_radius=approach_radius,
)
def generate_random_spaceship(world: World) -> int:
planets = [entity for entity, _ in world.query(PlanetMarker)]
_planet_sample = sample(planets, 2)
return create_travelling_spaceship(world, *_planet_sample)
+1
View File
@@ -0,0 +1 @@
pyglet
+11
View File
@@ -0,0 +1,11 @@
FPS = 60
SCREEN_WIDTH = 1280
SCREEN_HEIGHT = 1024
FULLSCREEN = False
MAX_PLANET_RADIUS = 50
MIN_PLANET_RADIUS = 20
SPACESHIP_RADIUS = 5
SPACESHIP_COLOR = (255, 255, 255, 255)
SPACESHIP_PATH_COLOR = (127, 127, 127, 127)
SPACESHIP_SPEED = 500
+64
View File
@@ -0,0 +1,64 @@
from pyglet.shapes import Circle
from libs.ecs import World
from components import (
PlanetMarker,
Position,
Color,
Radius,
SpaceShipMarker,
Target,
Vector2D,
)
from settings import SPACESHIP_COLOR, SPACESHIP_RADIUS, SPACESHIP_SPEED
class PlanetRenderSyncSystem:
@classmethod
def process(cls, world: World, **args):
for _, component_storage in world.query(PlanetMarker):
pos: Position = component_storage[Position]
color: Color = component_storage[Color]
radius: Radius = component_storage[Radius]
circle: Circle = component_storage[Circle]
circle.radius = radius.value
circle.x, circle.y = pos.x, pos.y
circle.color = color.value
class SpaceShipRenderSyncSystem:
@classmethod
def process(cls, world: World, **args):
for _, component_storage in world.query(SpaceShipMarker):
pos: Position = component_storage[Position]
circle: Circle = component_storage[Circle]
circle.radius = SPACESHIP_RADIUS
circle.x, circle.y = pos.x, pos.y
circle.color = SPACESHIP_COLOR
class SpaceShipKillSystem:
@classmethod
def process(cls, world: World, **args):
marked_for_death = []
for entity, component_storage in world.query(SpaceShipMarker):
pos: Position = component_storage[Position]
target: Target = component_storage[Target]
approach_radius = component_storage[Radius]
if abs(pos - target) < approach_radius.value:
marked_for_death.append(entity)
for entity in marked_for_death:
world.get_components(entity=entity, pop=True)
class SpaceShipTravelSystem:
@classmethod
def process(cls, world: World, **args):
for _, component_storage in world.query(SpaceShipMarker):
pos: Position = component_storage[Position]
target: Target = component_storage[Target]
diff: Vector2D = target - pos
diff_mag = abs(diff)
pos.x = pos.x + args["dt"] * SPACESHIP_SPEED * diff.x / diff_mag
pos.y = pos.y + args["dt"] * SPACESHIP_SPEED * diff.y / diff_mag
+67
View File
@@ -0,0 +1,67 @@
from functools import partial
from random import randint
import pyglet
from pyglet.shapes import Circle, Line
from components import PlanetMarker, SpaceShipMarker
from helpers import generate_random_planet, generate_random_spaceship
from libs.ecs import World
from systems import (
PlanetRenderSyncSystem,
SpaceShipKillSystem,
SpaceShipRenderSyncSystem,
SpaceShipTravelSystem,
)
from settings import FPS, FULLSCREEN, SCREEN_WIDTH, SCREEN_HEIGHT
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)
for i in range(10):
generate_random_spaceship(world)
@window.event
def on_draw():
window.clear()
for _, component_storage in world.query(SpaceShipMarker):
component_storage[Line].draw()
for _, component_storage in world.query(PlanetMarker):
component_storage[Circle].draw()
for _, component_storage in world.query(SpaceShipMarker):
component_storage[Circle].draw()
def on_update(dt):
world.tick(dt=dt)
def periodic_random_spaceship_generation(*args, **kwargs):
for i in range(randint(1, 5)):
generate_random_spaceship(world=world)
pyglet.clock.schedule_interval(on_update, 1 / FPS)
pyglet.clock.schedule_interval(periodic_random_spaceship_generation, 0.5)
pyglet.app.run()