from pycraft.gamestate import GameState from pycraft.world.sector import Sector from pycraft.world.world import World from pycraft.objects.player import Player from pycraft.objects.block import get_block from pyglet.window import key, mouse import pyglet.graphics from pycraft.util import sectorize, cube_vertices, normalize import pyglet.window import pyglet.gl as GL import math # Convenience list of num keys. NUMERIC_KEYS = [ key._1, key._2, key._3, key._4, key._5, key._6, key._7, key._8, key._9, key._0 ] class GameStateRunning(GameState): def __init__(self, config, height, width): super(GameStateRunning, self).__init__() self.world = World() self.player = Player(config["world"]) # The crosshairs at the center of the screen. self.reticle = None # The label that is displayed in the top left of the canvas. self.game_info_label = pyglet.text.Label( '', font_name='Arial', font_size=18, x=10, y=height - 10, anchor_x='left', anchor_y='top', color=(0, 0, 0, 255)) self.current_item_label = pyglet.text.Label( '', font_name='Arial', font_size=18, x=width - 10, y=10, anchor_x='right', anchor_y='bottom', color=(0, 0, 0, 255)) def on_mouse_press(self, x, y, button, modifiers): if (button == mouse.RIGHT) or \ ((button == mouse.LEFT) and (modifiers & key.MOD_CTRL)): block, previous = self.player.hit(self.world.area.blocks, left=False) # ON OSX, control + left click = right click. if block and self.player.current_item: self.world.add_block(previous, get_block(self.player.get_block())) elif button == mouse.LEFT: block = self.player.hit(self.world.area.blocks)[0] if block: texture = self.world.area.get_block(block) if texture.hit_and_destroy(): self.world.remove_block(block) def on_mouse_motion(self, x, y, dx, dy): m = 0.15 x, y = self.player.rotation x, y = x + dx * m, y + dy * m y = max(-90, min(90, y)) self.player.rotation = (x, y) def on_key_press(self, symbol, modifiers, controls): if symbol == getattr(key, controls['forward']): self.player.strafe_forward() elif symbol == getattr(key, controls['backward']): self.player.strafe_backward() elif symbol == getattr(key, controls['right']): self.player.strafe_right() elif symbol == getattr(key, controls['left']): self.player.strafe_left() elif symbol == getattr(key, controls['jump']): self.player.jump() elif symbol == getattr(key, controls['down']): self.player.strafe_down() elif symbol == getattr(key, controls['fly']): self.player.fly() elif symbol in NUMERIC_KEYS: self.player.switch_inventory(symbol - NUMERIC_KEYS[0]) def on_key_release(self, symbol, modifiers, controls): if symbol == getattr(key, controls['forward']): self.player.strafe_backward() elif symbol == getattr(key, controls['backward']): self.player.strafe_forward() elif symbol == getattr(key, controls['left']): self.player.strafe_right() elif symbol == getattr(key, controls['right']): self.player.strafe_left() elif symbol == getattr(key, controls['jump']): self.player.strafe_down() elif symbol == getattr(key, controls['down']): self.player.strafe_up() def on_resize(self, width, height): # label self.game_info_label.y = height - 10 self.current_item_label.x = width - 10 # reticle if self.reticle: self.reticle.delete() x, y = width // 2, height // 2 n = 10 self.reticle = pyglet.graphics.vertex_list( 4, ('v2i', (x - n, y, x + n, y, x, y - n, x, y + n)) ) def on_draw(self, size): self.set_3d(size) GL.glColor3d(1, 1, 1) # self.world.start_shader() self.world.batch.draw() self.world.stop_shader() self.draw_focused_block() self.set_2d(size) self.draw_labels() self.draw_reticle() def set_3d(self, size): """Configure OpenGL to draw in 3d.""" width, height = size GL.glEnable(GL.GL_DEPTH_TEST) GL.glViewport(0, 0, width, height) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.gluPerspective(65.0, width / float(height), 0.1, 60.0) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() x, y = self.player.rotation GL.glRotatef(x, 0, 1, 0) GL.glRotatef(-y, math.cos(math.radians(x)), 0, math.sin(math.radians(x))) x, y, z = self.player.position GL.glTranslatef(-x, -y, -z) def set_2d(self, size): """Configure OpenGL to draw in 2d.""" width, height = size GL.glDisable(GL.GL_DEPTH_TEST) GL.glViewport(0, 0, width, height) GL.glMatrixMode(GL.GL_PROJECTION) GL.glLoadIdentity() GL.glOrtho(0, width, 0, height, -1, 1) GL.glMatrixMode(GL.GL_MODELVIEW) GL.glLoadIdentity() def update(self, dt, ticks_per_second): self.world.process_queue(ticks_per_second) sector = sectorize(self.player.position) if sector != self.world.sector: self.world.change_sectors(self.world.sector, sector) if self.world.sector is None: self.world.process_entire_queue() self.world.sector = sector m = 8 dt = min(dt, 0.2) for _ in range(m): self.player.update(dt / m, self.world.area.get_blocks()) def draw_focused_block(self): """Draw black edges around the block that is currently under the crosshairs. """ block = self.player.hit(self.world.area.blocks)[0] if block: x, y, z = block vertex_data = cube_vertices(x, y, z, 0.51) GL.glColor3d(0, 0, 0) GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE) pyglet.graphics.draw(24, GL.GL_QUADS, ('v3f/static', vertex_data)) GL.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL) def draw_labels(self): """Draw the label in the top left of the screen.""" x, y, z = self.player.position self.game_info_label.text = '%02d (%.2f, %.2f, %.2f) %d / %d' % ( pyglet.clock.get_fps(), x, y, z, len(self.world._shown), len(self.world.area.get_blocks())) self.game_info_label.draw() self.current_item_label.text = self.player.current_item if self.player.current_item else "No items in this inventory" self.current_item_label.draw() def draw_reticle(self): """Draw the crosshairs in the center of the screen.""" GL.glColor3d(0, 0, 0) self.reticle.draw(GL.GL_LINES)