punyverse/punyverse/world.py
2018-08-24 14:44:11 -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, '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