Пример #1
0
class Application:
    def __init__(self,
                 title="",
                 sWidth=1280,
                 sHeight=720,
                 bgC=color_rgb(25, 25, 25)):
        self.window = GraphWin(title, sWidth, sHeight)
        self.window.setBackground(bgC)

        self.gameState = GameState.MENU

        self.menu = MainMenu(self.window)
        self.game = Game(self.window, False)

        self.dt = 0.0  #DeltaTime
        self.lastFrameTime = 0.0

        self.setState(self.gameState)

    def quit(self):
        self.window.flush()
        self.window.close()

    def undraw(self):
        if self.gameState == GameState.MENU:
            self.menu.undraw()
        elif self.gameState == GameState.GAME:
            self.game.undraw()
        else:
            self.menu.undraw()
            self.game.undraw()

    def run(self):
        while not self.window.isClosed():
            #Calculate deltatime
            currentTime = time.time()
            self.dt = currentTime - self.lastFrameTime
            self.lastFrameTime = currentTime

            self.update(self.dt)

            if not self.window.isClosed():
                self.window.flush()

            #If the close key is pressed, close window, for debugging
            if input.kClose():
                quit()

    def update(self, dt):
        state = GameState.NONE
        if self.gameState == GameState.MENU:
            state = self.menu.update(self.window)
        elif self.gameState == GameState.GAME:
            state = self.game.update(dt, self.window)

        if not state == GameState.NONE:
            if state == GameState.QUIT:
                quit()
            else:
                self.setState(state)

    def setState(self, state=GameState.NONE):
        if state == GameState.NONE:
            self.setState(GameState.MENU)
        else:
            if state == GameState.GAMEONLINE:  #Failsafe since its not yet implemented
                print("Game Online Unavailable")
                print("Reverting to GameState.GAME")
                self.setState(GameState.GAME)
            else:
                self.undraw()
                if state == GameState.GAME:
                    self.game.draw(self.window)
                elif state == GameState.MENU:
                    self.menu.draw(self.window)
                self.gameState = state
Пример #2
0
class GameLoop:
    def __init__(self, option_handler):
        self.option_handler = option_handler
        self.state = State.MENU

        self.level = Level()
        self.players = dict()
        self.colliders = []

        self.time_scale = 1.0

        self.camera = Camera([0, 0], self.option_handler.resolution)

        self.respawn_time = 50.0

        self.menu = MainMenu()
        self.player_menus = [
            PlayerMenu((6 * i - 9) * basis(0)) for i in range(4)
        ]
        self.options_menu = OptionsMenu()
        self.options_menu.set_values(self.option_handler)

        self.network = None
        self.network_id = -1
        self.obj_id = -1

        self.controller_id = 0

    def load_level(self):
        self.level = Level('lvl')
        size = [
            int(self.camera.zoom * self.level.width),
            int(self.camera.zoom * self.level.height)
        ]
        self.level.background = pygame.Surface(size)
        self.level.background.fill((150, 150, 150))

        self.colliders.clear()

        self.colliders = [[[] for _ in range(int(self.level.height))]
                          for _ in range(int(self.level.width))]

        for wall in self.level.walls:
            wall.collider.update_occupied_squares(self.colliders)

        for obj in self.level.objects.values():
            obj.collider.update_occupied_squares(self.colliders)

    def reset_game(self):
        for w in self.level.walls:
            if type(w) is Basket:
                self.level.scoreboard.scores[w.team] = w.score

        for o in self.level.objects.values():
            if o.collider:
                o.collider.clear_occupied_squares(self.colliders)

        self.level.reset()

        for o in self.level.objects.values():
            o.collider.update_occupied_squares(self.colliders)

        for p in self.players.values():
            p.set_spawn(self.level, self.players)
            p.reset(self.colliders)

    def add_player(self, controller_id, network_id=-1):
        if network_id == -1:
            network_id = controller_id
        player = Player([0, 0], controller_id, network_id)
        self.players[network_id] = player

    def update(self, time_step):
        if self.state is State.PLAY:
            alive = 0
            for player in self.players.values():
                if player.active:
                    alive += 1

                player.update(self.level.gravity, self.time_scale * time_step,
                              self.colliders)

            if len(self.players) > 1 >= alive:
                self.reset_game()

            self.level.update(self.time_scale * time_step, self.colliders)

            for o in list(self.level.objects.values()):
                if type(o) is Ball and o.scored and o.speed < 0.1:
                    self.reset_game()

            self.camera.update(self.time_scale * time_step, self.players,
                               self.level)
        elif self.state is State.MENU:
            self.menu.update(time_step)
            self.state = self.menu.target_state
            self.menu.target_state = State.MENU

            if self.state is State.OPTIONS:
                self.option_handler.load()
                self.options_menu.set_values(self.option_handler)
        elif self.state is State.PLAYER_SELECT:
            if not self.players:
                return

            for pm in self.player_menus:
                if pm.controller_id is not None:
                    # FIXME: hardcoded index
                    self.players[pm.controller_id].body_type = pm.buttons[
                        1].get_value()
                    self.players[pm.controller_id].head_type = pm.buttons[
                        0].get_value()

            for pm in self.player_menus:
                if pm.controller_id is None:
                    if pm.controller_id in self.players:
                        del self.players[pm.controller_id]

                if pm.target_state is State.MENU:
                    pm.target_state = State.PLAYER_SELECT
                    self.state = State.MENU
                    self.players.clear()
                    return

                if pm.controller_id is not None and pm.target_state is State.PLAYER_SELECT:
                    return

            self.state = State.PLAY
            self.load_level()
            for p in self.players.values():
                p.set_spawn(self.level, self.players)
                p.reset(self.colliders)
        elif self.state is State.LAN:
            if self.network is None:
                self.network = Network()
                data = self.network.data

                if data is None:
                    print('Server can not be reached')
                    self.network = None
                    self.state = State.MENU
                    return

                self.network_id = data[0][0]

                self.add_player(self.controller_id, data[0][0])
                self.players[data[0][0]].apply_data(data[0])

                self.level.clear()
                self.level.apply_data(data[1])

                self.colliders = [[[]
                                   for _ in range(int(self.level.height + 1))]
                                  for _ in range(int(self.level.width + 1))]

                for wall in self.level.walls:
                    wall.collider.update_occupied_squares(self.colliders)

                for obj in self.level.objects.values():
                    obj.collider.update_occupied_squares(self.colliders)

                start_new_thread(self.network_thread, ())

            player = self.players[self.network_id]
            player.update(self.level.gravity, self.time_scale * time_step,
                          self.colliders)

            obj = self.players[self.network_id].object
            if obj is not None:
                obj.update(self.level.gravity, self.time_scale * time_step,
                           self.colliders)

            self.camera.update(time_step, self.players, self.level)

            for i in list(self.level.objects):
                obj = self.level.objects[i]
                if isinstance(obj, Destroyable):
                    obj.update(self.level.gravity, self.time_scale * time_step,
                               self.colliders)
                    if obj.destroyed and not obj.debris:
                        del self.level.objects[i]
                elif isinstance(obj, Bullet):
                    obj.update(self.level.gravity, self.time_scale * time_step,
                               self.colliders)
                    if obj.destroyed and not obj.particle_clouds:
                        del self.level.objects[i]
        elif self.state is State.OPTIONS:
            self.state = self.options_menu.target_state
            self.options_menu.target_state = State.OPTIONS

            if self.options_menu.options_changed:
                if self.options_menu.buttons[0].get_value() == 'windowed':
                    pygame.display.set_mode(
                        self.options_menu.buttons[1].get_value())
                    self.option_handler.fullscreen = False
                else:
                    pygame.display.set_mode(
                        self.options_menu.buttons[1].get_value(),
                        pygame.FULLSCREEN)
                    self.option_handler.fullscreen = True

                self.camera.set_resolution(
                    self.options_menu.buttons[1].get_value())

                self.option_handler.resolution = self.options_menu.buttons[
                    1].get_value()

                self.option_handler.shadows = self.options_menu.buttons[
                    4].get_value() == 'ON'

                self.option_handler.save()

                self.options_menu.options_changed = False

    def network_thread(self):
        while True:
            data = [self.players[self.network_id].get_data()]

            if self.obj_id != -1:
                data.append(self.level.objects[self.obj_id].get_data())
                self.level.objects[self.obj_id].attacked = False

            data = self.network.send(data)

            for p in data[0]:
                if p[0] == self.network_id:
                    player = self.players[self.network_id]
                    if player.health <= 0 < p[9]:
                        player.set_spawn(self.level, self.players)
                        player.reset(self.colliders)
                    player.health = p[9]
                else:
                    if p[0] not in self.players:
                        self.add_player(-1, p[0])

                    self.players[p[0]].apply_data(p)

            # kinda purkka
            ids = [p[0] for p in data[0]]
            for k in list(self.players.keys()):
                if k != self.network_id and k not in ids:
                    del self.players[k]

            for d in data[1]:
                if d[0] == self.obj_id:
                    continue

                if d[0] in self.level.objects:
                    self.level.objects[d[0]].apply_data(d)
                else:
                    obj = d[1]([d[2], d[3]])
                    obj.apply_data(d)
                    self.level.objects[d[0]] = obj
                    self.colliders[obj.collider.group].append(obj.collider)

            ids = [o[0] for o in data[1]]
            for i in list(self.level.objects):
                obj = self.level.objects[i]
                obj.collider.update_occupied_squares(self.colliders)
                if i not in ids:
                    if isinstance(obj, Destroyable):
                        obj.destroy(self.colliders)
                    elif isinstance(obj, Bullet):
                        obj.destroy()

    def input(self, input_handler):
        input_handler.update(self.camera)

        if input_handler.quit:
            self.state = State.QUIT

        if self.state is State.PLAY:
            if 0 in self.players:
                input_handler.relative_mouse[:] = input_handler.mouse_position - self.players[
                    0].shoulder

            for i, player in enumerate(self.players.values()):
                player.input(input_handler)

            if input_handler.keys_pressed[pygame.K_r]:
                self.reset_game()
        elif self.state is State.MENU:
            self.menu.input(input_handler)
            for i in range(len(input_handler.controllers)):
                if self.menu.selection_moved[i]:
                    self.controller_id = i
                    break
        elif self.state is State.PLAYER_SELECT:
            for i, controller in enumerate(input_handler.controllers):
                for pm in self.player_menus:
                    if pm.controller_id == i:
                        pm.input(input_handler, i)
                        break
                else:
                    for pm in self.player_menus:
                        if pm.controller_id is None:
                            pm.input(input_handler, i)
                        if pm.controller_id == i:
                            self.add_player(i)
                            break

            if all(pm.target_state is State.PLAYER_SELECT
                   for pm in self.player_menus):
                for i, controller in enumerate(input_handler.controllers):
                    if controller.button_down['B']:
                        self.state = State.MENU
        elif self.state is State.LAN:
            if self.network is not None:
                player = self.players[self.network_id]

                input_handler.relative_mouse[:] = input_handler.mouse_position - player.shoulder

                self.obj_id = player.object.id if player.object is not None else -1

                player.input(input_handler)
        elif self.state is State.OPTIONS:
            self.options_menu.input(input_handler)

    def draw(self, screen, image_handler):
        if self.state in [State.PLAY, State.LAN]:
            screen.fill((0, 0, 0))
            screen.blit(
                self.level.background,
                self.camera.world_to_screen(np.array([0, self.level.height])))

            if self.option_handler.shadows:
                self.level.draw_shadow(screen, self.camera, image_handler)
                for p in self.players.values():
                    p.draw_shadow(screen, self.camera, image_handler,
                                  self.level.light)

            self.level.draw(screen, self.camera, image_handler)

            for player in self.players.values():
                player.draw(screen, self.camera, image_handler)

            if self.option_handler.debug_draw:
                self.debug_draw(screen, image_handler)
        elif self.state is State.MENU:
            screen.fill((50, 50, 50))
            self.menu.draw(screen, self.camera, image_handler)
        elif self.state is State.PLAYER_SELECT:
            screen.fill((50, 50, 50))
            for pm in self.player_menus:
                pm.draw(screen, self.camera, image_handler)
                if pm.controller_id is not None:
                    self.players[pm.controller_id].set_position(pm.position +
                                                                3 * basis(1))
                    self.players[pm.controller_id].on_ground = True
                    self.players[pm.controller_id].animate(0.0)
                    self.players[pm.controller_id].draw(
                        screen, self.camera, image_handler)
        elif self.state is State.OPTIONS:
            screen.fill((50, 50, 50))
            self.options_menu.draw(screen, self.camera, image_handler)

    def debug_draw(self, screen, image_handler):
        for player in self.players.values():
            player.debug_draw(screen, self.camera, image_handler)

        self.level.debug_draw(screen, self.camera, image_handler)

    def play_sounds(self, sound_handler):
        if self.state in [State.PLAY, State.LAN]:
            for p in self.players.values():
                p.play_sounds(sound_handler)

            self.level.play_sounds(sound_handler)
        elif self.state is State.OPTIONS:
            sound_handler.set_volume(self.options_menu.buttons[2].get_value())
            sound_handler.set_music_volume(
                self.options_menu.buttons[3].get_value())

            self.option_handler.sfx_volume = self.options_menu.buttons[
                2].get_value()
            self.option_handler.music_volume = self.options_menu.buttons[
                3].get_value()
            self.option_handler.save()

            self.menu.play_sounds(sound_handler)
            self.options_menu.play_sounds(sound_handler)
        else:
            self.menu.play_sounds(sound_handler)
            self.options_menu.play_sounds(sound_handler)
            for pm in self.player_menus:
                pm.play_sounds(sound_handler)