| 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() |
|
|