Skip to content

Instantly share code, notes, and snippets.

@mrzechonek
Last active May 22, 2017 11:07
Show Gist options
  • Save mrzechonek/385c16207077e443f0279f69fd13e823 to your computer and use it in GitHub Desktop.
Save mrzechonek/385c16207077e443f0279f69fd13e823 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python3.4
import pyglet
from vector import Vector
class Entity:
def __init__(self, name, *args, **kwargs):
self.name = name
super().__init__(*args, **kwargs)
class PositionComponent:
def __init__(self, position, speed, *args, **kwargs):
self.position = position
self.speed = speed
super().__init__(*args, **kwargs)
class MassComponent:
def __init__(self, mass, *args, **kwargs):
self.mass = mass
super().__init__(*args, **kwargs)
class RadiationComponent:
def __init__(self, intensity, *args, **kwargs):
self.intensity = intensity
super().__init__(*args, **kwargs)
class TailComponent:
def __init__(self, tail, *args, **kwargs):
self.tail = tail
super().__init__(*args, **kwargs)
class Planet(MassComponent, PositionComponent, Entity):
pass
class Star(MassComponent, PositionComponent, RadiationComponent, Entity):
pass
class Comet(MassComponent, PositionComponent, TailComponent, Entity):
pass
class Universe:
def __init__(self):
self._entities = set()
def add(self, entity):
self._entities.add(entity)
def find_by_components(self, *components):
for entity in self._entities:
if all(isinstance(entity, c) for c in components):
yield entity
class DisplaySystem:
def __init__(self, universe, window):
self.universe = universe
self.window = window
self._widgets = {}
self._center = Vector(self.window.width, self.window.height) / 2
def _widget_for_entity(self, entity):
try:
return self._widgets[entity]
except KeyError:
image = pyglet.image.load('images/%s.png' % entity.name.lower())
widget = pyglet.sprite.Sprite(image)
self._widgets[entity] = widget
return widget
def _project(self, entity):
widget = self._widget_for_entity(entity)
scaled = self._center + entity.position / (7.5 * 10**8)
widget.x = scaled.x - widget.width/2
widget.y = scaled.y - widget.height/2
return widget
def process(self, dt):
for entity in self.universe.find_by_components(PositionComponent):
widget = self._project(entity)
widget.draw()
class GravitySystem:
G = 6.67408 * 10**-11
def __init__(self, universe, timescale=None):
self.universe = universe
self.timescale = timescale
def _acceleration(self, entity, other):
distance = entity.position - other.position
force = (self.G * entity.mass * other.mass) / abs(distance)**2
direction = -distance / abs(distance)
return direction * force / entity.mass
def process(self, dt):
for entity in self.universe.find_by_components(PositionComponent, MassComponent):
acceleration = Vector(0, 0)
for other in self.universe.find_by_components(PositionComponent, MassComponent):
if entity is other:
continue
acceleration += self._acceleration(entity, other)
entity.speed += acceleration * dt * self.timescale
entity.position += entity.speed * dt * self.timescale
if __name__ == '__main__':
window = pyglet.window.Window()
universe = Universe()
universe.add(
Star(
name='Sol',
position=Vector(0, 0),
speed=Vector(0, 0),
mass=1.9884 * 10**30,
intensity=None,
)
)
universe.add(
Planet(
name='Earth',
position=Vector(0, 149.6 * 10**9),
speed=Vector(29.78 * 10**3, 0),
mass=5.9722 * 10**24,
)
)
display = DisplaySystem(universe, window)
gravity = GravitySystem(universe, 30 * 24 * 3600)
@window.event
def on_draw():
window.clear()
display.process(pyglet.clock)
pyglet.clock.schedule_interval(gravity.process, 1/60)
pyglet.app.run()
import math
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __neg__(self):
return self * -1
def __add__(self, vector):
return Vector(self.x + vector.x, self.y + vector.y)
def __sub__(self, vector):
return Vector(self.x - vector.x, self.y - vector.y)
def __mul__(self, number):
return Vector(self.x * number, self.y * number)
def __truediv__(self, number):
return Vector(self.x / number, self.y / number)
def __floordiv__(self, number):
return Vector(self.x // number, self.y // number)
def __abs__(self):
return math.sqrt(self.x ** 2 + self.y ** 2)
def __str__(self):
return '(%f, %f)' % (self.x, self.y)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment