Esempio n. 1
0
 def init_simulation_objects(self):
     
     self.simulation_connection, input_connection = multiprocessing.Pipe()
     
     self.match_simulation = MatchSimulation(
         input_connection,
         player_dictionary=self.player_dictionary,
         player_type_dictionary=self.player_type_dictionary
     )
Esempio n. 2
0
class VersusModeState():
    def __init__(self):
        
        self.initialized = False
        self.player_dictionary = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }
        self.player_key_handlers = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }
        self.player_event_handlers = {
            PlayerPositions.PLAYER1 : EventRegistry(),
            PlayerPositions.PLAYER2 : EventRegistry()
        }
        self.player_type_dictionary = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }
        self.player_sound_mixer_dictionary = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }
        self.player_health_bars = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }
        self.fight_label = None
        self.ready_label = None
        self.player1_wins_label = None
        self.player2_wins_label = None
        self.match_state = None
        self.match_time = None
        self.exit_button = button.ExitButton()
        self.exit_indicator = False
        self.versus_mode_start_time = None
        self.fight_start_time = None
        self.fight_end_time = None
        self.fight_end_timer = None
        self.versus_mode_start_timer = None
        self.fight_start_timer = None
        self.fps_label = None
        self.command_label = None
        self.point_effects = {}
        self.trail_effects = {
            PlayerPositions.PLAYER1 : {},
            PlayerPositions.PLAYER2 : {}
        }
        self.particle_effects = {
            PlayerPositions.PLAYER1 : {},
            PlayerPositions.PLAYER2 : {}
        }
        self.camera = None
        self.player_renderer_state = None
        self.surface_renderer = None
        self.match_simulation = None
        self.simulation_process = None
        self.simulation_connection = None
        self.pause = False
        self.pause_held = False
        self.attack_lists = {
            PlayerPositions.PLAYER1 : None,
            PlayerPositions.PLAYER2 : None
        }

        self.attack_result_sound_mixer = AttackResultSoundMixer()
    
    def init(self):
        
        self.init_match_state_variables()
        self.init_rendering_objects()
        self.init_player_data()
        self.init_simulation_objects()
        self.set_GUI_module_variables()
        self.init_stage()
        self.init_screen()
        
        self.initialized = True
        self.exit_indicator = False

    def init_screen(self):
        gamestate.screen.blit(gamestate.stage.background_image, (0,0))
        gamestate.new_dirty_rects.append(
            pygame.Rect((0,0), (gamestate._WIDTH, gamestate._HEIGHT))
        )
        gamestate.update_screen()

    def init_stage(self):
        gamestate.stage = stage.ScrollableStage(1047, 0, gamestate._WIDTH)

    def set_GUI_module_variables(self):
        wotsuievents.key_repeat = wotsuievents.KeyRepeat.HIGH
        gamestate.frame_rate = gamestate.VERSUSMODE_FRAMERATE
        gamestate.drawing_mode = gamestate.DrawingModes.DIRTY_RECTS

    def exit(self):
        
        self.end_simulation()
        self.cleanup_rendering_objects()
        self.cleanup_match_state_variables()
        self.reset_GUI_variables()
        self.initialized = False

    def reset_GUI_variables(self):
        wotsuievents.key_repeat = wotsuievents.KeyRepeat.NONE
        gamestate.drawing_mode = gamestate.DrawingModes.UPDATE_ALL
        gamestate.frame_rate = gamestate.NORMAL_FRAMERATE

    def handle_events(self):
        
        if self.simulation_process == None and self.exit_indicator == False:
            self.start_match_simulation()
        
        if gamestate.devmode:
            self.fps_label.set_text(str(gamestate.clock.get_fps()))
            self.fps_label.draw(gamestate.screen)
            gamestate.new_dirty_rects.append(
                pygame.Rect(
                    self.fps_label.position,
                    (self.fps_label.width, self.fps_label.height))
            )
        
        if self.exit_indicator == False:
            simulation_rendering_info = None
            
            while self.simulation_connection.poll():
                simulation_rendering_info = self.simulation_connection.recv()
                
                if simulation_rendering_info.match_time > self.match_time:
                    self.update_simulation_rendering(simulation_rendering_info)
            
            self.render_simulation()
            
            self.handle_pause_events()
            
            if not self.pause:
                self.clean_expired_effects()
                
                self.handle_match_state()
        
        if self.simulation_connection != None:
            self.update_simulation()
        
        self.handle_exit_events()
    
    def handle_pause_events(self):
        if ((
        pygame.K_KP_ENTER in wotsuievents.keys_pressed or 
        pygame.K_RETURN in wotsuievents.keys_pressed) and
        not self.pause_held):
            self.pause_held = True
            self.simulation_connection.send('PAUSE')
            self.pause = not self.pause
        elif ((
        pygame.K_KP_ENTER in wotsuievents.keys_released or 
        pygame.K_RETURN in wotsuievents.keys_released) and 
        self.pause_held):
            self.pause_held = False
        
        if self.pause:
            for attack_list in self.attack_lists.values():
                attack_list.handle_events()
    
    def build_player_command_types(self):
        
        return {
            PlayerPositions.PLAYER1 : self.player_key_handlers[
                PlayerPositions.PLAYER1
            ].get_command_data(wotsuievents.keys_pressed),
            PlayerPositions.PLAYER2 : self.player_key_handlers[
                PlayerPositions.PLAYER2
            ].get_command_data(wotsuievents.keys_pressed)
        }
    
    def init_simulation_objects(self):
        
        self.simulation_connection, input_connection = multiprocessing.Pipe()
        
        self.match_simulation = MatchSimulation(
            input_connection,
            player_dictionary=self.player_dictionary,
            player_type_dictionary=self.player_type_dictionary
        )
    
    def init_player_health_bars(self):
        self.player_health_bars[PlayerPositions.PLAYER1] = PlayerHealth(
            self.player_dictionary[PlayerPositions.PLAYER1].moveset.name, 
            PlayerPositions.PLAYER1
        )
        self.player_health_bars[PlayerPositions.PLAYER2] = PlayerHealth(
            self.player_dictionary[PlayerPositions.PLAYER2].moveset.name,
            PlayerPositions.PLAYER2
        )
    
    def init_attack_lists(self):
        self.attack_lists[PlayerPositions.PLAYER1] = AttackList(
            self.player_dictionary[PlayerPositions.PLAYER1].moveset,
            (
                int((gamestate._WIDTH / 2) - PAUSE_MENU_WIDTH),
                int((gamestate._HEIGHT / 2) - (PAUSE_MENU_HEIGHT / 2))
            )
        )
        self.attack_lists[PlayerPositions.PLAYER2] = AttackList(
            self.player_dictionary[PlayerPositions.PLAYER2].moveset,
            (
                int((gamestate._WIDTH / 2)),
                int((gamestate._HEIGHT / 2) - (PAUSE_MENU_HEIGHT / 2))
            )
        )
    
    def init_player_data(self):
        
        for player_position in self.player_type_dictionary.keys():
            if self.player_type_dictionary[player_position] == PlayerTypes.BOT:
                self.player_dictionary[player_position] = aiplayer.Bot(
                    (0, 0),
                    player_position
                )
            elif self.player_type_dictionary[player_position] == PlayerTypes.HUMAN:
                self.player_dictionary[player_position] = humanplayer.HumanPlayer(
                    (0, 0),
                    player_position
                )
            else:
                raise Exception(
                    "No player type set for player position: " + str(player_position)
                )
            
            
            self.player_key_handlers[player_position] = KeyToCommandTypeConverter(
                dict([(entry[1], entry[0]) 
                for entry in get_controls()[player_position].iteritems()])
            )
        
        
        player1 = self.player_dictionary[PlayerPositions.PLAYER1]
        player1.direction = PlayerStates.FACING_RIGHT
        player1.init_state()
        player1.model.move_model((400, 967))
        
        
        player2 = self.player_dictionary[PlayerPositions.PLAYER2]
        player2.direction = PlayerStates.FACING_LEFT
        player2.init_state()
        player2.model.move_model((1200, 967))
    
    def init_player_sounds(self):
        player1 = self.player_dictionary[PlayerPositions.PLAYER1]
        self.player_sound_mixer_dictionary[PlayerPositions.PLAYER1] = PlayerSoundMixer(player1)
        
        player2 = self.player_dictionary[PlayerPositions.PLAYER2]
        self.player_sound_mixer_dictionary[PlayerPositions.PLAYER2] = PlayerSoundMixer(player2)
    
    def init_match_state_variables(self):
        
        self.match_state = MatchStates.READY
        self.match_time = 0
        self.fight_end_timer = 0
        self.versus_mode_start_timer = 0
        self.fight_start_timer = 0
    
    def start_run_start_particle_effect(self, player_position, player_rendering_info):
        model = player_rendering_info.player_model
        orientation = model.orientation
        emit_position = (model.center()[0], model.bottom() + 10)
        
        if orientation == Orientations.FACING_RIGHT:
            self.particle_effects[player_position][EffectTypes.RIGHT_RUN_SMOKE].start(
                emit_position
            )
        else:
            self.particle_effects[player_position][EffectTypes.LEFT_RUN_SMOKE].start(
                emit_position
            )
    
    def start_jump_particle_effect(self, player_position, player_rendering_info):
        model = player_rendering_info.player_model
        
        
        if model.bottom() > gamestate.stage.floor_height - 50:
            emit_position = (model.center()[0], model.bottom() + 10)    
            self.particle_effects[player_position][EffectTypes.JUMP_SMOKE].start(
                emit_position
            )
    
    def start_fall_particle_effect(self, player_position, player_rendering_info):
        model = player_rendering_info.player_model
        emit_position = (model.center()[0], model.bottom() + 10)
        
        effect = self.particle_effects[player_position][EffectTypes.FALL_SMOKE]
        
        if not effect.active():
            effect.start(
                emit_position
            )
    
    def start_run_stop_particle_effect(self, player_position, player_rendering_info):
        model = player_rendering_info.player_model
        orientation = model.orientation
        
        if orientation == Orientations.FACING_RIGHT:
            emit_position = (model.position[0] + model.width, model.bottom() + 10)
            self.particle_effects[player_position][EffectTypes.LEFT_RUN_SMOKE].start(
                emit_position
            )
        else:
            emit_position = (model.position[0] - model.width, model.bottom() + 10)
            self.particle_effects[player_position][EffectTypes.RIGHT_RUN_SMOKE].start(
                emit_position
            )
    
    def init_rendering_objects(self):
        
        self.player_event_handlers = {
            PlayerPositions.PLAYER1 : EventRegistry(),
            PlayerPositions.PLAYER2 : EventRegistry()
        }
        
        self.player_event_handlers[PlayerPositions.PLAYER1].add_event_handler(
            (EventTypes.START, PlayerStates.RUNNING),
            self.start_run_start_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER1].add_event_handler(
            (EventTypes.STOP, PlayerStates.RUNNING),
            self.start_run_stop_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER1].add_event_handler(
            (EventTypes.START, PlayerStates.JUMPING),
            self.start_jump_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER1].add_event_handler(
            (EventTypes.START, EventStates.STUN_GROUND),
            self.start_fall_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER2].add_event_handler(
            (EventTypes.START, PlayerStates.RUNNING),
            self.start_run_start_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER2].add_event_handler(
            (EventTypes.STOP, PlayerStates.RUNNING),
            self.start_run_stop_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER2].add_event_handler(
            (EventTypes.START, PlayerStates.JUMPING),
            self.start_jump_particle_effect
        )
        self.player_event_handlers[PlayerPositions.PLAYER2].add_event_handler(
            (EventTypes.START, EventStates.STUN_GROUND),
            self.start_fall_particle_effect
        )
        
        self.particle_effects = {
            PlayerPositions.PLAYER1 : {
                EffectTypes.LEFT_RUN_SMOKE : RunSmoke(1100, 1),
                EffectTypes.RIGHT_RUN_SMOKE : RunSmoke(1100, -1),
                EffectTypes.JUMP_SMOKE : JumpSmoke(1100),
                EffectTypes.FALL_SMOKE : FallSmoke(1100)
            },
            PlayerPositions.PLAYER2 : {
                EffectTypes.LEFT_RUN_SMOKE : RunSmoke(1100, 1),
                EffectTypes.RIGHT_RUN_SMOKE : RunSmoke(1100, -1),
                EffectTypes.JUMP_SMOKE : JumpSmoke(1100),
                EffectTypes.FALL_SMOKE : FallSmoke(1100)
            }
        }
        
        self.point_effects = {}
        self.trail_effects = {
            PlayerPositions.PLAYER1 : {},
            PlayerPositions.PLAYER2 : {}
        }
        
        self.camera = versusrendering.ViewportCamera(
            gamestate.stage.width,
            gamestate.stage.height,
            gamestate._WIDTH,
            gamestate._HEIGHT
        )
        self.player_renderer_state = versusrendering.PlayerRendererState(
            self.camera,
            [PlayerPositions.PLAYER1, PlayerPositions.PLAYER2]
        )
        
        self.surface_renderer = versusrendering.SurfaceRenderer(self.camera)
        
        self.fps_label = button.Label(
            (20,20), 
            str(gamestate.clock.get_fps()),(0,0,255),
            30
        )
        #command_label = AttackLabel("", [])
        #command_label.key_combination_label.set_position((20,50))
        
        self.ready_label = button.Label((0,0),'READY...',(0,0,255),80)
        ready_label_position = (
            (gamestate._WIDTH / 2) - (self.ready_label.width / 2),
            (gamestate._HEIGHT / 2) - (self.ready_label.height / 2)
        )
        self.ready_label.set_position(ready_label_position)
        
        self.fight_label = button.Label((0,0),'FIGHT!',(0,0,255),80)
        fight_label_position = (
            (gamestate._WIDTH / 2) - (self.fight_label.width / 2),
            (gamestate._HEIGHT / 2) - (self.fight_label.height / 2)
        )
        self.fight_label.set_position(fight_label_position)
        
        self.player1_wins_label = button.Label((0,0),'PLAYER 1 WINS!',(0,0,255),80)
        player1_wins_label_position = (
            (gamestate._WIDTH / 2) - (self.player1_wins_label.width / 2), 
            (gamestate._HEIGHT / 2) - (self.player1_wins_label.height / 2)
        )
        self.player1_wins_label.set_position(player1_wins_label_position)
        
        self.player2_wins_label = button.Label((0,0),'PLAYER 2 WINS!',(0,0,255),80)
        player2_wins_label_position = (
            (gamestate._WIDTH / 2) - (self.player2_wins_label.width / 2),
            (gamestate._HEIGHT / 2) - (self.player2_wins_label.height / 2)
        )
        self.player2_wins_label.set_position(player2_wins_label_position)
    
    def cleanup_match_state_variables(self):
        
        self.match_state = None
        self.match_time = 0
        self.versus_mode_start_timer = None
        self.fight_start_timer = None
        self.fight_end_timer = None

    def cleanup_rendering_objects(self):
        
        self.point_effects = {}
        self.player_health_bars = {}
        self.trail_effects = None
        self.player_renderer_state = None
        self.surface_renderer = None
        self.fps_label = None
        self.command_label = None
        self.ready_label = None
        self.fight_label = None
        self.player1_wins_label = None
        self.player2_wins_label = None

    def end_simulation(self):
        
        self.simulation_connection.send('STOP')
        self.simulation_connection.close()
        self.simulation_process.terminate()
        self.simulation_process.join()
        self.simulation_connection = None
        gamestate.processes.remove(self.simulation_process)
        self.simulation_process = None
        self.match_simulation = None


    def handle_exit_events(self):
        
        self.exit_button.draw(gamestate.screen)
        gamestate.new_dirty_rects.append(
            pygame.Rect(
                self.exit_button.position, 
                (self.exit_button.width, self.exit_button.height)
            )
        )
        
        if pygame.MOUSEBUTTONDOWN in wotsuievents.event_types:
            if self.exit_button.contains(wotsuievents.mouse_pos):
                self.exit_indicator = True
                self.exit_button.color = button.Button._SlctdColor
                self.exit_button.symbol.color = button.Button._SlctdColor
        elif pygame.MOUSEBUTTONUP in wotsuievents.event_types:
            if self.exit_indicator == True:
                self.exit_indicator = False
                self.exit_button.color = button.Button._InactiveColor
                self.exit_button.symbol.color = button.Button._InactiveColor
                
                if self.exit_button.contains(wotsuievents.mouse_pos):
                    gamestate.mode = gamestate.Modes.VERSUSMOVESETSELECT
                    self.exit()

    def clean_expired_effects(self):
        
        dead_effects = []
        
        for point_id, effect in self.point_effects.iteritems():
            if effect.effect_over():
                dead_effects.append(point_id)
        
        for point_id in dead_effects:
            del self.point_effects[point_id]

    def render_simulation(self):
        
        ground_surface = gamestate.stage.draw_ground()
        self.surface_renderer.draw_surface_to_screen(
            (0, gamestate.stage.floor_height - 20), 
            ground_surface
        )
        versusrendering.draw_player_renderer_state(
            self.player_renderer_state, 
            gamestate.screen
        )
        
        for effect in self.point_effects.values():
            
            effect_position, effect_surface = effect.draw_effect()
            self.surface_renderer.draw_surface_to_screen(
                effect_position, 
                effect_surface
            )
        
        for player_trail_effects in self.trail_effects.values():
            for point_effects in player_trail_effects.values():
                for trail_effect in point_effects.values():
                    if trail_effect.is_renderable():
                        for polygon_positions in trail_effect.get_polygons():
                            self.surface_renderer.draw_polygon(
                                polygon_positions,
                                trail_effect.color
                            )
        
        for player_particle_effects in self.particle_effects.values():
            for effect in player_particle_effects.values():
                if effect.active():
                    
                    surface, position = effect.draw()
                    self.surface_renderer.draw_surface_to_screen(
                        position, 
                        surface
                    )
        
        for health_bar in self.player_health_bars.values():
            self.surface_renderer.draw_surface_to_absolute_position(
                health_bar.position, 
                health_bar.draw()
            )
        
        if self.pause:
            for attack_list in self.attack_lists.values():
                attack_list.draw(gamestate.screen)

    def update_simulation(self):
        self.simulation_connection.send(
            (self.build_player_command_types(), gamestate.time_passed)
        )

    def update_simulation_rendering(self, simulation_rendering_info):
        
        self.set_outline_color(simulation_rendering_info)
        
        for effect in self.point_effects.values():
            if not self.pause:
                effect.update(gamestate.time_passed)
        
        if simulation_rendering_info.attack_result_rendering_info != None:
            self.create_collision_effects(
                simulation_rendering_info.attack_result_rendering_info
            )
            self.attack_result_sound_mixer.handle_hit_sounds(
                simulation_rendering_info.attack_result_rendering_info
            )
            
            if simulation_rendering_info.attack_result_rendering_info.attack_type in InputActionTypes.STRONG_ATTACKS:
                self.camera.start_shaking(
                    simulation_rendering_info.attack_result_rendering_info.attack_damage
                )
        
        if not self.pause:
            self.update_trail_effects(
                simulation_rendering_info.player_rendering_info_dictionary
            )
            self.update_particle_effects()
        
        for player_position, player_rendering_info in simulation_rendering_info.player_rendering_info_dictionary.iteritems():
            event_handler = self.player_event_handlers[player_position]
            
            for event in player_rendering_info.events:
                event_handler.fire_event_handlers(
                    event, 
                    (player_position, player_rendering_info)
                )
            
            health_bar = self.player_health_bars[player_position]
            health_bar.update(
                gamestate.time_passed,
                player_rendering_info.health_percentage
            )
        
        self.player_renderer_state.update(
            simulation_rendering_info.player_rendering_info_dictionary, 
            1
        )
        self.play_player_sounds(simulation_rendering_info, PlayerPositions.PLAYER1)
        self.play_player_sounds(simulation_rendering_info, PlayerPositions.PLAYER2)
        self.match_state = simulation_rendering_info.match_state
        self.match_time = simulation_rendering_info.match_time
    
    def update_particle_effects(self):
        for player_particle_effects in self.particle_effects.values():
            for effect in player_particle_effects.values():
                if effect.active():
                    effect.update(gamestate.time_passed)
    
    def update_trail_effects(self, player_rendering_info): 
        
        for player_position in self.trail_effects.keys():
            player_info = player_rendering_info[player_position]
            attack_type = player_info.attack_type
            player_trail_effects = self.trail_effects[player_position]
            
            if attack_type != None: #and attack_type in InputActionTypes.QUICK_ATTACKS:
                
                player_model = player_info.player_model
                
                if player_info.animation_name in player_trail_effects:
                    #update pointeffects
                    for point_name, effect in player_trail_effects[player_info.animation_name].iteritems():
                        effect.update(player_model.points[point_name].pos)
                
                else:
                    #create point effects
                    point_effects = player_trail_effects[player_info.animation_name] = {}
                    
                    if attack_type in InputActionTypes.PUNCHES:
                        point_effects[PointNames.RIGHT_HAND] = TrailEffect(
                            player_model.points[PointNames.RIGHT_HAND].pos,
                            10,
                            50,
                            player_info.player_health_color
                        )
                        point_effects[PointNames.LEFT_HAND] = TrailEffect(
                            player_model.points[PointNames.LEFT_HAND].pos,
                            10,
                            50,
                            player_info.player_health_color
                        )
                    else:
                        point_effects[PointNames.RIGHT_FOOT] = TrailEffect(
                            player_model.points[PointNames.RIGHT_FOOT].pos,
                            10,
                            50,
                            player_info.player_health_color
                        )
                        point_effects[PointNames.LEFT_FOOT] = TrailEffect(
                            player_model.points[PointNames.LEFT_FOOT].pos,
                            10,
                            50,
                            player_info.player_health_color
                        )
            else:
                if len(player_trail_effects.keys()) > 0:
                    self.trail_effects[player_position] = {}
    
    def play_player_sounds(self, simulation_rendering_info, player_position):
        player_rendering_info = simulation_rendering_info.player_rendering_info_dictionary[player_position]
        
        self.player_sound_mixer_dictionary[player_position].play_sound(
            player_rendering_info.player_state,
            player_rendering_info.animation_name,
            player_rendering_info.frame_index
        )
    
    def start_match_simulation(self):    
        
        self.match_simulation.step(
            self.build_player_command_types(), self.match_simulation.timestep
        )
        
        #initialize renderer state
        self.player_renderer_state.update(
            self.match_simulation.get_rendering_info(
            ).player_rendering_info_dictionary, 
            1
        )
        
        #start simulation process
        self.simulation_process = multiprocessing.Process(
            target=self.match_simulation.run,
            name="Way of the stick simulation"
        )
        gamestate.processes.append(self.simulation_process)
        self.simulation_process.start()
        
        #reset game clock
        gamestate.clock.tick(gamestate.frame_rate)
        gamestate.update_time()
        gamestate.clock.tick(gamestate.frame_rate)
        gamestate.update_time()

    def set_outline_color(self, simulation_rendering_info):
        player_rendering_info_dictionary = simulation_rendering_info.player_rendering_info_dictionary
        
        for player_position, rendering_info in player_rendering_info_dictionary.iteritems():
            
            if rendering_info.player_state == PlayerStates.STUNNED:
                if (simulation_rendering_info.match_time % 30) >= 15:
                    rendering_info.player_outline_color = (255, 255, 0)
                else:
                    rendering_info.player_outline_color = (255, 0, 0)
            else:
                pass #leave the outline color as it is

    def handle_match_state(self):
        
        if self.match_state == MatchStates.READY:
            self.ready_label.draw(gamestate.screen)
            gamestate.new_dirty_rects.append(
                pygame.Rect(
                    self.ready_label.position,
                    (self.ready_label.width, self.ready_label.height))
            )
            
        elif self.match_state == MatchStates.FIGHT and self.match_time < 4000:
            self.fight_label.draw(gamestate.screen)
            gamestate.new_dirty_rects.append(
                pygame.Rect(
                    self.fight_label.position,
                    (self.fight_label.width, self.fight_label.height))
            )
        
        elif self.match_state == MatchStates.PLAYER1_WINS:
            
            if self.fight_end_timer < 8000:
                self.fight_end_timer += gamestate.time_passed
                self.player1_wins_label.draw(gamestate.screen)
                
                gamestate.new_dirty_rects.append(
                    pygame.Rect(
                        self.player1_wins_label.position, 
                        (
                            self.player1_wins_label.width,
                            self.player1_wins_label.height
                        )
                    )
                )
                
            else:
                gamestate.mode = gamestate.Modes.VERSUSMOVESETSELECT
                self.exit()
        elif self.match_state == MatchStates.PLAYER2_WINS:
            
            if self.fight_end_timer < 8000:
                self.fight_end_timer += gamestate.time_passed
                self.player2_wins_label.draw(gamestate.screen)
                gamestate.new_dirty_rects.append(
                    pygame.Rect(
                        self.player2_wins_label.position,
                        (
                            self.player2_wins_label.width,
                            self.player2_wins_label.height
                        )
                    )
                )
            else:
                gamestate.mode = gamestate.Modes.VERSUSMOVESETSELECT
                self.exit()

    def create_collision_effects(self, attack_result_rendering_info):
        
        attack_knockback_vector = attack_result_rendering_info.knockback_vector
        
        damage = attack_result_rendering_info.attack_damage
        effect_height = max(50, damage)
        effect_width = max(50, .2 * damage)
        fade_rate = .2
        
        angle_in_degrees = 0
        
        if attack_knockback_vector[0] == 0:
            if mathfuncs.sign(attack_knockback_vector[1]) == 1:
                angle_in_degrees = 0
            else:
                angle_in_degrees = 180
                
        elif attack_knockback_vector[1] == 0:
            if mathfuncs.sign(attack_knockback_vector[0]) == 1:
                angle_in_degrees = 90
            else:
                angle_in_degrees = 270
            
        else:
            angle_in_degrees = math.degrees(
                math.asin(attack_knockback_vector[1] / math.hypot(
                        attack_knockback_vector[0], attack_knockback_vector[1]
                    )
                )
            )
        
        attack_point = attack_result_rendering_info.attack_point
        if not attack_point.id in self.point_effects:
            if attack_result_rendering_info.clash_indicator:
                self.point_effects[attack_point.id] = ClashEffect(
                    attack_result_rendering_info.clash_position,
                    angle_in_degrees,
                    effect_width,
                    effect_height,
                    .7,
                    fade_rate,
                    1
                )
            else:
                self.point_effects[attack_point.id] = HitEffect(
                    attack_result_rendering_info.attack_point.pos,
                    angle_in_degrees,
                    effect_width,
                    effect_height,
                    .7,
                    fade_rate,
                    .6
                )