|
import math |
|
import ctypes |
|
import random |
|
import pyglet |
|
|
|
pyglet.options["shadow_window"] = False |
|
pyglet.options["debug_gl"] = False |
|
|
|
import pyglet.gl as gl |
|
|
|
import matrix |
|
import shader |
|
import player |
|
|
|
import block_type |
|
import texture_manager |
|
|
|
import chunk |
|
import world |
|
|
|
import hit |
|
|
|
class Window(pyglet.window.Window): |
|
def __init__(self, **args): |
|
super().__init__(**args) |
|
|
|
|
|
|
|
self.world = world.World() |
|
|
|
|
|
|
|
self.shader = shader.Shader("vert.glsl", "frag.glsl") |
|
self.shader_sampler_location = self.shader.find_uniform(b"texture_array_sampler") |
|
self.shader.use() |
|
|
|
|
|
|
|
pyglet.clock.schedule_interval(self.update, 1.0 / 60) |
|
self.mouse_captured = False |
|
|
|
|
|
|
|
self.player = player.Player(self.world, self.shader, self.width, self.height) |
|
|
|
|
|
|
|
self.holding = 44 |
|
|
|
def update(self, delta_time): |
|
|
|
|
|
if not self.mouse_captured: |
|
self.player.input = [0, 0, 0] |
|
|
|
self.player.update(delta_time) |
|
|
|
def on_draw(self): |
|
self.player.update_matrices() |
|
|
|
|
|
|
|
gl.glActiveTexture(gl.GL_TEXTURE0) |
|
gl.glBindTexture(gl.GL_TEXTURE_2D_ARRAY, self.world.texture_manager.texture_array) |
|
gl.glUniform1i(self.shader_sampler_location, 0) |
|
|
|
|
|
|
|
gl.glEnable(gl.GL_DEPTH_TEST) |
|
gl.glEnable(gl.GL_CULL_FACE) |
|
|
|
gl.glClearColor(0.0, 0.0, 0.0, 0.0) |
|
self.clear() |
|
self.world.draw() |
|
|
|
gl.glFinish() |
|
|
|
|
|
|
|
def on_resize(self, width, height): |
|
print(f"Resize {width} * {height}") |
|
gl.glViewport(0, 0, width, height) |
|
|
|
self.player.view_width = width |
|
self.player.view_height = height |
|
|
|
def on_mouse_press(self, x, y, button, modifiers): |
|
if not self.mouse_captured: |
|
self.mouse_captured = True |
|
self.set_exclusive_mouse(True) |
|
|
|
return |
|
|
|
|
|
|
|
def hit_callback(current_block, next_block): |
|
if button == pyglet.window.mouse.RIGHT: self.world.try_set_block(current_block, self.holding, self.player.collider) |
|
elif button == pyglet.window.mouse.LEFT: self.world.set_block(next_block, 0) |
|
elif button == pyglet.window.mouse.MIDDLE: self.holding = self.world.get_block_number(next_block) |
|
|
|
x, y, z = self.player.position |
|
y += self.player.eyelevel |
|
|
|
hit_ray = hit.Hit_ray(self.world, self.player.rotation, (x, y, z)) |
|
|
|
while hit_ray.distance < hit.HIT_RANGE: |
|
if hit_ray.step(hit_callback): |
|
break |
|
|
|
def on_mouse_motion(self, x, y, delta_x, delta_y): |
|
if self.mouse_captured: |
|
sensitivity = 0.004 |
|
|
|
self.player.rotation[0] += delta_x * sensitivity |
|
self.player.rotation[1] += delta_y * sensitivity |
|
|
|
self.player.rotation[1] = max(-math.tau / 4, min(math.tau / 4, self.player.rotation[1])) |
|
|
|
def on_mouse_drag(self, x, y, delta_x, delta_y, buttons, modifiers): |
|
self.on_mouse_motion(x, y, delta_x, delta_y) |
|
|
|
def on_key_press(self, key, modifiers): |
|
if not self.mouse_captured: |
|
return |
|
|
|
if key == pyglet.window.key.D: self.player.input[0] += 1 |
|
elif key == pyglet.window.key.A: self.player.input[0] -= 1 |
|
elif key == pyglet.window.key.W: self.player.input[2] += 1 |
|
elif key == pyglet.window.key.S: self.player.input[2] -= 1 |
|
|
|
elif key == pyglet.window.key.SPACE : self.player.input[1] += 1 |
|
elif key == pyglet.window.key.LSHIFT: self.player.input[1] -= 1 |
|
elif key == pyglet.window.key.LCTRL : self.player.target_speed = player.SPRINTING_SPEED |
|
|
|
elif key == pyglet.window.key.F: |
|
self.player.flying = not self.player.flying |
|
|
|
elif key == pyglet.window.key.G: |
|
self.holding = random.randint(1, len(self.world.block_types) - 1) |
|
|
|
elif key == pyglet.window.key.O: |
|
self.world.save.save() |
|
|
|
elif key == pyglet.window.key.R: |
|
|
|
|
|
max_y = 0 |
|
|
|
max_x, max_z = (0, 0) |
|
min_x, min_z = (0, 0) |
|
|
|
for pos in self.world.chunks: |
|
x, y, z = pos |
|
|
|
max_y = max(max_y, (y + 1) * chunk.CHUNK_HEIGHT) |
|
|
|
max_x = max(max_x, (x + 1) * chunk.CHUNK_WIDTH) |
|
min_x = min(min_x, x * chunk.CHUNK_WIDTH) |
|
|
|
max_z = max(max_z, (z + 1) * chunk.CHUNK_LENGTH) |
|
min_z = min(min_z, z * chunk.CHUNK_LENGTH) |
|
|
|
|
|
|
|
x = random.randint(min_x, max_x) |
|
z = random.randint(min_z, max_z) |
|
|
|
|
|
|
|
for y in range(chunk.CHUNK_HEIGHT - 1, -1, -1): |
|
if not self.world.get_block_number((x, y, z)): |
|
continue |
|
|
|
self.player.teleport((x, y + 1, z)) |
|
break |
|
|
|
elif key == pyglet.window.key.ESCAPE: |
|
self.mouse_captured = False |
|
self.set_exclusive_mouse(False) |
|
|
|
def on_key_release(self, key, modifiers): |
|
if not self.mouse_captured: |
|
return |
|
|
|
if key == pyglet.window.key.D: self.player.input[0] -= 1 |
|
elif key == pyglet.window.key.A: self.player.input[0] += 1 |
|
elif key == pyglet.window.key.W: self.player.input[2] -= 1 |
|
elif key == pyglet.window.key.S: self.player.input[2] += 1 |
|
|
|
elif key == pyglet.window.key.SPACE : self.player.input[1] -= 1 |
|
elif key == pyglet.window.key.LSHIFT: self.player.input[1] += 1 |
|
elif key == pyglet.window.key.LCTRL : self.player.target_speed = player.WALKING_SPEED |
|
|
|
class Game: |
|
def __init__(self): |
|
self.config = gl.Config(double_buffer = True, major_version = 3, minor_version = 3, depth_size = 16) |
|
self.window = Window(config = self.config, width = 800, height = 600, caption = "Minecraft clone", resizable = True, vsync = False) |
|
|
|
def run(self): |
|
pyglet.app.run() |
|
|
|
if __name__ == "__main__": |
|
game = Game() |
|
game.run() |
|
|