Planet and spaceship creation, travel and destruction
This commit is contained in:
1 parent
ca9e8a2f19
commit
90e421909a
7 files changed
+307
No files matched your search
@@ -1,3 +1,4 @@
|
|||||||
|
.vscode
|
||||||
.venv
|
.venv
|
||||||
*.pyc
|
*.pyc
|
||||||
**__pycache__/
|
**__pycache__/
|
||||||
@@ -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
@@ -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)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
pyglet
|
||||||
+11
@@ -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
@@ -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
|
||||||
@@ -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()
|
||||||
Reference in new issue
Block a user