adds labyrinth and subjects as well as performance increases

This commit is contained in:
zomseffen 2022-02-07 21:08:45 +01:00
parent 6c5cae958b
commit 0638d5e666
10 changed files with 1591 additions and 234 deletions

View file

@ -41,10 +41,30 @@ def value_to_color(v, min_value, max_value):
class Client: class Client:
def __init__(self, test=False, pos=[0, 0, 0]): def __init__(self, test=False, pos=[0, 0, 0], world_class=WorldProvider):
self.state = 0 self.state = 0
with open('./config.json', 'r') as f: with open('./config.json', 'r') as f:
self.config = json.load(f) self.config = json.load(f)
self.init_shaders()
self.world_provider = world_class(self.normal_program)
self.draw_world()
self.pos = pos
self.time = time.time()
glutReshapeFunc(self.resize)
glutDisplayFunc(self.display)
glutKeyboardFunc(self.keyboardHandler)
glutSpecialFunc(self.funcKeydHandler)
if not test:
glutMainLoop()
else:
self.display()
self.resize(100, 100)
def init_shaders(self):
glutInit(sys.argv) glutInit(sys.argv)
self.width = 1920 self.width = 1920
self.height = 1080 self.height = 1080
@ -96,7 +116,7 @@ class Client:
self.depth_program[self.normal_program[key]] = Spotlight.getDepthProgram(self.vertex_shader_id, self.depth_program[self.normal_program[key]] = Spotlight.getDepthProgram(self.vertex_shader_id,
key.GeometryShaderId) key.GeometryShaderId)
self.world_provider = WorldProvider(self.normal_program) def draw_world(self):
for x_pos in range(0, 100): for x_pos in range(0, 100):
for y_pos in range(0, 100): for y_pos in range(0, 100):
for z_pos in range(0, 1): for z_pos in range(0, 1):
@ -118,97 +138,11 @@ class Client:
r, g, b = colors[int(self.world_provider.world.plates[x_pos, y_pos])] r, g, b = colors[int(self.world_provider.world.plates[x_pos, y_pos])]
self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b) self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b)
# total_x = self.world_provider.world.chunk_n_x * self.world_provider.world.chunk_size_x
# total_y = self.world_provider.world.chunk_n_y * self.world_provider.world.chunk_size_y
# for x_pos in range(0, 100):
# for y_pos in range(0, 100):
# if self.world_provider.world.faults[x_pos, y_pos] == -2:
# self.world_provider.world.set_color(x_pos, y_pos, 0, 0, 0, 0)
#
# for line_index, line in enumerate(self.world_provider.world.fault_lines):
# for x_pos in range(0, 100):
# for y_pos in range(0, 100):
# if self.world_provider.world.faults[x_pos, y_pos] == line_index:
# if line_index != 9:
# self.world_provider.world.set_color(x_pos, y_pos, 0, 0, 0, 1)
# else:
# self.world_provider.world.set_color(x_pos, y_pos, 0, 1, 1, 1)
#
# for x_pos in range(0, 100):
# for y_pos in range(0, 100):
# for z_pos in range(0, 1):
# if [x_pos, y_pos] in self.world_provider.world.fault_nodes:
# r, g, b = 1, 0, 0
# self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b)
# # visualize direction lengths
# lengths = np.sqrt(np.sum(np.square(self.world_provider.world.directions), axis=2))
# lengths = lengths / np.max(lengths)
# for x_pos in range(0, 100):
# for y_pos in range(0, 100):
# for z_pos in range(0, 1):
# r, g, b = lengths[x_pos, y_pos], lengths[x_pos, y_pos], lengths[x_pos, y_pos]
# self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b)
self.projMatrix = perspectiveMatrix(45.0, 400 / 400, 0.01, MAX_DISTANCE) self.projMatrix = perspectiveMatrix(45.0, 400 / 400, 0.01, MAX_DISTANCE)
self.rx = self.cx = self.cy = 0 self.rx = self.cx = self.cy = 0
self.opening = 45 self.opening = 45
glutReshapeFunc(self.resize)
glutDisplayFunc(self.display)
glutKeyboardFunc(self.keyboardHandler)
glutSpecialFunc(self.funcKeydHandler)
self.pos = pos
self.time = time.time()
self.field = (100, 100, 1)
self.e_a = np.array([
[0, 0, 0],
[1, 0, 0],
[1, 1, 0],
[0, 1, 0],
[-1, 1, 0],
[-1, 0, 0],
[-1, -1, 0],
[0, -1, 0],
[1, -1, 0],
])
self.relaxation_time = 0.55 # 0.55
self.w_a = [
4.0 / 9.0,
1.0 / 9.0,
1.0 / 36.0,
1.0 / 9.0,
1.0 / 36.0,
1.0 / 9.0,
1.0 / 36.0,
1.0 / 9.0,
1.0 / 36.0
]
self.n_a = np.zeros((len(self.e_a),) + self.field)
self.n_a_eq = np.zeros(self.n_a.shape)
self.n = np.zeros(self.field)
self.n[:, :, :] += 1.0
self.gravity_applies = np.zeros(self.field)
# self.n /= np.sum(self.n)
self.n_a[0] = np.array(self.n)
self.u = np.zeros(self.field + (self.e_a.shape[1],))
self.compressible = True
self.max_n = self.w_a[0]
self.test_pixel = [40, 50, 0]
if not test:
glutMainLoop()
else:
self.display()
self.resize(100, 100)
def display(self): def display(self):
glClearColor(0, 0, 0, 0) glClearColor(0, 0, 0, 0)
@ -261,41 +195,7 @@ class Client:
glutSwapBuffers() glutSwapBuffers()
min_value = 0 print('fps', 1.0 / (time.time() - self.time))
max_value_n = np.max(self.n)
# max_value_n = 1.0
vel = np.sqrt(np.sum(np.square(self.u), axis=3)) *self.n
max_value_vel = np.max(vel)
# max_value_vel = np.sqrt(3)
# print('round')
# print('sum n: %f' % np.sum(self.n))
# print('max n: %f' % np.max(self.n))
# print('min n: %f' % np.min(self.n))
# print('sum vel: %f' % np.sum(vel))
# print('max vel: %f' % np.max(vel))
# print('min vel: %f' % np.min(vel))
# for x_pos in range(0, 100):
# for y_pos in range(0, 100):
# for z_pos in range(0, 1):
# # if self.state == 2:
# # r, g, b = value_to_color(int(self.gravity_applies[x_pos, y_pos, z_pos]), 0, 1)
# # if self.state == 1:
# # r, g, b = value_to_color(vel[x_pos, y_pos, z_pos], min_value, max_value_vel)
# # if self.state == 0:
# # r, g, b = value_to_color(self.n[x_pos, y_pos, z_pos], min_value, max_value_n)
# r, g, b, = 128, 128, 128
# if [x_pos, y_pos] in self.world_provider.world.fault_nodes:
# r, g, b = 128, 0, 0
#
# self.world_provider.world.set_color(x_pos, y_pos, z_pos, r, g, b)
# self.world_provider.world.set_color(int(round(self.test_pixel[0])),
# int(round(self.test_pixel[1])),
# int(round(self.test_pixel[2])), 1.0, 1.0, 1.0)
print(1.0 / (time.time() - self.time))
self.time = time.time() self.time = time.time()
glutPostRedisplay() glutPostRedisplay()

View file

@ -19,6 +19,9 @@ class Structure(Renderable):
self.Objects = {} self.Objects = {}
self.vais = {} self.vais = {}
self.dirty = True self.dirty = True
self.dirty_pos = True
self.dirty_color = True
self.dirty_size = True
self.x_offset = x_offset self.x_offset = x_offset
self.y_offset = y_offset self.y_offset = y_offset
@ -31,6 +34,7 @@ class Structure(Renderable):
@x_offset.setter @x_offset.setter
def x_offset(self, value): def x_offset(self, value):
self.dirty = True self.dirty = True
self.dirty_pos = True
self._x_offset = value self._x_offset = value
@property @property
@ -40,6 +44,7 @@ class Structure(Renderable):
@y_offset.setter @y_offset.setter
def y_offset(self, value): def y_offset(self, value):
self.dirty = True self.dirty = True
self.dirty_pos = True
self._y_offset = value self._y_offset = value
@property @property
@ -49,6 +54,7 @@ class Structure(Renderable):
@z_offset.setter @z_offset.setter
def z_offset(self, value): def z_offset(self, value):
self.dirty = True self.dirty = True
self.dirty_pos = True
self._z_offset = value self._z_offset = value
def addShape(self, program, shape): def addShape(self, program, shape):
@ -56,6 +62,9 @@ class Structure(Renderable):
self.Objects[program] = [] self.Objects[program] = []
self.Objects[program].append(shape) self.Objects[program].append(shape)
self.dirty = True self.dirty = True
self.dirty_color = True
self.dirty_pos = True
self.dirty_size = True
def removeShape(self, program, shape): def removeShape(self, program, shape):
if program in self.Objects.keys(): if program in self.Objects.keys():
@ -63,26 +72,33 @@ class Structure(Renderable):
if len(self.Objects[program]) == 0: if len(self.Objects[program]) == 0:
self.Objects.pop(program) self.Objects.pop(program)
self.dirty = True self.dirty = True
self.dirty_color = True
self.dirty_pos = True
self.dirty_size = True
def buildvertexArrays(self): def buildvertexArrays(self):
if self.dirty: if self.dirty:
self.clearVertexArrays() # self.clearVertexArrays()
glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_COLOR_ARRAY) glEnableClientState(GL_COLOR_ARRAY)
self.vais = {}
for key, objects in self.Objects.items(): for key, objects in self.Objects.items():
needs_new_buffers = key not in self.vais.keys()
if needs_new_buffers:
tvai = GLuint(0) tvai = GLuint(0)
tpbi = GLuint(0) tpbi = GLuint(0)
tcbi = GLuint(0) tcbi = GLuint(0)
tsbi = GLuint(0) tsbi = GLuint(0)
num = len(objects) num = len(objects)
else:
tvai, tpbi, tcbi, tsbi, num = self.vais[key]
if needs_new_buffers:
glGenVertexArrays(1, tvai) glGenVertexArrays(1, tvai)
glBindVertexArray(tvai) glBindVertexArray(tvai)
if self.dirty_pos:
if needs_new_buffers:
vid = glGetAttribLocation(key, "in_position") vid = glGetAttribLocation(key, "in_position")
glEnableVertexAttribArray(vid) glEnableVertexAttribArray(vid)
@ -94,32 +110,39 @@ class Structure(Renderable):
positions.append(o.pos[1] + self.y_offset) positions.append(o.pos[1] + self.y_offset)
positions.append(o.pos[2] + self.z_offset) positions.append(o.pos[2] + self.z_offset)
glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None) glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create position buffer") self.check_error("Could not create position buffer")
if self.dirty_color:
colors = [] colors = []
for o in objects: for o in objects:
colors.append(o.color[0]) colors.append(o.color[0])
colors.append(o.color[1]) colors.append(o.color[1])
colors.append(o.color[2]) colors.append(o.color[2])
if needs_new_buffers:
tcbi = glGenBuffers(1) tcbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tcbi) glBindBuffer(GL_ARRAY_BUFFER, tcbi)
glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
vc = glGetAttribLocation(key, "MyInColor") vc = glGetAttribLocation(key, "MyInColor")
if vc != -1: if vc != -1:
glEnableVertexAttribArray(vc) glEnableVertexAttribArray(vc)
glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None) glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create color buffer") self.check_error("Could not create color buffer")
if self.dirty_size:
if hasattr(objects[0], 'size'): if hasattr(objects[0], 'size'):
sizes = [] sizes = []
for o in objects: for o in objects:
sizes.append(o.size[0]) sizes.append(o.size[0])
sizes.append(o.size[1]) sizes.append(o.size[1])
sizes.append(o.size[2]) sizes.append(o.size[2])
if needs_new_buffers:
tsbi = glGenBuffers(1) tsbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tsbi) glBindBuffer(GL_ARRAY_BUFFER, tsbi)
glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
vs = glGetAttribLocation(key, "MyInSize") vs = glGetAttribLocation(key, "MyInSize")
if vs != -1: if vs != -1:
glEnableVertexAttribArray(vs) glEnableVertexAttribArray(vs)
@ -129,6 +152,9 @@ class Structure(Renderable):
glBindVertexArray(0) glBindVertexArray(0)
self.vais[key] = (tvai, tpbi, tcbi, tsbi, num) self.vais[key] = (tvai, tpbi, tcbi, tsbi, num)
self.dirty = False self.dirty = False
self.dirty_pos = False
self.dirty_color = False
self.dirty_size = False
def clearVertexArrays(self): def clearVertexArrays(self):
temp = dict(self.vais) temp = dict(self.vais)

View file

@ -1,3 +1,5 @@
import time
from Lights.Lights import Light from Lights.Lights import Light
from Objects.Objects import Object from Objects.Objects import Object
from Objects.Renderable import Renderable from Objects.Renderable import Renderable
@ -9,7 +11,8 @@ import math
import numpy as np import numpy as np
import random import random
import sys import sys
import ctypes
float_pointer = ctypes.POINTER(ctypes.c_float)
# Plate Types # Plate Types
SEA_PLATE = 0 SEA_PLATE = 0
CONTINENTAL_PLATE = 1 CONTINENTAL_PLATE = 1
@ -22,6 +25,7 @@ METAMORPH_STONE = 3
SEDIMENTAL_STONE = 4 SEDIMENTAL_STONE = 4
SEDIMENT = 5 SEDIMENT = 5
class WorldChunk(Structure): class WorldChunk(Structure):
def __init__(self, width: int, length: int, height: int, programs: dict): def __init__(self, width: int, length: int, height: int, programs: dict):
assert width > 0, 'Width must be greater than 0' assert width > 0, 'Width must be greater than 0'
@ -38,6 +42,8 @@ class WorldChunk(Structure):
self.height = height self.height = height
self.programs = programs self.programs = programs
self.objects = {}
for x in range(width): for x in range(width):
self.content.append([]) self.content.append([])
self.visible.append([]) self.visible.append([])
@ -54,6 +60,7 @@ class WorldChunk(Structure):
assert 0 <= z < self.height, 'Put out of bounds for z coordinate! Must be between 0 and %i' % self.height assert 0 <= z < self.height, 'Put out of bounds for z coordinate! Must be between 0 and %i' % self.height
no_visibility_changes = (self.content[x][y][z] is None) == (new_object is None) no_visibility_changes = (self.content[x][y][z] is None) == (new_object is None)
old_object = self.content[x][y][z]
self.content[x][y][z] = new_object self.content[x][y][z] = new_object
new_object.translate(translate(x, y, z)) new_object.translate(translate(x, y, z))
@ -87,6 +94,32 @@ class WorldChunk(Structure):
else: else:
self.visible[x][y][z - 1] += change self.visible[x][y][z - 1] += change
# todo: add visibility check for object listing
added = False
if old_object is not None:
if new_object is not None and type(old_object) == type(new_object):
new_object.buffer_id = old_object.buffer_id
self.objects[self.programs[type(old_object)]][old_object.buffer_id] = new_object
added = True
else:
# todo: maybe replace the element with a placeholder that is skipped when rendering/ saving and have a
# cleanup task, since this could be exploited to lower update rates
leading = self.objects[self.programs[type(old_object)]][:old_object.buffer_id]
following = self.objects[self.programs[type(old_object)]][old_object.buffer_id + 1:]
for element in following:
element.buffer_id -= 1
self.objects[self.programs[type(old_object)]] = leading + following
if not added and new_object is not None:
if self.programs[type(new_object)] not in self.objects.keys():
self.objects[self.programs[type(new_object)]] = []
new_object.buffer_id = len(self.objects[self.programs[type(new_object)]])
self.objects[self.programs[type(new_object)]].append(new_object)
self.dirty = True
self.dirty_pos = True
self.dirty_color = True
self.dirty_size = True
return visible_carry_over return visible_carry_over
def get_object(self, x: int, y: int, z: int): def get_object(self, x: int, y: int, z: int):
@ -112,71 +145,80 @@ class WorldChunk(Structure):
def buildvertexArrays(self): def buildvertexArrays(self):
if self.dirty: if self.dirty:
self.clearVertexArrays() # self.clearVertexArrays()
glEnableClientState(GL_VERTEX_ARRAY) glEnableClientState(GL_VERTEX_ARRAY)
glEnableClientState(GL_TEXTURE_COORD_ARRAY) glEnableClientState(GL_TEXTURE_COORD_ARRAY)
glEnableClientState(GL_NORMAL_ARRAY) glEnableClientState(GL_NORMAL_ARRAY)
glEnableClientState(GL_COLOR_ARRAY) glEnableClientState(GL_COLOR_ARRAY)
self.vais = {}
objects = {} for key, object_list in self.objects.items():
counts = {} needs_new_buffers = key not in self.vais.keys()
for x in range(self.width): if needs_new_buffers:
for y in range(self.length):
for z in range(self.height):
if self.content[x][y][z] is not None: # and self.visible[x][y][z] > 0: TODO: check visibility...
if self.programs[type(self.content[x][y][z])] not in objects.keys():
objects[self.programs[type(self.content[x][y][z])]] = []
counts[self.programs[type(self.content[x][y][z])]] = 0
objects[self.programs[type(self.content[x][y][z])]].append(self.content[x][y][z])
counts[self.programs[type(self.content[x][y][z])]] += 1
for key, object_list in objects.items():
tvai = GLuint(0) tvai = GLuint(0)
tpbi = GLuint(0) tpbi = GLuint(0)
tcbi = GLuint(0) tcbi = GLuint(0)
tsbi = GLuint(0) tsbi = GLuint(0)
glGenVertexArrays(1, tvai) glGenVertexArrays(1, tvai)
else:
tvai, tpbi, tcbi, tsbi, old_len = self.vais[key]
glBindVertexArray(tvai) glBindVertexArray(tvai)
if self.dirty_pos:
if needs_new_buffers:
vid = glGetAttribLocation(key, "in_position") vid = glGetAttribLocation(key, "in_position")
glEnableVertexAttribArray(vid) glEnableVertexAttribArray(vid)
tpbi = glGenBuffers(1) tpbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tpbi) glBindBuffer(GL_ARRAY_BUFFER, tpbi)
positions = [] positions = []
for o in object_list: for index, o in enumerate(object_list):
o.buffer_id = index
positions.append(o.pos[0] + self.x_offset) positions.append(o.pos[0] + self.x_offset)
positions.append(o.pos[1] + self.y_offset) positions.append(o.pos[1] + self.y_offset)
positions.append(o.pos[2] + self.z_offset) positions.append(o.pos[2] + self.z_offset)
glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(positions, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None) glVertexAttribPointer(vid, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create position buffer") self.check_error("Could not create position buffer")
if self.dirty_color:
colors = [] colors = []
for o in object_list: for o in object_list:
colors.append(o.color[0]) colors.append(o.color[0])
colors.append(o.color[1]) colors.append(o.color[1])
colors.append(o.color[2]) colors.append(o.color[2])
if needs_new_buffers:
tcbi = glGenBuffers(1) tcbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tcbi) glBindBuffer(GL_ARRAY_BUFFER, tcbi)
if needs_new_buffers or old_len != len(object_list):
glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(colors, dtype=np.float32), GL_STATIC_DRAW)
else:
# todo: check if this improves anything. Timewise it seems to be the same
ptr = ctypes.cast(glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE), float_pointer)
for index, value in enumerate(colors):
ptr[index] = value
glUnmapBuffer(GL_ARRAY_BUFFER)
if needs_new_buffers:
vc = glGetAttribLocation(key, "MyInColor") vc = glGetAttribLocation(key, "MyInColor")
if vc != -1: if vc != -1:
glEnableVertexAttribArray(vc) glEnableVertexAttribArray(vc)
glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None) glVertexAttribPointer(vc, 3, GL_FLOAT, GL_FALSE, 0, None)
self.check_error("Could not create color buffer") self.check_error("Could not create color buffer")
if self.dirty_size:
if hasattr(object_list[0], 'size'): if hasattr(object_list[0], 'size'):
sizes = [] sizes = []
for o in object_list: for o in object_list:
sizes.append(o.size[0]) sizes.append(o.size[0])
sizes.append(o.size[1]) sizes.append(o.size[1])
sizes.append(o.size[2]) sizes.append(o.size[2])
if needs_new_buffers:
tsbi = glGenBuffers(1) tsbi = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, tsbi) glBindBuffer(GL_ARRAY_BUFFER, tsbi)
glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW) glBufferData(GL_ARRAY_BUFFER, np.array(sizes, dtype=np.float32), GL_STATIC_DRAW)
if needs_new_buffers:
vs = glGetAttribLocation(key, "MyInSize") vs = glGetAttribLocation(key, "MyInSize")
if vs != -1: if vs != -1:
glEnableVertexAttribArray(vs) glEnableVertexAttribArray(vs)
@ -184,8 +226,11 @@ class WorldChunk(Structure):
self.check_error("Could not create size buffer") self.check_error("Could not create size buffer")
glBindVertexArray(0) glBindVertexArray(0)
self.vais[key] = (tvai, tpbi, tcbi, tsbi, counts[key]) self.vais[key] = (tvai, tpbi, tcbi, tsbi, len(object_list))
self.dirty = False self.dirty = False
self.dirty_pos = False
self.dirty_color = False
self.dirty_size = False
def render(self, proj_matrix, geometry_rot_matrix, alternate_programs=None, def render(self, proj_matrix, geometry_rot_matrix, alternate_programs=None,
preselected_program=None, projection_pos=None, rot_pos=None): preselected_program=None, projection_pos=None, rot_pos=None):
@ -204,6 +249,17 @@ class WorldChunk(Structure):
if self.content[x][y][z] is not None: if self.content[x][y][z] is not None:
self.content[x][y][z].setColor(r, g, b) self.content[x][y][z].setColor(r, g, b)
self.dirty = True self.dirty = True
self.dirty_color = True
def load(self):
for x in range(self.width):
for y in range(self.length):
for z in range(self.height):
if self.content[x][y][z] is not None: # and self.visible[x][y][z] > 0: TODO: check visibility...
if self.programs[type(self.content[x][y][z])] not in self.objects.keys():
self.objects[self.programs[type(self.content[x][y][z])]] = []
self.objects[self.programs[type(self.content[x][y][z])]].append(self.content[x][y][z])
class World(Renderable): class World(Renderable):
def __init__(self, chunk_size_x: int, chunk_size_y: int, chunk_size_z: int, def __init__(self, chunk_size_x: int, chunk_size_y: int, chunk_size_z: int,
@ -488,6 +544,8 @@ class World(Renderable):
y % self.chunk_size_y, y % self.chunk_size_y,
z % self.chunk_size_z, z % self.chunk_size_z,
r, g, b) r, g, b)
else:
print('Changing color of nonexistant element!')
def put_object(self, x: int, y: int, z: int, new_object: Object): def put_object(self, x: int, y: int, z: int, new_object: Object):
x = x % (self.chunk_size_x * self.chunk_n_x) x = x % (self.chunk_size_x * self.chunk_n_x)

View file

@ -2,8 +2,8 @@ from Objects.World import World
class WorldProvider: class WorldProvider:
def __init__(self, programs): def __init__(self, programs, world_class=World):
self.world: World = World(10, 10, 10, 10, 10, 10, programs) self.world: World = world_class(10, 10, 10, 10, 10, 10, programs)
self.world.generate() self.world.generate()
def update(self): def update(self):

View file

@ -0,0 +1,43 @@
import time
from Client.Client import Client, MAX_DISTANCE
from MatrixStuff.Transformations import perspectiveMatrix
from labirinth_ai.LabyrinthProvider import LabyrinthProvider
import numpy as np
class LabyrinthClient(Client):
def __init__(self, test=False, pos=[0, 0, 0], world_class=LabyrinthProvider):
super(LabyrinthClient, self).__init__(test, pos, world_class)
def draw_world(self):
start_time = time.time()
for x in range(self.world_provider.world.chunk_size_x * self.world_provider.world.chunk_n_x):
for y in range(self.world_provider.world.chunk_size_y * self.world_provider.world.chunk_n_y):
if self.world_provider.world.board[x, y] in [1, 2]:
r, g, b = 57, 92, 152
if 1.5 >= self.world_provider.world.hunter_grass[x, y] > 0.5:
r, g, b = 25, 149, 156
if 3 >= self.world_provider.world.hunter_grass[x, y] > 1.5:
r, g, b = 112, 198, 169
self.world_provider.world.set_color(x, y, 0, r / 255.0, g / 255.0, b / 255.0)
if self.world_provider.world.board[x, y] == 3:
self.world_provider.world.set_color(x, y, 0, 139 / 255.0, 72 / 255.0, 82 / 255.0)
for sub in self.world_provider.world.subjects:
if not sub.random:
# pyxel.rectb(sub.x * 4 + 1, sub.y * 4 + 1, 2, 2, sub.col)
self.world_provider.world.set_color(sub.x, sub.y, 0, sub.r / 255.0, sub.g / 255.0, sub.b / 255.0)
else:
self.world_provider.world.set_color(sub.x, sub.y, 0, 212 / 255.0, 150 / 255.0, 222 / 255.0)
self.projMatrix = perspectiveMatrix(45.0, 400 / 400, 0.01, MAX_DISTANCE)
print('redraw', time.time() - start_time)
def display(self):
super(LabyrinthClient, self).display()
self.draw_world()
self.world_provider.world.update()
if __name__ == '__main__':
client = LabyrinthClient(pos=[-50, -50, -200])

View file

@ -0,0 +1,6 @@
from WorldProvider.WorldProvider import WorldProvider
from labirinth_ai.LabyrinthWorld import LabyrinthWorld
class LabyrinthProvider(WorldProvider):
def __init__(self, programs):
super(LabyrinthProvider, self).__init__(programs, LabyrinthWorld)

View file

@ -0,0 +1,232 @@
import time
from Objects.Cube.Cube import Cube
from Objects.World import World
import numpy as np
import random
class LabyrinthWorld(World):
randomBuffer = 0
batchsize = 1000
randomBuffer = max(4 * batchsize, randomBuffer)
def __init__(self, chunk_size_x: int, chunk_size_y: int, chunk_size_z: int,
chunk_n_x: int, chunk_n_y: int, chunk_n_z: int, programs: dict):
self.board_shape = (chunk_size_x * chunk_n_x, chunk_size_y * chunk_n_y)
self.board = np.zeros(self.board_shape)
super(LabyrinthWorld, self).__init__(chunk_size_x, chunk_size_y, chunk_size_z,
chunk_n_x, chunk_n_y, chunk_n_z, programs)
self.max_room_dim = 20
self.min_room_dim = 6
self.max_room_num = 32
self.max_corridors = 4 * self.max_room_num
self.max_crates = self.max_room_num
self.subjects = []
self.ins = []
self.actions = []
self.targets = []
self.model = None
self.lastUpdate = time.time()
self.nextTrain = self.randomBuffer
self.round = 0
self.trailMix = np.zeros(self.board_shape)
self.grass = np.zeros(self.board_shape)
self.hunter_grass = np.zeros(self.board_shape)
self.subjectDict = {}
def generate(self, seed: int = None, sea_plate_height: int = 50, continental_plate_height: int = 200):
board = np.zeros(self.board_shape)
random.seed(seed)
np.random.seed(seed)
# find random starting point
px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim)
py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim)
# 0, 0 is top left
right = (1, 0)
left = (-1, 0)
up = (0, -1)
down = (0, 1)
# place rooms
room_num = 0
corridor_num = 0
while room_num < self.max_room_num and corridor_num < self.max_corridors:
# try to place Room
w = random.randint(self.min_room_dim, self.max_room_dim)
h = random.randint(self.min_room_dim, self.max_room_dim)
can_place_room = np.sum(
board[px - int(w / 2.0):px + int(w / 2.0), py - int(h / 2.0):py + int(h / 2.0)] == 1) == 0 and px - int(
w / 2.0) >= 0 and px + int(w / 2.0) < self.board_shape[0] and \
py - int(h / 2.0) >= 0 and py + int(h / 2.0) < self.board_shape[1]
if can_place_room:
# place Room
board[px - int(w / 2.0):px + int(w / 2.0), py - int(h / 2.0):py + int(h / 2.0)] = 1
room_num += 1
else:
# move && place Corridor
directions = []
while len(directions) == 0:
movable = []
corridor_length = random.randint(self.min_room_dim, self.max_room_dim)
if px - corridor_length >= 0:
movable.append(left)
if board[px - 1, py] != 2:
directions.append(left)
if px + corridor_length < self.board_shape[0]:
movable.append(right)
if board[px + 1, py] != 2:
directions.append(right)
if py - corridor_length >= 0:
movable.append(up)
if board[px, py - 1] != 2:
directions.append(up)
if py + corridor_length < self.board_shape[1]:
movable.append(down)
if board[px, py + 1] != 2:
directions.append(down)
if len(directions) != 0:
if len(directions) > 1:
d = directions[random.randint(0, len(directions) - 1)]
else:
d = directions[0]
changed = False
for _ in range(corridor_length):
if board[px, py] != 1 and board[px, py] != 2:
board[px, py] = 2
if (-d[0], -d[1]) not in movable or board[px - d[0], py - d[1]] != 2:
changed = True
px += d[0]
py += d[1]
if changed:
corridor_num += 1
else:
if len(movable) != 0:
if len(movable) > 1:
d = movable[random.randint(0, len(movable) - 1)]
else:
d = movable[0]
for _ in range(corridor_length):
px += d[0]
py += d[1]
crates = 0
while crates < self.max_crates:
px = random.randint(0, (self.board_shape[0] - 1))
py = random.randint(0, (self.board_shape[1] - 1))
if board[px, py] == 1:
board[px, py] = 3
crates += 1
board[board == 2] = 1
print((room_num, self.max_room_num))
print((corridor_num, self.max_corridors))
self.board = board
# setting up the board
for x_pos in range(0, self.board_shape[0]):
for y_pos in range(0, self.board_shape[1]):
for z_pos in range(0, 1):
self.put_object(x_pos, y_pos, z_pos, Cube().setColor(1, 1, 1))
# adding subjects
from labirinth_ai.Subject import Hunter, Herbivore
while len(self.subjects) < 2:
px = random.randint(self.max_room_dim, self.board_shape[0] - self.max_room_dim)
py = random.randint(self.max_room_dim, self.board_shape[1] - self.max_room_dim)
if self.board[px, py] == 1:
self.subjects.append(Hunter(px, py))
self.ins += self.subjects[-1].x_in
self.actions += self.subjects[-1].actions
self.targets += self.subjects[-1].target
while len(self.subjects) < 10:
px = random.randint(self.max_room_dim, self.board_shape[0] - self.max_room_dim)
py = random.randint(self.max_room_dim, self.board_shape[1] - self.max_room_dim)
if self.board[px, py] == 1:
self.subjects.append(Herbivore(px, py))
self.ins += self.subjects[-1].x_in
self.actions += self.subjects[-1].actions
self.targets += self.subjects[-1].target
for x in range(self.board_shape[0]):
for y in range(self.board_shape[1]):
self.subjectDict[(x, y)] = []
for sub in self.subjects:
self.subjectDict[(sub.x, sub.y)].append(sub)
def update(self):
# start = time.time()
if self.model is None:
for sub in self.subjects:
sub.calculateAction(self)
else:
states = list(map(lambda e: e.createState(self), self.subjects))
states = sum(list(map(lambda e: [e, e, e, e], states)), [])
vals = self.model.predict(states)
vals = np.reshape(np.transpose(np.reshape(vals, (len(self.subjects), 4, 2)), (0, 2, 1)),
(len(self.subjects), 1, 8))
list(map(lambda e: e[1].calculateAction(self, vals[e[0]], states[e[0]]), enumerate(self.subjects)))
for sub in self.subjects:
if sub.alive:
sub.update(self, doTrain=self.model is None)
sub.tick += 1
if self.model is not None:
if self.round >= self.nextTrain:
samples = list(map(lambda e: e.generateSamples(), self.subjects))
states = sum(list(map(lambda e: e[0], samples)), [])
targets = sum(list(map(lambda e: e[1], samples)), [])
self.model.fit(states, targets)
self.nextTrain = self.batchsize / 5
self.round = 0
for sub in self.subjects:
if len(sub.samples) > 20*self.batchsize:
sub.samples = sub.samples[:-20*self.batchsize]
else:
self.round += 1
new_subjects = []
kill_table = {}
live_table = {}
for sub in self.subjects:
if sub.name not in kill_table.keys():
kill_table[sub.name] = 0
live_table[sub.name] = 0
kill_table[sub.name] += sub.kills
live_table[sub.name] += sub.lives
if sub.alive:
new_subjects.append(sub)
else:
px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim)
py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim)
while self.board[px, py] == 0:
px = random.randint(self.max_room_dim, (self.board_shape[0] - 1) - self.max_room_dim)
py = random.randint(self.max_room_dim, (self.board_shape[1] - 1) - self.max_room_dim)
sub.respawnUpdate(px, py, self)
new_subjects.append(sub)
self.subjects = new_subjects
self.trailMix *= 0.99
self.grass = np.minimum(self.grass + 0.01 * (self.board != 0), 3)
self.hunter_grass = np.minimum(self.hunter_grass + 0.01 * (self.board != 0), 3)
self.trailMix *= (self.trailMix > 0.01)

1055
labirinth_ai/Subject.py Normal file

File diff suppressed because it is too large Load diff

0
labirinth_ai/__init__.py Normal file
View file

37
labirinth_ai/loss.py Normal file
View file

@ -0,0 +1,37 @@
import tensorflow as tf
def loss(nextState, actions):
# return tf.reduce_sum(tf.square(nextState[:, 2:, 0] * (0.5 * (nextState[:, 0] + 0.25 * nextState[:, 1] - actions))), axis=1)
return tf.reduce_mean(tf.square(nextState[:, 0] + 0.25 * nextState[:, 1] - tf.reduce_sum(
nextState[:, 2:6, 0] * (actions[:, :4] + actions[:, 4:]), axis=1))) + tf.reduce_mean(
tf.reduce_sum(tf.square(nextState[:, 6:, 0] - actions[:, :4]), axis=1), axis=0)
def loss2(nextState, actions):
# return tf.reduce_sum(tf.square(nextState[:, 2:, 0] * (0.5 * (nextState[:, 0] + 0.25 * nextState[:, 1] - actions))), axis=1)
# return 0.1 * tf.reduce_mean(tf.square(0.75 * nextState[:, 1] - tf.reduce_sum(nextState[:, 2:6, 0] * (actions[:, 4:] + actions[:, :4]),axis=1))) + 0.9 * tf.reduce_mean(tf.reduce_sum(tf.square(nextState[:, 6:, 0] - actions[:, :4]), axis=1), axis=0)
# return 0.0 * tf.reduce_mean(tf.square(0.75 * nextState[:, 1] - tf.reduce_sum(nextState[:, 2:6, 0] * (actions[:, :4]),axis=1))) + 1.0 * tf.reduce_mean(tf.reduce_sum(tf.square(nextState[:, 6:, 0] - actions[:, :4]), axis=1), axis=0)
return tf.reduce_mean(
tf.reduce_max(nextState[:, 2:6, 0] * tf.square((nextState[:, 6:, 0] - (actions[:, :4] + actions[:, 4:]))),
axis=1), axis=0)
# action = nextState[:, 3] * 1 + nextState[:, 4] * 2 + nextState[:, 5] * 3
# action = tf.cast(action, tf.int32)
# action = tf.reshape(action, (-1,))
#
# # test = actions[:, action[:]]
#
# test1 = tf.slice(actions[:, :4], action, (-1, 1))
# test2 = tf.slice(actions[:, 4:], action, (-1, 1))
#
# return 1.0 * tf.reduce_mean(tf.reduce_sum(tf.square((0.1 * nextState[:, 1] + nextState[:, 6:, 0]) - (test1 + test2)), axis=1)) + 0.0 * tf.reduce_mean(tf.reduce_sum(tf.square(nextState[:, 6:, 0] - actions[:, :4]), axis=1), axis=0)
# return 1.0 * tf.reduce_mean(tf.reduce_sum(tf.square((0.1 * nextState[:, 1] + nextState[:, 6:, 0]) - (actions[:, :4] + actions[:, 4:])), axis=1)) + 0.0 * tf.reduce_mean(tf.reduce_sum(tf.square(nextState[:, 6:, 0] - actions[:, :4]), axis=1), axis=0)
def loss3(target, pred):
return tf.reduce_mean(0.5 * tf.square(0.1 * target[:, 0, 0] + target[:, 1, 0] - (pred[:, 0] + pred[:, 1]))
+ 0.5 * tf.square(target[:, 1, 0] - pred[:, 0]), axis=0)