Example #1
0
    def __init__(self, owner):
        self.owner = owner        
        self.moving_right = False
        self.moving_left = False        
        self.push_balls = False 
               
        self.fps_clock = pygame.time.Clock() 
           
        self.physics_world = physics.PhysicsWorld(STEP_TIME_INTEGRATE) 
        
        self.game_status = GameLayer.INITIALIZATION       
        self.current_map = MapSelector()
        
        self.bricks = []
        self.paddles = []
        self.balls = []

        self.entities = []
        self.bodies = []       
        
        on_ball_brick_event = self.physics_world.CallBack('ball', 'brick', self.on_ball_brick_collision)
        on_ball_paddle_event = self.physics_world.CallBack('ball', 'paddle', self.on_ball_paddle_collision)
        on_ball_bottom_wall_event = self.physics_world.CallBack('ball', 'bottom-wall', self.on_ball_bottom_wall_collision)
        on_ball_left_wall_event = self.physics_world.CallBack('ball', 'left-wall', self.on_ball_left_right_collision)
        on_ball_right_wall_event = self.physics_world.CallBack('ball', 'right-wall', self.on_ball_left_right_collision)
        
        
        self.physics_world.add_callback(on_ball_brick_event)
        self.physics_world.add_callback(on_ball_paddle_event)
        self.physics_world.add_callback(on_ball_bottom_wall_event) 
        self.physics_world.add_callback(on_ball_left_wall_event)
        self.physics_world.add_callback(on_ball_right_wall_event)     
Example #2
0
class GameLayer:
    """
    Processes the main game logic
    """   
    INITIALIZATION = 0
    GAME_LOOP = 1
    GAME_EXIT = 2
    GAME_WIN_SCREEN = 3
    GAME_PAUSE_SCREEN = 4
    
    def __init__(self, owner):
        self.owner = owner        
        self.moving_right = False
        self.moving_left = False        
        self.push_balls = False 
               
        self.fps_clock = pygame.time.Clock() 
           
        self.physics_world = physics.PhysicsWorld(STEP_TIME_INTEGRATE) 
        
        self.game_status = GameLayer.INITIALIZATION       
        self.current_map = MapSelector()
        
        self.bricks = []
        self.paddles = []
        self.balls = []

        self.entities = []
        self.bodies = []       
        
        on_ball_brick_event = self.physics_world.CallBack('ball', 'brick', self.on_ball_brick_collision)
        on_ball_paddle_event = self.physics_world.CallBack('ball', 'paddle', self.on_ball_paddle_collision)
        on_ball_bottom_wall_event = self.physics_world.CallBack('ball', 'bottom-wall', self.on_ball_bottom_wall_collision)
        on_ball_left_wall_event = self.physics_world.CallBack('ball', 'left-wall', self.on_ball_left_right_collision)
        on_ball_right_wall_event = self.physics_world.CallBack('ball', 'right-wall', self.on_ball_left_right_collision)
        
        
        self.physics_world.add_callback(on_ball_brick_event)
        self.physics_world.add_callback(on_ball_paddle_event)
        self.physics_world.add_callback(on_ball_bottom_wall_event) 
        self.physics_world.add_callback(on_ball_left_wall_event)
        self.physics_world.add_callback(on_ball_right_wall_event)     
        
    def initialize(self, previous_layer):      
        self.moving_right = False
        self.moving_left = False           
        self.push_balls = False
        
        self.game_status = GameLayer.INITIALIZATION            
        self.current_map.initialize_current_map()
        self.update_map()
        
    def clear_game(self):
        self.bricks = []
        self.paddles = []
        self.balls = []

        self.entities = []
        self.bodies = []
        
        self.physics_world.clear_bodies()
        
        self.push_balls = False
    
    def update_map(self):
        self.clear_game()
        m = self.current_map.get_next_map()
        
        for brick in m.bricks:
            self.register_entity(brick)
            self.bricks.append(brick)

        for ball in m.balls:
            self.register_entity(ball)
            self.balls.append(ball)

        for paddle in m.paddles:
            self.register_entity(paddle)
            self.paddles.append(paddle)

        for body in m.bodies:
            self.register_body(body)

    def register_body(self, new_body):
        if not new_body in self.bodies:
            self.physics_world.add_body(new_body)
            self.bodies.append(new_body)

    def register_entity(self, new_entity):
        if not new_entity in self.entities:
            self.physics_world.add_body(new_entity.body)
            self.entities.append(new_entity) 

    def unregister_entity(self, entity):
        if entity in self.entities:
            self.physics_world.delete_body(entity.body)
            self.entities.remove(entity)                              

    def on_ball_brick_collision(self, ball_body, brick_body, normal):       
        brick_ent = brick_body.tag_ent
        ball_ent = ball_body.tag_ent
        brick_ent.apply_damage(ball_ent.damage_points) 
        ball_ent.body.set_velocity(min(self.physics_world.MAX_SPEED, ball_body.velocity * 1.1)) 
        
    def on_ball_paddle_collision(self, ball_body, paddle_body, normal):
        # Adjusts the ball direction if the paddle is moving when the ball collides with it
        angle = math.acos(dot(normal, ball_body.direction)) # Angle between the reflected direction and the normal
        delta_angle = abs(((math.pi * 0.5) - angle) * 0.5) # Half the angle that remains if were to perform a 90 degree reflection
        if paddle_body.direction.x > 0: # Clockwise rotation because the paddle is moving to the right
            ball_body.direction = normalize(rotate(ball_body.direction, delta_angle))
        elif paddle_body.direction.x < 0: # Counter-clockwise rotation because the paddle is moving to the left
            ball_body.direction = normalize(rotate(ball_body.direction, -delta_angle))           
                   
    def on_ball_bottom_wall_collision(self, bottom_body, ball_body, normal):
        if len(self.balls) == 1:
            self.game_status = GameLayer.GAME_EXIT     
        else:
            ball_ent = ball_body.tag_ent
            self.unregister_entity(ball_ent)
    
    def on_ball_left_right_collision(self, ball_body, wall_body, normal):
        angle = math.acos(dot(normal, ball_body.direction)) # Angle between the reflected direction and the normal

        # If the angle is too flat, add a small rotation to the reflected direction
        if angle < 0.1:
            delta_angle = 0.2
            if ball_body.direction.y > 0: # Counter-clockwise rotation because the ball is moving downwards
                ball_body.direction = normalize(rotate(ball_body.direction, -delta_angle))
            elif ball_body.direction.y <= 0: # Clockwise rotation because the ball is moving upwards 
                ball_body.direction = normalize(rotate(ball_body.direction, delta_angle))   
            
    def update(self, step_time):
        def change_dir_vel(entities, direction, velocity):
            for entity in entities:
                entity.body.direction = direction
                entity.body.set_velocity(velocity)
           
        if(self.moving_left or self.moving_right):
            if self.moving_left:
                change_dir_vel(self.paddles, Vector2(-1,0), PADDLE_VELOCITY)
                if self.game_status == GameLayer.INITIALIZATION:
                    change_dir_vel(self.balls, Vector2(-1,0), PADDLE_VELOCITY)  
            else:
                change_dir_vel(self.paddles, Vector2(1,0), PADDLE_VELOCITY)
                if self.game_status == GameLayer.INITIALIZATION:
                    change_dir_vel(self.balls, Vector2(1,0), PADDLE_VELOCITY)    
        else:
            change_dir_vel(self.paddles, ZERO2, magnitude(ZERO2))
            if self.game_status == GameLayer.INITIALIZATION:
                change_dir_vel(self.balls, ZERO2, magnitude(ZERO2))
                    
        if self.push_balls and self.game_status == GameLayer.INITIALIZATION:                  
            for ball in self.balls:
                if ball.body.is_static:
                    ball.body.is_static = False
            v = Vector2(BALL_VELOCITY_X, BALL_VELOCITY_Y) 
            change_dir_vel(self.balls, normalize(v), magnitude(v))
            self.push_balls = False
            self.game_status = GameLayer.GAME_LOOP
             
        # Remove bricks that have been destroyed
        free_brick_list = []
        for brick in self.bricks:
            if brick.health_points == 0:
                self.unregister_entity(brick)
                free_brick_list.append(brick)
        self.bricks = [ b for b in self.bricks if free_brick_list.count(b) == 0 ] 
                
        for paddle in self.paddles:          
            # Integrate paddle
            paddle.body.rect.position = sum(paddle.body.rect.position,
                                            mul(paddle.body.direction, paddle.body.velocity * step_time))
    
            # Relocate paddle position to a valid position range
            paddle.body.rect.position.x = utils.clamp(paddle.body.rect.position.x, 0, 
                                                      WINDOW_WIDTH - PADDLE_WIDTH)
            paddle.body.rect.position.y = WINDOW_HEIGHT - PADDLE_HEIGHT - PADDLE_LINE_SPACING

        for ball in self.balls:
            if ball.body.is_static:
                pos_r = Vector2((PADDLE_WIDTH - BALL_WIDTH) * 0.5,  - BALL_HEIGHT)
                ball.body.rect.position = sum(self.paddles[0].body.rect.position, pos_r)
     
    def run(self):
        """
        Main game loop: processes inputs, updates the game status and renders the game scene
        """        
        last_update_time = pygame.time.get_ticks()
        accumulated = 0.0
        while self.game_status == GameLayer.INITIALIZATION or self.game_status == GameLayer.GAME_LOOP:
            #Process inputs       
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    utils.terminate()             
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_LEFT:
                        self.moving_left = True
                    elif event.key == pygame.K_RIGHT:
                        self.moving_right = True
                    elif event.key == pygame.K_a:
                        self.push_balls = True 
                    elif event.key == pygame.K_p: 
                        self.game_status = GameLayer.GAME_PAUSE_SCREEN
                elif event.type == pygame.KEYUP:
                    if event.key == pygame.K_ESCAPE:
                        utils.terminate()
                    elif event.key == pygame.K_RIGHT:
                        self.moving_right = False
                    elif event.key == pygame.K_LEFT:
                        self.moving_left = False  
                  
            time = pygame.time.get_ticks()    
            delta_time = time - last_update_time
            
            accumulated = accumulated + delta_time                
            if accumulated > BALL_PUSH: 
                self.push_balls = True
                accumulated = 0.0
            
            while delta_time > 0:
                sim_step_time = STEP_TIME
                if delta_time - STEP_TIME < 0:
                    sim_step_time = delta_time
                self.update(sim_step_time)
                self.physics_world.step_simulation(sim_step_time)
                
                if len(self.bricks) < 1:
                    if not self.current_map.has_next_map():
                        self.game_status = GameLayer.GAME_WIN_SCREEN
                    else:
                        self.update_map()
                        self.game_status = GameLayer.INITIALIZATION
                        accumulated = 0
                delta_time -= sim_step_time
            last_update_time = time
            graphics.clear_display_surf(BLUE)        
            for entity in self.entities:            
                dest_rect = pygame.Rect(entity.body.rect.position.x,
                                        entity.body.rect.position.y,
                                        entity.body.rect.w,
                                        entity.body.rect.h)
                graphics.draw(entity.surface, entity.surface_src, dest_rect)
            graphics.flip_display_surf()
            
            self.fps_clock.tick(MAX_FPS)
            
    def at_exit(self):
        """
        Sets the next layer to execute: GameOverLayer or PauseLayer     
        """
        if self.game_status == GameLayer.GAME_PAUSE_SCREEN:
            self.owner.set_layer(self.owner.PAUSE_LAYER)
            self.game_status = GameLayer.GAME_LOOP
        elif self.game_status == GameLayer.GAME_WIN_SCREEN:
            self.owner.set_layer(self.owner.WIN_LAYER)               
        else:
            self.owner.set_layer(self.owner.GAME_OVER_LAYER)
   
    def signal_exit(self):
        self.game_status = GameLayer.GAME_EXIT