class Wall(Entity): defaults = { 'width': config.block_width, 'height': config.block_height, 'collidable': True } attributes = {'color': RGB(255, 255, 255)} def init(self, **kwargs): self.shape = Rectangle(self.x, self.y, height=self.height, width=self.width, color=self.color, batch=self.batch) def on_collision(self, obj): pass def take_damage(self, source, damage): pass def update(self): pass def draw(self): self.shape.draw()
class Button: def __init__(self, width, height, x, y, x_shift, y_shift, text, color, font_color): self.width = width self.height = height self.x = x self.y = y self.text = text self.org_color = color self.org_font_color = font_color self.color = color self.font_color = font_color self.x_shift = width / x_shift self.y_shift = height / y_shift def draw(self): self.rect = Rectangle(self.x, self.y, self.width, self.height, self.color) self.rect.draw() self.description = Label(self.text, self.x + self.x_shift, self.y + self.y_shift, self.font_color) self.description.draw() def hovered(self): self.inverse_colors() self.draw() def not_hovered(self): self.color = self.org_color self.font_color = self.org_font_color self.draw() def inverse_colors(self): self.color = (self.org_font_color[0], self.org_font_color[1], self.org_font_color[2]) self.font_color = (self.org_color[0], self.org_color[1], self.org_color[2], 255)
class EndScreen: def __init__(self, window_width, window_height, score, kill_count, total_enemies): self.win_width = window_width self.win_height = window_height self.score = score self.kill_count = kill_count self.button_width = 300 self.button_height = 50 self.x = (self.win_width / 2) - (self.button_width / 2) self.y = (self.win_height / 2) - (self.button_height / 2) self.pop_up = Rectangle(self.x - 100, self.y - 300, 500, 800, (50, 50, 50)) self.title = Label('G A M E O V E R!', self.x + 5, self.y + 90, (150, 1, 1, 255)) self.info_label_score = Label(f'SCORE: {self.score}', self.x + 50, self.y, (60, 135, 50, 255)) self.info_label_kills = Label( f'KILLS: {self.kill_count} / {total_enemies}', self.x + 15, self.y - 50, (60, 135, 50, 255)) self.menu_button = Button(self.button_width, self.button_height, self.x, self.y - 150, 3.4, 5, 'M E N U', (1, 1, 1), (60, 235, 50, 255)) def draw(self): self.pop_up.draw() self.info_label_score.draw() self.info_label_kills.draw() self.menu_button.draw() self.title.draw() def button_was_clicked(self, x, y, button): if (x >= int(button.x)) and (x <= int(button.x) + (self.button_width)): if (y >= int(button.y)) and (y <= int(button.y) + (self.button_height)): return True return False def button_was_touched(self, x, y, button): if (x >= int(button.x)) and (x <= int(button.x) + (self.button_width)): if (y >= int(button.y)) and (y <= int(button.y) + (self.button_height)): return True return False
def on_draw(): #window.clear() #main_batch.draw() rec = Rectangle(x, y, 1, 1) rec.draw()
class Player(GameObject): def __init__(self, x: int, y: int, frame: Frame, grid: Grid, renderbox: RenderBox, name: str = 'Player1', batch: Batch = None, debug: bool = False): # Player Sprite Select Related self.player_res_list = [ PlayerImages.p1, PlayerImages.p2, PlayerImages.p3 ] self.player_select = 0 self.player_res = self.player_res_list[self.player_select] # Initialize Base Class super().__init__(x=x, y=y, res=self.player_res.jump_right, frame=frame, grid=grid, renderbox=renderbox, name=name, batch=batch, usage='dynamic', is_anchor_x_centered=True) # Movement Related self.BASE_WALKING_SPEED = 200 self.BASE_JUMPING_SPEED = 300 self.vx = 0.0 self.vy = 0.0 self.facing = 'right' self.status = 'jumping' self.arrow_key_buffer = ArrowKeyBuffer() # Grid Related self.up_contact_obj_list = cast(List[GridObject], []) self.down_contact_obj_list = cast(List[GridObject], []) self.left_contact_obj_list = cast(List[GridObject], []) self.right_contact_obj_list = cast(List[GridObject], []) # Debug self.debug = debug self.ref_point = Circle(x=self.camera_x, y=self.camera_y, radius=5, color=(255, 0, 0)) self.ref_rect = Rectangle(x=self.camera_x, y=self.camera_y, width=self.width, height=self.height, color=(0, 0, 255)) self.ref_rect.anchor_x = self.ref_rect.width // 2 @property def x(self) -> int: return super().x @x.setter def x(self, x: int): super().x = x if self.debug: self.ref_point.x = self.camera_x self.ref_rect.x = self.camera_x @property def y(self) -> int: return super().y @y.setter def y(self, y: int): super().y = y if self.debug: self.ref_point.y = self.camera_y self.ref_rect.y = self.camera_y def change_player(self, idx: int): self.player_res = self.player_res_list[idx] self.player_select = idx self.update_sprite() def toggle_player(self): self.change_player( (self.player_select + 1) % len(self.player_res_list)) def toggle_debug(self): self.debug = not self.debug self.grid.show_contacts = not self.grid.show_contacts def change_sprite(self, image): self.sprite.image = image if self.debug: self.ref_rect.width = self.sprite.width self.ref_rect.height = self.sprite.height self.ref_rect.anchor_x = self.ref_rect.width // 2 def update_sprite(self): if self.status == 'idle': if self.facing == 'right': self.change_sprite(self.player_res.idle_right.img) elif self.facing == 'left': self.change_sprite(self.player_res.idle_left.img) else: raise Exception elif self.status == 'jumping': if self.facing == 'right': self.change_sprite(self.player_res.jump_right.img) elif self.facing == 'left': self.change_sprite(self.player_res.jump_left.img) else: raise Exception elif self.status == 'walking': if self.facing == 'right': self.change_sprite(self.player_res.walk_right_anim.animation) elif self.facing == 'left': self.change_sprite(self.player_res.walk_left_anim.animation) else: raise Exception else: raise Exception @property def is_idle(self) -> bool: return self.status == 'idle' @property def is_walking(self) -> bool: return self.status == 'walking' @property def is_jumping(self) -> bool: return self.status == 'jumping' def face(self, direction: str): if direction == 'right': self.facing = 'right' self.update_sprite() elif direction == 'left': self.facing = 'left' self.update_sprite() else: raise Exception def start_walking(self, direction: str): if direction == 'right': self.vx = self.BASE_WALKING_SPEED self.facing = 'right' self.status = 'walking' self.update_sprite() elif direction == 'left': self.vx = -self.BASE_WALKING_SPEED self.facing = 'left' self.status = 'walking' self.update_sprite() else: raise Exception def stop_walking(self): self.status = 'idle' self.vx = 0 self.update_sprite() def start_jumping(self): self.status = 'jumping' self.vy = self.BASE_JUMPING_SPEED self.update_sprite() def start_falling(self): self.status = 'jumping' self.update_sprite() def stop_jumping(self): self.status = 'idle' self.vy = 0 self.update_sprite() def draw(self): if self.debug: self.ref_point.draw() self.ref_rect.draw() super().draw() def move(self, dx: int, dy: int): player_grid_obj = self.grid.contained_obj_list.get_obj_from_name( self.name) other_renderable_objects = self.renderbox.get_all_renderable_objects( exclude_names=[self.name]) other_renderable_names = [ other_renderable_object.name for other_renderable_object in other_renderable_objects ] other_grid_objects = self.grid.contained_obj_list.get_objects( include_names=other_renderable_names) all_grid_objects = self.grid.contained_obj_list.get_objects() self.up_contact_obj_list = [] self.down_contact_obj_list = [] self.left_contact_obj_list = [] self.right_contact_obj_list = [] self.grid.reset_contacts() # Move X proposed_player_occupied_spaces = player_grid_obj.get_occupied_spaces( dx=dx) collision = False for proposed_player_occupied_space in proposed_player_occupied_spaces: for other_grid_object in other_grid_objects: if proposed_player_occupied_space in other_grid_object.occupied_spaces: other_grid_object.is_in_contact = True if dx > 0: self.right_contact_obj_list.append(other_grid_object) elif dx < 0: self.left_contact_obj_list.append(other_grid_object) else: raise Error( f'Player got stuck in object in x direction.') collision = True if not collision: self.set_x(x=self.x + dx, fix_camera=True) self.grid.move(dx=-dx) else: if len(self.left_contact_obj_list) > 0: dx_adjustment = self.left_contact_obj_list[ 0].x_right + 1 - self.x_left self.set_x(x=self.x + dx_adjustment, fix_camera=True) self.grid.move(dx=-dx_adjustment) elif len(self.right_contact_obj_list) > 0: dx_adjustment = self.right_contact_obj_list[ 0].x_left - self.x_right self.set_x(x=self.x + dx_adjustment, fix_camera=True) self.grid.move(dx=-dx_adjustment) else: raise Exception # Move Y proposed_player_occupied_spaces = player_grid_obj.get_occupied_spaces( dy=dy) collision = False for proposed_player_occupied_space in proposed_player_occupied_spaces: for other_grid_object in other_grid_objects: if proposed_player_occupied_space in other_grid_object.occupied_spaces: other_grid_object.is_in_contact = True if dy > 0: self.up_contact_obj_list.append(other_grid_object) elif dy < 0: self.down_contact_obj_list.append(other_grid_object) else: raise Error( f'Player got stuck in object in y direction.') collision = True if not collision: self.set_y(y=self.y + dy, fix_camera=True) self.grid.move(dy=-dy) self.start_falling() else: self.vy = 0 if len(self.down_contact_obj_list) > 0: dy_adjustment = self.down_contact_obj_list[ 0].y_top - self.y_bottom self.set_y(y=self.y + dy_adjustment, fix_camera=True) self.grid.move(dy=-dy_adjustment) if self.is_jumping: self.stop_jumping() if self.arrow_key_buffer.is_pressed: self.start_walking( direction=self.arrow_key_buffer.buffer[-1]) else: self.vx = 0 elif len(self.up_contact_obj_list) > 0: dy_adjustment = self.up_contact_obj_list[ 0].y_bottom - self.y_top self.set_y(y=self.y + dy_adjustment, fix_camera=True) self.grid.move(dy=-dy_adjustment) else: raise Exception
class Game(pyglet.window.Window): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # 窗口是否捕获鼠标 self.exclusive = False # 玩家 self.player = Player() # 拓展功能 self.debug = {} self.debug['debug'] = False self.debug['enable'] = False self.debug['running'] = False # rotation = (水平角 x, 俯仰角 y) self.player['rotation'] = (0, 0) # 玩家所处的区域 self.sector = None # 这个十字在屏幕中央 self.reticle = None # 显示在 debug 区域的 info self._info_ext = [] self._info_ext.append('pyglet' + pyglet.version) # 玩家可以放置的方块, 使用数字键切换 self.inventory = ['grass', 'dirt', 'log', 'brick', 'leaf', 'plank', 'craft_table', 'glass'] # 数字键列表 self.num_keys = [ key._1, key._2, key._3, key._4, key._5, key._6, key._7, key._8, key._9, key._0] # 这个标签在画布的上方显示 self.label = {} self.label['top'] = pyglet.text.Label('', x=2, y=self.height - 5, width=self.width // 2, multiline=True, anchor_x='left', anchor_y='top', font_size=12, font_name='minecraftia') self.is_init = True # 设置图标 self.set_icon(image.load(os.path.join(path['texture'], 'icon.png'))) # 这个标签在画布正中偏上显示 self.label['center'] = pyglet.text.Label('', x=self.width // 2, y=self.height // 2 + 50, anchor_x='center', anchor_y='center', font_name='minecraftia') # 死亡信息 self.die_info = pyglet.text.Label('', color=(255, 255, 255, 255), x=self.width // 2, y=self.height // 2, anchor_x='center', anchor_y='center', font_size=24, font_name='minecraftia') # 这个标签在画布正中偏下显示 self.label['actionbar'] = pyglet.text.Label('', x=self.width // 2, y=self.height // 2 - 100, anchor_x='center', anchor_y='center', font_name='minecraftia') # 加载窗口 self.loading = Loading() # 覆盖屏幕的矩形 self.full_screen = Rectangle(0, 0, self.width, self.height) # 聊天区 self.dialogue = Dialogue() # 将 self.upgrade() 方法每 1.0 / TICKS_PER_SEC 调用一次, 它是游戏的主事件循环 pyglet.clock.schedule_interval(self.update, 1.0 / TICKS_PER_SEC) # 检测玩家是否应该死亡 pyglet.clock.schedule_interval(self.check_die, 1.0 / TICKS_PER_SEC) # 每10秒更新一次方块数据 pyglet.clock.schedule_interval(self.update_status, 0.1) # 每30秒保存一次进度 pyglet.clock.schedule_interval(self.save, 30.0) # 天空颜色变换 pyglet.clock.schedule_interval(change_sky_color, 7.5) log_info('welcome %s' % player['name']) for lib in libs: if hasattr(lib, 'init'): lib.init() def can_place(self, block, position): """ 检测坐标是否能够放置方块 :param: block 方块坐标 :param: position 玩家坐标 """ if block != normalize(position): position = position[0], position[1] - 1, position[2] if block != normalize(position): return True else: return False else: return False def add_info_ext(self, s): self._info_ext.append(s) def check_die(self, dt): """ 这个函数被 pyglet 计时器反复调用 :param: dt 距上次调用的时间 """ return if not self.player['die']: if self.player['position'][1] < -64: self.player['die_reason'] = get_lang('game.text.die.fall_into_void') % player['name'] self.player['die'] = True self.dialogue.add_dialogue(self.player['die_reason']) elif self.player['position'][1] > 512: self.player['die_reason'] = get_lang('game.text.die.no_oxygen') % player['name'] self.player['die'] = True if self.player['die']: log_info('%s die: %s' % (player['name'], self.player['die_reason'])) self.dialogue.add_dialogue(self.player['die_reason']) self.set_exclusive_mouse(False) def init_player(self): # 初始化玩家 self.hud = {} # E 键打开的背包 self.hud['bag'] = Bag() # 生命值 self.hud['heart'] = Heart(batch=self.world.batch2d) # 饥饿值 self.hud['hunger'] = Hunger(batch=self.world.batch2d) # 工具栏 self.hud['hotbar'] = HotBar() self.hud['hotbar'].set_index(self.block) self.hud['hotbar'].set_all(self.inventory) # 经验条 self.hud['xpbar'] = XPBar() # 菜单 self.menu = {} self.menu['pause'] = PauseMenu(self) self.menu['pause'].frame.enable(True) self.menu['chat'] = Chat(self) def save(self, dt): """ 这个函数被 pyglet 计时器反复调用 :param: dt 距上次调用的时间 """ archiver.save_block(self.name, self.world.change) archiver.save_player(self.name, self.player['position'], self.player['respawn_position'], normalize(self.player['rotation']), self.player['block']) archiver.save_info(self.name, 0, get_time()) def set_exclusive_mouse(self, exclusive): # 如果 exclusive 为 True, 窗口会捕获鼠标. 否则忽略之 super(Game, self).set_exclusive_mouse(exclusive) self.exclusive = exclusive def set_name(self, name): # 设置游戏存档名 self.name = name self.world = World(name) # self.world_gen_thread = Thread(target=self.world.init_world, name='WorldGen') # self.world_gen_thread.start() # 读取玩家位置和背包 data = archiver.load_player(self.name) self.player['position'] = data['position'] self.player['respawn_position'] = data['respawn'] if len(self.player['position']) != 3: if archiver.load_info(self.name)['type'] == 'flat': self.player['position'] = self.player['respawn_position'] = (0, 8, 0) else: self.player['position'] = self.player['respawn_position'] = (0, self.world.simplex.noise2d(x=0, y=0) * 5 + 13, 0) self.sector = sectorize(self.player['position']) self.player['rotation'] = tuple(data['rotation']) self.block = data['now_block'] # 读取世界数据 self.world_info = archiver.load_info(self.name) set_time(self.world_info['time']) def set_cursor(self, cursor=None): # 设置光标形状 if cursor is None: self.set_mouse_cursor(None) else: self.set_mouse_cursor(self.get_system_mouse_cursor(cursor)) def run_command(self, s): # 运行命令 command = s.split(' ')[0] if command not in commands: self.dialogue.add_dialogue('Command not found') else: try: cmd = commands[command](self, self.player['position'], s) except ValueError: pass else: cmd.run() def update(self, dt): """ 这个方法被 pyglet 计时器反复调用 :param: dt 距上次调用的时间 """ self.world.process_queue() self.dialogue.update() sector = sectorize(self.player['position']) if sector != self.sector: self.world.change_chunk(self.sector, sector) if self.sector is None: self.world.process_entire_queue() self.sector = sector m = 8 dt = min(dt, 0.2) for _ in range(m): self._update(dt / m) def update_status(self, dt): # 这个函数定时改变世界状态 for sector in self.world.sectors.values(): blocks = random.choices(sector, k=3) for block in blocks: self.world.get(block).on_ticking(self, block) def _update(self, dt): """ update() 方法的私有实现, 刷新 :param: dt 距上次调要用的时间 """ # 移动速度 if self.player['flying']: speed = FLYING_SPEED elif self.player['running'] or self.debug['running']: speed = RUNNING_SPEED elif self.player['stealing']: speed = STEALING_SPEED else: speed = WALKING_SPEED # 一个游戏刻玩家经过的距离 d = dt * speed dx, dy, dz = self.player.get_motion_vector() # 玩家新的位置 dx, dy, dz = dx * d, dy * d, dz * d # 重力 if not self.player['die']: if not self.player['flying']: self.player['dy'] -= dt * GRAVITY self.player['dy'] = max(self.player['dy'], -TERMINAL_VELOCITY) dy += self.player['dy'] * dt if not self.player['in_hud']: # 碰撞检测 x, y, z = self.player['position'] if self.player['gamemode'] != 1: x, y, z = self.player.collide((x + dx, y + dy, z + dz)) else: x, y, z = x + dx, y + dy, z + dz self.player['position'] = (x, y, z) def on_close(self): # 当玩家关闭窗口时调用 archiver.save_window(self.width, self.height) pyglet.app.exit() def on_mouse_press(self, x, y, button, modifiers): """ 当玩家按下鼠标按键时调用 :param: x, y 鼠标点击时的坐标, 如果被捕获的话总是在屏幕中央 :param: button 哪个按键被按下: 1 = 左键, 4 = 右键 :param: modifiers 表示单击鼠标按钮时按下的任何修改键的数字 """ for menu in self.menu.values(): if menu.frame.on_mouse_press(x, y, button, modifiers): return self.player.on_mouse_press(x, y, button, modifiers) def on_mouse_release(self, x, y, button, modifiers): for menu in self.menu.values(): menu.frame.on_mouse_release(x, y, button, modifiers) def on_mouse_motion(self, x, y, dx, dy): """ 当玩家移动鼠标时调用 :param: x, y 鼠标点击时的坐标, 如果被捕获的话它们总是在屏幕中央 :param: dx, dy 鼠标移动的距离 """ for menu in self.menu.values(): menu.frame.on_mouse_motion(x, y, dx, dy) self.player.on_mouse_motion(x, y, dx, dy) def on_mouse_scroll(self, x, y, scroll_x, scroll_y): """ 当鼠标滚轮滚动时调用 :param: scroll_x, scroll_y 鼠标滚轮滚动(scroll_y 为1时向上, 为-1时向下) """ self.player.on_mouse_scroll(x, y, scroll_x, scroll_y) def on_key_press(self, symbol, modifiers): """ 当玩家按下一个按键时调用 :param: symbol 按下的键 :param: modifiers 同时按下的修饰键 """ self.player.on_key_press(symbol, modifiers) def on_key_release(self, symbol, modifiers): """ 当玩家释放一个按键时调用 :param: symbol 释放的键 """ self.player.on_key_release(symbol, modifiers) def on_resize(self, width, height): # 当窗口被调整到一个新的宽度和高度时调用 # 标签 self.label['top'].x = 2 self.label['top'].y = self.height - 5 self.label['top'].width = self.width // 2 self.label['center'].x = self.width // 2 self.label['center'].y = self.height // 2 + 50 self.die_info.x = self.width // 2 self.die_info.y =self.height // 2 self.label['actionbar'].x = self.width // 2 self.label['actionbar'].y = self.height // 2 - 100 # 加载窗口 self.loading.resize(self.width, self.height) # 窗口中央的十字线 if self.reticle: self.reticle.delete() x, y = self.width // 2, self.height // 2 n = 12 self.reticle = pyglet.graphics.vertex_list(4, ('v2i', (x - n, y, x + n, y, x, y - n, x, y + n)) ) # 覆盖屏幕的矩形 self.full_screen.position = (0, 0) self.full_screen.width = self.width self.full_screen.height = self.height # 聊天区 self.dialogue.resize(self.width, self.height) # HUD # 在第一次调用该函数时, 所有存储 HUD 的变量都没有定义 if not self.is_init: self.hud['bag'].resize(self.width, self.height) self.hud['heart'].resize(self.width, self.height) self.hud['hunger'].resize(self.width, self.height) self.hud['hotbar'].resize(self.width, self.height) self.hud['xpbar'].resize(self.width, self.height) for menu in self.menu.values(): menu.frame.on_resize(width, height) def set_2d(self): # 使 OpenGL 绘制二维图形 width, height = self.get_size() glDisable(GL_DEPTH_TEST) viewport = self.get_viewport_size() glViewport(0, 0, max(1, viewport[0]), max(1, viewport[1])) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0, max(1, width), 0, max(1, height), -1, 1) glMatrixMode(GL_MODELVIEW) glLoadIdentity() def set_3d(self): # 使 OpenGL 绘制三维图形 width, height = self.get_size() glEnable(GL_DEPTH_TEST) viewport = self.get_viewport_size() glViewport(0, 0, max(1, viewport[0]), max(1, viewport[1])) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(self.player['fov'], width / float(height), 0.1, 60.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() x, y = self.player['rotation'] glRotatef(x, 0, 1, 0) glRotatef(-y, math.cos(math.radians(x)), 0, math.sin(math.radians(x))) x, y, z = self.player['position'] glTranslatef(-x, -y + (0.1 if self.player['stealing'] else 0), -z) def on_draw(self): # 当 pyglet 在画布上绘图时调用 self.clear() if not self.is_init: self.set_3d() glColor3d(1, 1, 1) self.world.draw() self.draw_focused_block() self.set_2d() if not self.player['die'] and not self.player['hide_hud']: self.world.batch2d.draw() self.hud['hotbar'].draw() self.hud['xpbar'].draw() self.draw_reticle() if not self.player['in_hud'] and not self.exclusive: self.full_screen.color = (0, 0, 0) self.full_screen.opacity = 100 self.full_screen.draw() if not self.player['in_chat']: self.menu['pause'].frame.draw() else: self.menu['chat'].frame.draw() if self.player['in_hud'] or not self.exclusive: self.full_screen.color = (0, 0, 0) self.full_screen.opacity = 100 self.full_screen.draw() if self.player['show_bag']: self.hud['bag'].draw() elif self.player['die']: self.full_screen.color = (200, 0, 0) self.full_screen.opacity = 100 self.full_screen.draw() self.set_2d() if not self.player['hide_hud']: self.draw_label() if self.is_init: self.world.init_world() self.init_player() self.is_init = False def on_text(self, text): for menu in self.menu.values(): menu.frame.on_text(text) def on_text_motion(self, motion): for menu in self.menu.values(): menu.frame.on_text_motion(motion) def on_text_motion_select(self, motion): for menu in self.menu.values(): menu.frame.on_text_motion_select(motion) def draw_focused_block(self): # 在十字线选中的方块绘制黑边 vector = self.player.get_sight_vector() block = self.world.hit_test(self.player['position'], vector)[0] if block and self.player['gamemode'] != 1: x, y, z = block vertex_data = cube_vertices(x, y, z, 0.5001) glColor4f(1.0, 1.0, 1.0, 0.2) glDisable(GL_CULL_FACE) pyglet.graphics.draw(24, GL_QUADS, ('v3f/static', vertex_data)) glEnable(GL_CULL_FACE) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) def draw_label(self): if not self.is_init: if self.exclusive: self.dialogue.draw() if self.player['die']: # 玩家死亡 self.die_info.text = get_lang('game.text.die') self.label['actionbar'].text = self.player['die_reason'] self.die_info.draw() self.label['actionbar'].draw() elif self.debug['debug'] and self.exclusive: x, y, z = self.player['position'] rx, ry = self.player['rotation'] mem = round(psutil.Process(os.getpid()).memory_full_info()[0] / 1048576, 2) fps = pyglet.clock.get_fps() info_ext = [] self.label['top'].text = '\n'.join(get_lang('game.text.debug')) % (VERSION['str'], ', '.join(self._info_ext), x, y, z, rx, ry, mem, fps) self.label['top'].draw() else: # 初始化屏幕 self.loading.draw() def draw_reticle(self): # 在屏幕中央画十字线 if not self.is_init and not self.player['in_hud'] and self.exclusive: glColor3f(1.0, 1.0, 1.0) glLineWidth(3.0) self.reticle.draw(GL_LINES) glLineWidth(1.0)
class DialogueEntry(Widget): def __init__(self): win_width, win_height = get_size() self.batch = Batch() self._doc = pyglet.text.document.UnformattedDocument('') self._doc.set_style(0, len(self._doc.text), dict(color=(255, 255, 255, 255))) font = self._doc.get_font() self.text_height = font.ascent - font.descent self.pad = 2 self._outline = Rectangle(5 - self.pad, 20 - self.pad, get_size()[0] + self.pad - 5, self.text_height + self.pad, color=(0, 0, 0)) self._outline.opacity = 150 self._layout = IncrementalTextLayout(self._doc, get_size()[0] + self.pad - 5, self.text_height, multiline=False, batch=self.batch) self._caret = Caret(self._layout, color=(255, 255, 255)) self._caret.visible = False self._layout.x = 5 self._layout.y = 20 self._focus = False self._press = False self.last_char = '' super().__init__(5, 20, get_size()[0] + self.pad - 5, self.text_height) def draw(self): self._outline.draw() self.batch.draw() def text(self, text): self._doc.text = text def _set_focus(self, value): self._focus = value self._caret.visible = value def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if self._focus: self._caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers) def on_mouse_motion(self, x, y, dx, dy): if self.check_hit(x, y): get_game().set_cursor('text') else: get_game().set_cursor() def on_mouse_press(self, x, y, buttons, modifiers): if self.check_hit(x, y): self._press = True self._set_focus(True) self._caret.on_mouse_press(x, y, buttons, modifiers) else: self._set_focus(False) def on_mouse_release(self, x, y, buttons, modifiers): if self._press: self._press = False def on_resize(self, width, height): self.width = width - self.pad - 5 self._outline.width = width - self.pad - 5 self._layout.width = width - self.pad - 5 def on_text(self, text): if text == self.last_char: self.last_char = '' return else: self.last_char = text if self._focus: if text in ('\r', '\n'): self.dispatch_event('on_commit', self._layout.document.text) self._set_focus(False) return self._caret.on_text(text) def on_text_motion(self, motion): if self._focus: self._caret.on_text_motion(motion) def on_text_motion_select(self, motion): if self._focus: self._caret.on_text_motion_select(motion) def on_commit(self, text): pass
class DialogueEntry(Widget): def __init__(self): win_width, win_height = get_size() self.batch = Batch() self._doc = pyglet.text.document.UnformattedDocument('') self._doc.set_style(0, len(self._doc.text), dict(color=(255, 255, 255, 255))) font = self._doc.get_font() self.text_height = font.ascent - font.descent self.pad = 2 self._outline = Rectangle(5, 5 + self.pad, get_size()[0] - self.pad - 10, self.text_height + self.pad, color=(0, 0, 0)) self._outline.opacity = 150 self._layout = IncrementalTextLayout(self._doc, get_size()[0] - 14, self.text_height, multiline=False, batch=self.batch) self._caret = Caret(self._layout, color=(255, 255, 255)) self._caret.visible = False self._layout.x = 5 self._layout.y = 5 + self.pad self._focus = False self._press = False self.last_press = [0, 0] super().__init__(5, 5 + self.pad, get_size()[0] - self.pad - 10, self.text_height + self.pad) def draw(self): self._outline.draw() self.batch.draw() def text(self, text): self._doc.text = text def _set_focus(self, value): self._focus = value self._caret.visible = value def on_key_press(self, symbol, modifiers): if symbol == key.PAGEUP: if self.last_press[0] == 1: self.last_press[0] = 0 return else: self.last_press[0] = 1 self.text('') self.text( get_game().dialogue.history[get_game().dialogue.pointer]) if get_game().dialogue.pointer != 0: get_game().dialogue.pointer -= 1 elif symbol == key.PAGEDOWN: if self.last_press[1] == 1: self.last_press[1] = 0 return else: self.last_press[1] = 1 if get_game().dialogue.pointer != len( get_game().dialogue.history) - 1: get_game().dialogue.pointer += 1 self.text('') self.text(get_game().dialogue.history[ get_game().dialogue.pointer]) else: self.text('') def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if self._focus: self._caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers) def on_mouse_motion(self, x, y, dx, dy): if self.check_hit(x, y): get_game().set_cursor('text') else: get_game().set_cursor() def on_mouse_press(self, x, y, buttons, modifiers): if self.check_hit(x, y): self._press = True self._set_focus(True) self._caret.on_mouse_press(x, y, buttons, modifiers) else: self._set_focus(False) def on_mouse_release(self, x, y, buttons, modifiers): if self._press: self._press = False def on_resize(self, width, height): self.width = width - self.pad - 10 self._outline.width = width - self.pad - 10 self._layout.width = width - self.pad - 10 def on_text(self, text): if self._focus: if text in ('\r', '\n'): self.dispatch_event('on_commit', self._layout.document.text) self._set_focus(False) return self._caret.on_text(text) def on_text_motion(self, motion): if self._focus: self._caret.on_text_motion(motion) def on_text_motion_select(self, motion): if self._focus: self._caret.on_text_motion_select(motion) def on_commit(self, text): pass
class TextEntry(Widget): def __init__(self, text, color, x, y, width): win_width, win_height = get_size() self.batch = Batch() self._doc = pyglet.text.document.UnformattedDocument(text) self._doc.set_style( 0, len(self._doc.text), dict(color=(255, 255, 255, 255), font_name='minecraftia')) font = self._doc.get_font() height = font.ascent - font.descent pad = 2 self._outline = Rectangle(x - pad, y - pad, width + pad, height + pad, color=color[:3]) self._outline.opacity = color[-1] self._layout = IncrementalTextLayout(self._doc, width, height, multiline=False, batch=self.batch) self._caret = Caret(self._layout, color=(255, 255, 255)) self._caret.visible = False self._layout.x = x self._layout.y = y self._focus = False self._press = False super().__init__(x, y, width, height) self.last_char = '' def draw(self): self._outline.draw() self.batch.draw() def text(self, text): self._doc.text = text def _set_focus(self, value): self._focus = value self._caret.visible = value def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if self._focus: self._caret.on_mouse_drag(x, y, dx, dy, buttons, modifiers) def on_mouse_press(self, x, y, buttons, modifiers): if self.check_hit(x, y): self._press = True self._set_focus(True) self._caret.on_mouse_press(x, y, buttons, modifiers) else: self._set_focus(False) def on_mouse_release(self, x, y, buttons, modifiers): if self._press: self._press = False def on_text(self, text): if text == self.last_char: self.last_char = '' return else: self.last_char = text if self._focus: if text in ('\r', '\n'): self.dispatch_event('on_commit', self._layout.document.text) self._set_focus(False) return self._caret.on_text(text) def on_text_motion(self, motion): if self._focus: self._caret.on_text_motion(motion) def on_text_motion_select(self, motion): if self._focus: self._caret.on_text_motion_select(motion) def on_commit(self, text): pass
class ItemSlot(Widget): def __init__(self, x, y, index=None): y = get_size()[1] - y super().__init__(x, y, 32, 32) self._index = index self._on = False self._item = self._item_name = None self._state = {'set': True, 'get': True} self._rect = Rectangle(self.x, get_size()[1] - self.y - 32, 32, 32, color=(255, ) * 3) self._rect.opacity = 100 def _update(self): self._rect.position = self.x, get_size()[1] - self.y - 32 if self._item is not None: self._item.position = self.x, get_size()[1] - self.y - 32 def on_mouse_motion(self, x, y, dx, dy): if self.check_hit(x, get_size()[1] - y): self._on = True else: self._on = False def on_mouse_press(self, x, y, buttons, modifiers): if not self._on: return if buttons == mouse.LEFT: i1, i2 = self._item_name, get_game().get_active_item() if all(self._state.values()): self.set_item(i2) get_game().set_active_item(i1) elif self._state['set']: if get_game().get_active_item() is not None: self.set_item(i2) get_game().set_active_item(i1) elif self._state['get']: if get_game().get_active_item() is None: self.set_item() get_game().set_active_item(i1) elif buttons == mouse.MIDDLE: get_game().set_active_item(self._item_name) if hasattr(self, 'on_change'): self.on_change(buttons, modifiers, self._index) def set_item(self, item=None): if item is None: self._item_name = self._item = None else: self._item_name = item self._item = Sprite(get_block_icon(blocks[item], 32), x=self.x, y=get_size()[1] - self.y - 32) def set_state(self, set_=True, get=True): self._state['set'] = set_ self._state['get'] = get def get_item(self): return self._item_name def draw(self): if self._item is not None: self._item.draw() if self._on: self._rect.draw()
class Game(): def __init__(self): self.batch = Batch() self.background = Rectangle(0, 0, 0, 0) self.window = Window() self.window.push_handlers(self) self.on_resize(self.window.width, self.window.height) clock.schedule_interval(self.update, 1 / 60) clock.schedule_interval(self.log, 1) self.sounds = { 'fail': media.load('resources/failure.mp3', streaming=False), 'jump': media.load('resources/jump.wav', streaming=False), 'score': media.load('resources/score.wav', streaming=False), } self.reset() def log(self, delta): logging.info('Current speed: {}'.format(self.speed)) logging.info('Current score: {}'.format(self.points)) def reset(self): self.pipes = [] self.points = 0 self.speed = 2 self.player = Player(batch=self.batch) self.create_pipe() self.create_pipe(x=(Grid.columns / 2) + (Pipe.WIDTH / 2)) def fail(self): self.sounds['fail'].play() self.reset() def create_pipe(self, *args, **kwargs): kwargs['batch'] = kwargs.get('batch', self.batch) self.pipes.append(Pipe(*args, **kwargs)) def update(self, delta): self.player.update(delta) self.speed += delta * 0.1 delta_x = delta * Grid.x() * self.speed if self.player.is_offscreen(): self.fail() return for pipe in self.pipes: pipe.scroll(delta_x) if pipe.is_offscreen(): self.pipes.remove(pipe) self.create_pipe() if pipe.collides(self.player.center): self.fail() if self.player.cleared(pipe): self.score() def score(self): self.sounds['score'].play() self.points += 1 def jump(self): logging.info('jumping') self.sounds['jump'].play() self.player.jump() def on_key_press(self, symbol, modifiers): self.jump() def on_mouse_press(self, x, y, button, modifiers): self.jump() def on_draw(self): self.window.clear() self.background.draw() self.batch.draw() def on_resize(self, width, height): Grid.update_factor(width, height) self.background.width, self.background.height = width, height if getattr(self, 'player', None): self.player.resize()
def on_draw(): global pos #window.clear() #main_batch.draw() rec = Rectangle(pos[0], pos[1], 1, 1) rec.draw()