punyverse/punyverse/world.py
Quantum 13e247bea3 Use dedicated loader window to perform loading.
This paves the way to use OpenGL core profile in the future while still using legacy to draw the simple loader.
2018-08-24 15:32:17 -04:00

151 lines
5.1 KiB
Python

from __future__ import division
import json
import os
from collections import OrderedDict
import six
from punyverse import texture
from punyverse.camera import Camera
from punyverse.entity import *
try:
from punyverse._model import model_list, load_model
except ImportError:
from punyverse.model import model_list, load_model
def load_world(file, callback=lambda message, completion: None):
return World(file, callback)
class World(object):
def __init__(self, file, callback):
self.tracker = []
self.x = None
self.y = None
self.z = None
self.tick_length = 0
self.tick = 0
self.asteroids = AsteroidManager()
self.cam = Camera()
self.callback = callback
self._parse(file)
del self.callback # So it can't be used after loading finishes
self._time_accumulate = 0
for entity in self.tracker:
entity.update()
def evaluate(self, value):
return eval(str(value), {'__builtins__': None}, self._context)
@property
def length(self):
return self._length
@property
def au(self):
return self._au
def _parse(self, file):
self.callback('Parsing configuration...', 'Loading configuration file...', 0)
with open(os.path.join(os.path.dirname(__file__), file)) as f:
root = json.load(f, object_pairs_hook=OrderedDict)
self._au = root.get('au', 2000)
self._length = root.get('length', 4320)
self._context = {'AU': self._au, 'TEXTURE': texture.max_texture_size(), 'KM': 1.0 / self._length}
self.tick_length = root.get('tick', 4320) # How many second is a tick?
# Need to know how many objects are being loaded
self._objects = 0
self._current_object = 0
def count_objects(bodies):
for body in six.itervalues(bodies):
self._objects += 1
count_objects(body.get('satellites', {}))
count_objects(root['bodies'])
if 'start' in root:
info = root['start']
self.cam.x = self.evaluate(info.get('x', 0))
self.cam.y = self.evaluate(info.get('y', 0))
self.cam.z = self.evaluate(info.get('z', 0))
self.cam.pitch = self.evaluate(info.get('pitch', 0))
self.cam.yaw = self.evaluate(info.get('yaw', 0))
self.cam.roll = self.evaluate(info.get('roll', 0))
for planet, info in six.iteritems(root['bodies']):
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
'Loading %s.' % planet, self._current_object / self._objects)
self._body(planet, info)
self._current_object += 1
if 'belts' in root:
belt_count = len(root['belts'])
for i, (name, info) in enumerate(six.iteritems(root['belts']), 1):
self.callback('Loading belts (%d of %d)...' % (i, belt_count),
'Loading %s.' % name, i / belt_count)
self.tracker.append(Belt(name, self, info))
if 'sky' in root:
self.callback('Loading sky...', 'Loading sky.', 0)
self.tracker.append(Sky(self, root['sky']))
if 'asteroids' in root:
asteroids = root['asteroids']
for i, file in enumerate(asteroids):
self.callback('Loading asteroids...', 'Loading %s...' % file, i / len(asteroids))
self.asteroids.load(file)
def _body(self, name, info, parent=None):
if 'texture' in info:
body = SphericalBody(name, self, info, parent)
elif 'model' in info:
body = ModelBody(name, self, info, parent)
else:
raise ValueError('Nothing to load for %s.' % name)
if parent:
parent.satellites.append(body)
else:
self.tracker.append(body)
for satellite, info in six.iteritems(info.get('satellites', {})):
self.callback('Loading objects (%d of %d)...' % (self._current_object, self._objects),
'Loading %s, satellite of %s.' % (satellite, name), self._current_object / self._objects)
self._body(satellite, info, body)
self._current_object += 1
def spawn_asteroid(self):
if self.asteroids:
c = self.cam
dx, dy, dz = c.direction()
speed = abs(self.cam.speed) * 1.1 + 5
self.tracker.append(self.asteroids.new((c.x, c.y - 3, c.z + 5), (dx * speed, dy * speed, dz * speed)))
def update(self, dt, move, tick):
c = self.cam
c.update(dt, move)
if tick:
delta = self.tick_length * dt
update = int(delta + self._time_accumulate + 0.5)
if update:
self._time_accumulate = 0
self.tick += update
for entity in self.tracker:
entity.update()
collision = entity.collides(c.x, c.y, c.z)
if collision:
c.speed *= -1
c.move(c.speed * 12 * dt)
else:
self._time_accumulate += delta