mirror of
https://github.com/quantum5/punyverse.git
synced 2025-08-02 22:08:17 -04:00
This paves the way to use OpenGL core profile in the future while still using legacy to draw the simple loader.
151 lines
5.1 KiB
Python
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
|