Ejemplo n.º 1
0
class Part:
    def __init__(self, x,y, image):
        self.base_image = image
        radius = (image.get_width() + image.get_height()) /4
        self.circle = Circle(x, y, radius)
        self.decay = False
        self.decay_time = STAR.DECAY_TIME
        self.image = self.base_image.copy()
        self.image_position = [x-image.get_width()/2, y-image.get_height() /2]
        
    def update(self, player, delta):
        if self.decay:
            self.decay_time -= delta
            if self.decay_time < 0:
                return True
            size = 1.0*self.decay_time/STAR.DECAY_TIME
            self.image = pygame.transform.rotozoom(self.base_image, 0, size)
            self.image_position = [self.circle.center[0] - self.image.get_width()/2, self.circle.center[1] - self.image.get_height()/2]
            self.image.set_alpha(size*255)
            return False
        else:
            if self.circle.collide_circle(player.circle):
                self.decay = True
                return True
            return False
Ejemplo n.º 2
0
class Part:
    def __init__(self, x, y, image):
        self.base_image = image
        radius = (image.get_width() + image.get_height()) / 4
        self.circle = Circle(x, y, radius)
        self.decay = False
        self.decay_time = STAR.DECAY_TIME
        self.image = self.base_image.copy()
        self.image_position = [
            x - image.get_width() / 2, y - image.get_height() / 2
        ]

    def update(self, player, delta):
        if self.decay:
            self.decay_time -= delta
            if self.decay_time < 0:
                return True
            size = 1.0 * self.decay_time / STAR.DECAY_TIME
            self.image = pygame.transform.rotozoom(self.base_image, 0, size)
            self.image_position = [
                self.circle.center[0] - self.image.get_width() / 2,
                self.circle.center[1] - self.image.get_height() / 2
            ]
            self.image.set_alpha(size * 255)
            return False
        else:
            if self.circle.collide_circle(player.circle):
                self.decay = True
                return True
            return False
Ejemplo n.º 3
0
class Star:
    def __init__(self, position, image_dict):
        self.circle = Circle(position[0], position[1], STAR.RADIUS)

        self.base_image = image_dict['star']
        self.image = self.base_image
        self.image_position = [
            position[0] - STAR.RADIUS, position[1] - STAR.RADIUS
        ]
        self.angle = 0
        self.d_angle = STAR.D_ANGLE
        self.d_d_angle = STAR.D_D_ANGLE
        self.decay = False
        self.decay_time = STAR.DECAY_TIME

    def update(self, player, delta):
        if self.decay:
            return self.update_decay(player, delta)
        else:
            return self.update_normal(player, delta)

    def update_normal(self, player, delta):
        self.d_angle -= self.angle * self.d_d_angle * delta * 0.001
        self.angle += self.d_angle * delta * 0.001
        self.image = pygame.transform.rotozoom(self.base_image, self.angle,
                                               1.0)
        self.image_position = [
            self.circle.center[0] - self.image.get_width() / 2,
            self.circle.center[1] - self.image.get_height() / 2
        ]
        if self.circle.collide_circle(player.circle):
            self.decay = True
            self.d_d_angle = STAR.DECAY_D_D_ANGLE
            return True
        return False

    def update_decay(self, player, delta):
        self.decay_time -= delta
        if self.decay_time < 0:
            return True
        self.d_angle += self.angle * self.d_d_angle * delta * 0.001
        self.angle += self.d_angle * delta * 0.001
        size = 1.0 * self.decay_time / STAR.DECAY_TIME
        self.image = pygame.transform.rotozoom(self.base_image, self.angle,
                                               size)
        self.image_position = [
            self.circle.center[0] - self.image.get_width() / 2,
            self.circle.center[1] - self.image.get_height() / 2
        ]
        self.image.set_alpha(size * 255)
        return False
Ejemplo n.º 4
0
class Booster:
    def __init__(self,
                 img_dict,
                 type,
                 obj,
                 position_or_angle,
                 force,
                 radius=30):
        if type == 'a':  # count start_position
            start = sum(
                obj.circle.center,
                multiply(angle_to_vector(position_or_angle),
                         obj.circle.radius + radius))
            angle = position_or_angle
            vector = angle_to_vector(angle)
        else:
            vector = inverse(perpendicular(normalise(obj.line.vector)))
            shift = multiply(obj.line.vector,
                             -position_or_angle / 100.0)  # side shift
            start = sum(
                sum(obj.line.start,
                    multiply(vector, PLATFORM.BORDER + radius + 3)), shift)
            angle = vector_to_angle(vector)
        self.circle = Circle(int(round(start[0])), int(round(start[1])),
                             radius)
        self.force = force
        self.force_vector = multiply(vector, force)
        self.img_list = []
        for i in img_dict['geyser'][obj.colour]:
            self.img_list.append(pygame.transform.rotozoom(i, -angle, 1.))
        self.frame = 0
        self.image = self.img_list[self.frame]
        self.frame_speed = BOOSTER.FRAME_SPEED + random.randint(-2, 2)
        image_offset = (-self.img_list[0].get_width() / 2,
                        -self.img_list[0].get_height() / 2)
        self.image_position = sum(self.circle.center, image_offset)

    def get_force(self, player):
        if self.circle.collide_circle(player.circle):
            return self.force_vector
        return [0, 0]

    def update(self, delta):
        self.frame += delta * 0.001 * self.frame_speed
        if self.frame > BOOSTER.FRAMES:
            self.frame %= BOOSTER.FRAMES
        frame = int(round(self.frame))
        if frame >= BOOSTER.FRAMES or frame < 0:
            frame = frame % BOOSTER.FRAMES
        self.image = self.img_list[frame]
Ejemplo n.º 5
0
class Star:
    def __init__(self, position, image_dict):
        self.circle = Circle(position[0], position[1], STAR.RADIUS)
        
        self.base_image = image_dict['star']
        self.image = self.base_image
        self.image_position = [position[0] - STAR.RADIUS, position[1] - STAR.RADIUS]
        self.angle = 0
        self.d_angle = STAR.D_ANGLE
        self.d_d_angle = STAR.D_D_ANGLE
        self.decay = False
        self.decay_time = STAR.DECAY_TIME
        
    def update(self, player, delta):
        if self.decay:
            return self.update_decay(player, delta)
        else:
            return self.update_normal(player, delta)
        
    def update_normal(self, player, delta):
        self.d_angle -= self.angle * self.d_d_angle * delta * 0.001
        self.angle += self.d_angle * delta * 0.001
        self.image = pygame.transform.rotozoom(self.base_image, self.angle, 1.0)
        self.image_position = [self.circle.center[0] - self.image.get_width()/2, self.circle.center[1] - self.image.get_height()/2]
        if self.circle.collide_circle(player.circle):
            self.decay = True
            self.d_d_angle = STAR.DECAY_D_D_ANGLE
            return True
        return False
        
    def update_decay(self, player, delta):
        self.decay_time -= delta
        if self.decay_time < 0:
            return True
        self.d_angle += self.angle * self.d_d_angle * delta * 0.001
        self.angle += self.d_angle * delta * 0.001
        size = 1.0*self.decay_time/STAR.DECAY_TIME
        self.image = pygame.transform.rotozoom(self.base_image, self.angle, size)
        self.image_position = [self.circle.center[0] - self.image.get_width()/2, self.circle.center[1] - self.image.get_height()/2]
        self.image.set_alpha(size*255)
        return False
Ejemplo n.º 6
0
class Booster:
    def __init__(self, img_dict, type, obj, position_or_angle, force, radius = 30):
        if type == 'a': # count start_position
            start = sum(obj.circle.center, multiply(angle_to_vector(position_or_angle), obj.circle.radius + radius))
            angle = position_or_angle
            vector = angle_to_vector(angle)
        else:
            vector = inverse(perpendicular(normalise(obj.line.vector)))
            shift = multiply(obj.line.vector, -position_or_angle/100.0) # side shift
            start = sum(sum(obj.line.start, multiply(vector, PLATFORM.BORDER + radius + 3)), shift)
            angle = vector_to_angle(vector)
        self.circle = Circle(int(round(start[0])), int(round(start[1])), radius)
        self.force = force
        self.force_vector = multiply(vector, force)
        self.img_list = []
        for i in img_dict['geyser'][obj.colour]:
            self.img_list.append(pygame.transform.rotozoom(i, -angle,1.))
        self.frame = 0
        self.image = self.img_list[self.frame]
        self.frame_speed = BOOSTER.FRAME_SPEED + random.randint(-2,2)
        image_offset = (-self.img_list[0].get_width()/2, -self.img_list[0].get_height()/2)
        self.image_position = sum(self.circle.center, image_offset)
        
    def get_force(self, player):
        if self.circle.collide_circle(player.circle):
            return self.force_vector
        return [0,0]
        
    def update(self, delta):
        self.frame += delta * 0.001 * self.frame_speed
        if self.frame > BOOSTER.FRAMES:
            self.frame %= BOOSTER.FRAMES
        frame = int(round(self.frame))
        if frame >= BOOSTER.FRAMES or frame < 0:
            frame = frame % BOOSTER.FRAMES
        self.image = self.img_list[frame]
Ejemplo n.º 7
0
class Player:#(MovingObject):
    def __init__(self, position, planets, platforms, image_dict):
        #super(Player, self).__init__()
        self.image_dict = image_dict['player']

#        self.old_image = pygame.Surface([PLAYER.SIZE, PLAYER.SIZE])
#        self.old_image.fill((255, 100, 0))
#        self.old_image = self.old_image.convert_alpha()
#        self.basic_old_image = self.old_image.copy()
#        self.basic_image = self.image.convert_alpha()
        self.shift_constant = self.image_dict['body'][0].get_height()/2 - PLAYER.SIZE/2
        self.x = position[0]
        self.y = position[1]
        self.circle = Circle(self.x, self.y, PLAYER.SIZE/2)
        self.image_position = [0,0]
        self.last_center = position
        self.angle = 0 # up
        self.display_angle = self.angle
        self.angle_vector = [0,-1]
        self.display_angle_vector = [0,-1]
        self.gravity_angle = 0
        self.gravity_angle_vector = [0,-1]
        self.speed = [0,0] #x,y
        self.acc = [0,0]
        self.planets = planets
        self.platforms = platforms
        self.on_ground = False
        self.closest_planet = planets[0]
        self.move_frame = 0 # for moving with body
        self.eye_frame = 0 # moving with eyes
        self.movement = False
        self.jump_available = False
        self.ground_speed = 0
        self.was_on_ground = False
        self.move_eyes = False
        self.vacuum_time = 0
        
        #self.keep_keys = {'l':None, 'r':None, 'j':None}
        self.keep_keys = []
        self.update_image(1)
        
    def set_camera(self, cam):
        self.cam = cam    
    
    def respawn(self, position):
        self.circle.set_center(position[0], position[1])
        self.on_ground = False
        self.speed = [0,0]
        self.acc = [0,0]
        self.vacuum_time = 0
        
    def set_angle(self, angle):
        self.angle = angle
        self.angle_vector = angle_to_vector(angle)
        
    def set_angle_vector(self, vector):
        if vector != [0,0]:
            self.angle_vector = normalise(vector)
            self.angle = vector_to_angle(self.angle_vector)

    def set_gravity_angle(self, angle):
        self.gravity_angle = angle
        self.gravity_angle_vector = angle_to_vector(angle)
        
    def set_gravity_angle_vector(self, vector):
        if vector != [0,0]:
            self.gravity_angle_vector = normalise(vector)
            self.gravity_angle = vector_to_angle(vector)  
        
    def update(self, keys, delta, external):
        # move (use keys against PLAYER.CONTROLS)
        return self.move(keys, delta, external)

    def update_image(self, delta):
        diff = self.display_angle - self.angle
        while abs(diff) > 180:
            if diff > 0:
                diff -= 360
            else:
                diff += 360
        self.display_angle -= diff * PLAYER.TURN_RATIO * delta * 0.001
        if abs(diff) > delta * PLAYER.TURN_SPEED * 0.001:
            if diff > 0:
                self.display_angle -= delta * PLAYER.TURN_SPEED * 0.001
            else:
                self.display_angle += delta * PLAYER.TURN_SPEED * 0.001
        else:
            self.display_angle = self.angle
        movement = self.on_ground and self.movement
        if not movement and self.move_frame:
            c = 1
            if self.move_frame < PLAYER.MOVE_FRAMES/2:
                c = -1
            self.move_frame += delta * 0.001 * PLAYER.MOVE_FRAME_SPEED * c
            if self.move_frame < 0 or self.move_frame > PLAYER.MOVE_FRAMES:
                self.move_frame = 0
        if movement:
            self.move_frame += delta * 0.001 * PLAYER.MOVE_FRAME_SPEED
            if self.move_frame > PLAYER.MOVE_FRAMES:
                self.move_frame %= PLAYER.MOVE_FRAMES
        
        eye_frame = 0
        if self.move_eyes:
            self.eye_frame += delta * 0.001 * PLAYER.EYE_FRAME_SPEED
            if self.eye_frame > PLAYER.EYE_FRAMES:
                self.eye_frame = 0
                self.move_eyes = False
            eye_frame = int(round(self.eye_frame))
            if eye_frame >= PLAYER.EYE_FRAMES:
                eye_frame = eye_frame % PLAYER.EYE_FRAMES

        move_frame = int(round(self.move_frame))
        if move_frame >= PLAYER.MOVE_FRAMES:
            move_frame = move_frame % PLAYER.MOVE_FRAMES
        
        image = self.image_dict['eyes'][eye_frame].copy()
        image.blit(self.image_dict['body'][move_frame], (0,0))
        
        if diff:
            self.display_angle_vector = angle_to_vector(self.display_angle)
        self.image = pygame.transform.rotozoom(image, -self.display_angle,1.)
        self.image_position = subtract(sum(self.circle.center, multiply(self.display_angle_vector, self.shift_constant)), (self.image.get_width()/2, self.image.get_height()/2))
        
    def apply_keys(self, left, right, jump, delta):
        if self.on_ground and not self.was_on_ground:
            self.ground_speed = -tangent_size(self.speed, perpendicular(self.angle_vector))
            normal_speed = pythagory(self.speed[0], self.speed[1])
            if normal_speed > CAMERA.SHAKE_THRESHOLD:
                self.cam.shake((normal_speed - CAMERA.SHAKE_THRESHOLD)*CAMERA.SHAKE_RATIO)
            else:
                self.move_eyes = True
        if self.on_ground:
            self.was_on_ground = True
            self.movement = right or left
            if right:
                self.ground_speed += PLAYER.GROUND_ACCELERATION*delta*0.001
            if left:
                self.ground_speed -= PLAYER.GROUND_ACCELERATION*delta*0.001
            if self.ground_speed > PLAYER.MAX_GROUND_SPEED:
                self.ground_speed = PLAYER.MAX_GROUND_SPEED
            if self.ground_speed < -PLAYER.MAX_GROUND_SPEED:
                self.ground_speed = -PLAYER.MAX_GROUND_SPEED 
            if not right and not left:
                if self.ground_speed > 0:
                    self.ground_speed -= PLAYER.BRAKE_ACC*delta*0.001
                    if self.ground_speed < 0:
                        self.ground_speed = 0
                else:
                    self.ground_speed += PLAYER.BRAKE_ACC*delta*0.001
                    if self.ground_speed > 0:
                        self.ground_speed = 0
            self.speed[0] = (self.ground_speed) * -self.angle_vector[1]
            self.speed[1] = (self.ground_speed) * self.angle_vector[0]
            if jump and self.jump_available:
                self.jump_available = False
                self.speed[0] += PLAYER.JUMP_ACC * (self.angle_vector[0] + self.gravity_angle_vector[0]) /2
                self.speed[1] += PLAYER.JUMP_ACC * (self.angle_vector[1] + self.gravity_angle_vector[1]) /2
        else:
            self.was_on_ground = False
            if pythagory(self.speed[0], self.speed[1]) > PLAYER.MAX_AIR_SPEED:
                limiter = True
            else:
                limiter = False
            pom = 0
            if self.speed != [0,0]:
                pom = tangent_size([-self.gravity_angle_vector[1], self.gravity_angle_vector[0]], self.speed)
            if right and (not limiter or pom < 0):
                self.acc[0] += PLAYER.AIR_ACCELERATION * -self.gravity_angle_vector[1]
                self.acc[1] += PLAYER.AIR_ACCELERATION * self.gravity_angle_vector[0]
            if left and (not limiter or pom > 0):
                self.acc[0] += PLAYER.AIR_ACCELERATION * self.gravity_angle_vector[1]
                self.acc[1] += PLAYER.AIR_ACCELERATION * -self.gravity_angle_vector[0]
        if not jump:
            self.jump_available = True               
        
    
    def move(self, keys, delta, external):
        # calculate gravity
        strongest = None
        maximum = -1
        self.acc = [0.0, 0.0]
        for p in self.planets:
            gx, gy = gravity_circle_circle(self.circle, p.circle, p.mass, p.gravity_radius)
            if not self.on_ground:
                self.acc[0] += gx
                self.acc[1] += gy
            x,y = subtract(self.circle.center, p.circle.center)
            priority = pythagory(gx, gy) / pythagory(x,y) 
            if priority > maximum:
                maximum = priority
                self.closest_planet = p
        # check keys and add player acceleration
        left, right, jump = self.check_keys(keys)
        # determine speed based on given commands
        self.apply_keys(left, right, jump, delta)
        if self.on_ground:
            gx, gy = gravity_circle_circle(self.circle, self.closest_planet.circle, self.closest_planet.mass, self.closest_planet.gravity_radius)
            self.acc[0] += gx
            self.acc[1] += gy
        if self.acc == [0,0]:
            self.vacuum_time += delta
            if self.vacuum_time > PLAYER.VACUUM_TIME:
                return 'dead'
        self.speed[0] += self.acc[0]*delta*0.001
        self.speed[1] += self.acc[1]*delta*0.001 
        if external != [0,0]:
            diff = subtract(external, self.speed)
            self.speed = sum(self.speed, multiply(diff, PLAYER.BOOST_RATIO))       
        #move circle
        self.circle.move((self.speed[0]*delta*0.001, self.speed[1]*delta*0.001))
        
        if self.closest_planet:
            vector = gravity_circle_circle(self.circle, self.closest_planet.circle)
            self.set_gravity_angle_vector(inverse(vector))
            
        self.on_ground = False
        # checkout collision with surfaces
        self.colliding_planets = []
        for p in self.planets:
            if self.circle.collide_circle(p.circle):
                self.colliding_planets.append(p)

        self.colliding_platforms = []
        self.above_platform = None
        min_distance = 0
        for p in self.platforms:
            if self.circle.collide_line(p.line, PLATFORM.BORDER):
                self.colliding_platforms.append(p)
            is_above = collide_line_line(self.circle.center, self.closest_planet.circle.center, p.line.start, p.line.end)
            if is_above and self.above_platform == None:
                point = collide_line_line_extended(self.circle.center, self.closest_planet.circle.center, p.line.start, p.line.end)
                min_distance = pythagory(self.circle.center[0] - point[0], self.circle.center[1] - point[1])
                self.above_platform = p
            elif is_above:
                point = collide_line_line_extended(self.circle.center, self.closest_planet.circle.center, p.line.start, p.line.end)
                distance = pythagory(self.circle.center[0] - point[0], self.circle.center[1] - point[1])
                if min_distance > distance:
                    self.above_platform = p
                    min_distance = distance
        
        # workout angle
        
        if self.above_platform != None:
            vector = perpendicular(self.above_platform.line.vector)
            angle = vector_to_angle(vector)
            if 90 < abs(angle - self.gravity_angle) < 270:
                vector = inverse(vector)
            self.set_angle_vector(vector)
        else:
            self.set_angle(self.gravity_angle)
        
        self.handle_collision()

        self.update_image(delta)
        self.last_center = multiply(self.circle.center,1)
        
    def handle_collision(self):
        if len(self.colliding_platforms) == 1:
            self.handle_single_platform_collision(self.colliding_platforms[0])
        elif len(self.colliding_planets) == 1:
            planet = self.colliding_planets[0]
            vector = self.circle.collide_circle_extended(planet.circle)
            self.circle.move(vector)
            self.set_angle_vector(vector)
            self.on_ground = True           
        elif len(self.colliding_platforms) > 1:
            self.handle_multiple_collisions()
            
    def handle_single_platform_collision(self, platform):
        vector = self.circle.collide_line_extended(platform.line, PLATFORM.BORDER)
        if vector == [0,0]:
            return
        self.circle.move(vector)
        angle = vector_to_angle(vector)
        if PLATFORM.MIN_ANGLE < abs(angle - self.gravity_angle) < PLATFORM.MAX_ANGLE:
            self.on_ground = False
            if 90 < abs(angle - self.gravity_angle) < 270:
                x, y = tangent(vector, platform.line.vector)
                self.speed = [x,y]
        else:
            self.on_ground = True
        self.set_angle_vector(vector)
        self.ground_speed = -tangent_size(self.speed, perpendicular(self.angle_vector))
            
    def handle_multiple_collisions(self):
        platforms = []
        if len(self.colliding_platforms) == 0:
            return
        for platform in self.colliding_platforms:
            distance = 1
            if not self.circle.collide_line(platform.line, PLATFORM.BORDER):
                return
            vector = self.circle.collide_line_extended(platform.line, PLATFORM.BORDER)
            perpendicular_v = perpendicular(vector)
            if tangent_size(perpendicular_v, self.speed) < 0:
                perpendicular_v = inverse(perpendicular_v)
            pom = sum(self.circle.center, vector)
            point = collide_line_line_extended(self.last_center, self.circle.center, pom, subtract(pom, perpendicular_v))
            if point == self.last_center:
                distance = 0
            elif self.circle.center != self.last_center:
                distance = pythagory(point[0] - self.last_center[0], point[1] - self.last_center[1])/pythagory(self.circle.center[0] - self.last_center[0], self.circle.center[1] - self.last_center[1])
            platforms.append([platform, distance, point, perpendicular_v])
        platforms = sorted(platforms, key=lambda student: student[1])
        min_ground_speed = None
        for platform in platforms:
            self.handle_single_platform_collision(platform[0])
            if min_ground_speed == None:
                min_ground_speed = self.ground_speed
            elif abs(min_ground_speed) > abs(self.ground_speed):
                min_ground_speed = self.ground_speed
        self.ground_speed = min_ground_speed
            
    def check_keys(self, keys): # u,l,d,r
        d = {'u': keys[PLAYER.CONTROLS[0]],
             'l': keys[PLAYER.CONTROLS[1]],
             'd': keys[PLAYER.CONTROLS[2]],
             'r': keys[PLAYER.CONTROLS[3]]}
        left = right = jump = False
        jump_affected = False
        
        if self.keep_keys:
            if d[self.keep_keys[0]]:
                if self.keep_keys[2] == 'l':
                    left = True
                else:
                    right = True
                d[self.keep_keys[0]] = False
                
                # jump
                if d[self.keep_keys[1]]:
                    jump = True
                    d[self.keep_keys[1]] = False
            else:
                self.keep_keys = None

        if 315 <= self.angle or self.angle < 45 or 1:
            if d['u']:
                jump = True
            if d['l']:
                left = True
                self.keep_keys = ['l', 'u', 'l'] # the key to hold, jump key to remember and use, direction of movement
            if d['r']:
                right = True
                self.keep_keys = ['r', 'u', 'r']
            if d['d'] and not (right or left or jump):
                if 315 <= self.angle:
                    left = True
                    self.keep_keys = ['d', 'l', 'l']
                else:
                    right = True
                    self.keep_keys = ['d', 'r', 'r']
                
        elif 45 <= self.angle < 135:
            if d['r']:
                jump = True
            if d['u']:
                left = True
                self.keep_keys = ['u', 'r', 'l']
            if d['d']:
                right = True
                self.keep_keys = ['d', 'r', 'r']
            if d['l'] and not (right or left or jump):
                if self.angle < 90:
                    left = True
                    self.keep_keys = ['l', 'u', 'l']
                else:
                    right = True
                    self.keep_keys = ['l', 'd', 'r']
        elif 135 <= self.angle < 225:
            if d['d']:
                jump = True
            if d['r']:
                left = True
                self.keep_keys = ['r', 'd', 'l']
            if d['l']:
                right = True
                self.keep_keys = ['l', 'd', 'r']
            if d['u'] and not (right or left or jump):
                if self.angle < 180:
                    left = True
                    self.keep_keys = ['u', 'r', 'l']
                else:
                    right = True
                    self.keep_keys = ['u', 'l', 'r']
        elif 225 <= self.angle < 315:
            if d['l']:
                jump = True
            if d['d']:
                left = True
                self.keep_keys = ['d', 'l', 'l']
            if d['u']:
                right = True
                self.keep_keys = ['u', 'l', 'r']
            if d['r'] and not (right or left or jump):
                if self.angle < 270:
                    left = True
                    self.keep_keys = ['r', 'd', 'l']
                else:
                    right = True
                    self.keep_keys = ['r', 'u', 'r']
        return left, right, jump
Ejemplo n.º 8
0
class Player:  #(MovingObject):
    def __init__(self, position, planets, platforms, image_dict):
        #super(Player, self).__init__()
        self.image_dict = image_dict['player']

        #        self.old_image = pygame.Surface([PLAYER.SIZE, PLAYER.SIZE])
        #        self.old_image.fill((255, 100, 0))
        #        self.old_image = self.old_image.convert_alpha()
        #        self.basic_old_image = self.old_image.copy()
        #        self.basic_image = self.image.convert_alpha()
        self.shift_constant = self.image_dict['body'][0].get_height(
        ) / 2 - PLAYER.SIZE / 2
        self.x = position[0]
        self.y = position[1]
        self.circle = Circle(self.x, self.y, PLAYER.SIZE / 2)
        self.image_position = [0, 0]
        self.last_center = position
        self.angle = 0  # up
        self.display_angle = self.angle
        self.angle_vector = [0, -1]
        self.display_angle_vector = [0, -1]
        self.gravity_angle = 0
        self.gravity_angle_vector = [0, -1]
        self.speed = [0, 0]  #x,y
        self.acc = [0, 0]
        self.planets = planets
        self.platforms = platforms
        self.on_ground = False
        self.closest_planet = planets[0]
        self.move_frame = 0  # for moving with body
        self.eye_frame = 0  # moving with eyes
        self.movement = False
        self.jump_available = False
        self.ground_speed = 0
        self.was_on_ground = False
        self.move_eyes = False
        self.vacuum_time = 0

        #self.keep_keys = {'l':None, 'r':None, 'j':None}
        self.keep_keys = []
        self.update_image(1)

    def set_camera(self, cam):
        self.cam = cam

    def respawn(self, position):
        self.circle.set_center(position[0], position[1])
        self.on_ground = False
        self.speed = [0, 0]
        self.acc = [0, 0]
        self.vacuum_time = 0

    def set_angle(self, angle):
        self.angle = angle
        self.angle_vector = angle_to_vector(angle)

    def set_angle_vector(self, vector):
        if vector != [0, 0]:
            self.angle_vector = normalise(vector)
            self.angle = vector_to_angle(self.angle_vector)

    def set_gravity_angle(self, angle):
        self.gravity_angle = angle
        self.gravity_angle_vector = angle_to_vector(angle)

    def set_gravity_angle_vector(self, vector):
        if vector != [0, 0]:
            self.gravity_angle_vector = normalise(vector)
            self.gravity_angle = vector_to_angle(vector)

    def update(self, keys, delta, external):
        # move (use keys against PLAYER.CONTROLS)
        return self.move(keys, delta, external)

    def update_image(self, delta):
        diff = self.display_angle - self.angle
        while abs(diff) > 180:
            if diff > 0:
                diff -= 360
            else:
                diff += 360
        self.display_angle -= diff * PLAYER.TURN_RATIO * delta * 0.001
        if abs(diff) > delta * PLAYER.TURN_SPEED * 0.001:
            if diff > 0:
                self.display_angle -= delta * PLAYER.TURN_SPEED * 0.001
            else:
                self.display_angle += delta * PLAYER.TURN_SPEED * 0.001
        else:
            self.display_angle = self.angle
        movement = self.on_ground and self.movement
        if not movement and self.move_frame:
            c = 1
            if self.move_frame < PLAYER.MOVE_FRAMES / 2:
                c = -1
            self.move_frame += delta * 0.001 * PLAYER.MOVE_FRAME_SPEED * c
            if self.move_frame < 0 or self.move_frame > PLAYER.MOVE_FRAMES:
                self.move_frame = 0
        if movement:
            self.move_frame += delta * 0.001 * PLAYER.MOVE_FRAME_SPEED
            if self.move_frame > PLAYER.MOVE_FRAMES:
                self.move_frame %= PLAYER.MOVE_FRAMES

        eye_frame = 0
        if self.move_eyes:
            self.eye_frame += delta * 0.001 * PLAYER.EYE_FRAME_SPEED
            if self.eye_frame > PLAYER.EYE_FRAMES:
                self.eye_frame = 0
                self.move_eyes = False
            eye_frame = int(round(self.eye_frame))
            if eye_frame >= PLAYER.EYE_FRAMES:
                eye_frame = eye_frame % PLAYER.EYE_FRAMES

        move_frame = int(round(self.move_frame))
        if move_frame >= PLAYER.MOVE_FRAMES:
            move_frame = move_frame % PLAYER.MOVE_FRAMES

        image = self.image_dict['eyes'][eye_frame].copy()
        image.blit(self.image_dict['body'][move_frame], (0, 0))

        if diff:
            self.display_angle_vector = angle_to_vector(self.display_angle)
        self.image = pygame.transform.rotozoom(image, -self.display_angle, 1.)
        self.image_position = subtract(
            sum(self.circle.center,
                multiply(self.display_angle_vector, self.shift_constant)),
            (self.image.get_width() / 2, self.image.get_height() / 2))

    def apply_keys(self, left, right, jump, delta):
        if self.on_ground and not self.was_on_ground:
            self.ground_speed = -tangent_size(self.speed,
                                              perpendicular(self.angle_vector))
            normal_speed = pythagory(self.speed[0], self.speed[1])
            if normal_speed > CAMERA.SHAKE_THRESHOLD:
                self.cam.shake((normal_speed - CAMERA.SHAKE_THRESHOLD) *
                               CAMERA.SHAKE_RATIO)
            else:
                self.move_eyes = True
        if self.on_ground:
            self.was_on_ground = True
            self.movement = right or left
            if right:
                self.ground_speed += PLAYER.GROUND_ACCELERATION * delta * 0.001
            if left:
                self.ground_speed -= PLAYER.GROUND_ACCELERATION * delta * 0.001
            if self.ground_speed > PLAYER.MAX_GROUND_SPEED:
                self.ground_speed = PLAYER.MAX_GROUND_SPEED
            if self.ground_speed < -PLAYER.MAX_GROUND_SPEED:
                self.ground_speed = -PLAYER.MAX_GROUND_SPEED
            if not right and not left:
                if self.ground_speed > 0:
                    self.ground_speed -= PLAYER.BRAKE_ACC * delta * 0.001
                    if self.ground_speed < 0:
                        self.ground_speed = 0
                else:
                    self.ground_speed += PLAYER.BRAKE_ACC * delta * 0.001
                    if self.ground_speed > 0:
                        self.ground_speed = 0
            self.speed[0] = (self.ground_speed) * -self.angle_vector[1]
            self.speed[1] = (self.ground_speed) * self.angle_vector[0]
            if jump and self.jump_available:
                self.jump_available = False
                self.speed[0] += PLAYER.JUMP_ACC * (
                    self.angle_vector[0] + self.gravity_angle_vector[0]) / 2
                self.speed[1] += PLAYER.JUMP_ACC * (
                    self.angle_vector[1] + self.gravity_angle_vector[1]) / 2
        else:
            self.was_on_ground = False
            if pythagory(self.speed[0], self.speed[1]) > PLAYER.MAX_AIR_SPEED:
                limiter = True
            else:
                limiter = False
            pom = 0
            if self.speed != [0, 0]:
                pom = tangent_size([
                    -self.gravity_angle_vector[1], self.gravity_angle_vector[0]
                ], self.speed)
            if right and (not limiter or pom < 0):
                self.acc[
                    0] += PLAYER.AIR_ACCELERATION * -self.gravity_angle_vector[
                        1]
                self.acc[
                    1] += PLAYER.AIR_ACCELERATION * self.gravity_angle_vector[0]
            if left and (not limiter or pom > 0):
                self.acc[
                    0] += PLAYER.AIR_ACCELERATION * self.gravity_angle_vector[1]
                self.acc[
                    1] += PLAYER.AIR_ACCELERATION * -self.gravity_angle_vector[
                        0]
        if not jump:
            self.jump_available = True

    def move(self, keys, delta, external):
        # calculate gravity
        strongest = None
        maximum = -1
        self.acc = [0.0, 0.0]
        for p in self.planets:
            gx, gy = gravity_circle_circle(self.circle, p.circle, p.mass,
                                           p.gravity_radius)
            if not self.on_ground:
                self.acc[0] += gx
                self.acc[1] += gy
            x, y = subtract(self.circle.center, p.circle.center)
            priority = pythagory(gx, gy) / pythagory(x, y)
            if priority > maximum:
                maximum = priority
                self.closest_planet = p
        # check keys and add player acceleration
        left, right, jump = self.check_keys(keys)
        # determine speed based on given commands
        self.apply_keys(left, right, jump, delta)
        if self.on_ground:
            gx, gy = gravity_circle_circle(self.circle,
                                           self.closest_planet.circle,
                                           self.closest_planet.mass,
                                           self.closest_planet.gravity_radius)
            self.acc[0] += gx
            self.acc[1] += gy
        if self.acc == [0, 0]:
            self.vacuum_time += delta
            if self.vacuum_time > PLAYER.VACUUM_TIME:
                return 'dead'
        self.speed[0] += self.acc[0] * delta * 0.001
        self.speed[1] += self.acc[1] * delta * 0.001
        if external != [0, 0]:
            diff = subtract(external, self.speed)
            self.speed = sum(self.speed, multiply(diff, PLAYER.BOOST_RATIO))
        #move circle
        self.circle.move(
            (self.speed[0] * delta * 0.001, self.speed[1] * delta * 0.001))

        if self.closest_planet:
            vector = gravity_circle_circle(self.circle,
                                           self.closest_planet.circle)
            self.set_gravity_angle_vector(inverse(vector))

        self.on_ground = False
        # checkout collision with surfaces
        self.colliding_planets = []
        for p in self.planets:
            if self.circle.collide_circle(p.circle):
                self.colliding_planets.append(p)

        self.colliding_platforms = []
        self.above_platform = None
        min_distance = 0
        for p in self.platforms:
            if self.circle.collide_line(p.line, PLATFORM.BORDER):
                self.colliding_platforms.append(p)
            is_above = collide_line_line(self.circle.center,
                                         self.closest_planet.circle.center,
                                         p.line.start, p.line.end)
            if is_above and self.above_platform == None:
                point = collide_line_line_extended(
                    self.circle.center, self.closest_planet.circle.center,
                    p.line.start, p.line.end)
                min_distance = pythagory(self.circle.center[0] - point[0],
                                         self.circle.center[1] - point[1])
                self.above_platform = p
            elif is_above:
                point = collide_line_line_extended(
                    self.circle.center, self.closest_planet.circle.center,
                    p.line.start, p.line.end)
                distance = pythagory(self.circle.center[0] - point[0],
                                     self.circle.center[1] - point[1])
                if min_distance > distance:
                    self.above_platform = p
                    min_distance = distance

        # workout angle

        if self.above_platform != None:
            vector = perpendicular(self.above_platform.line.vector)
            angle = vector_to_angle(vector)
            if 90 < abs(angle - self.gravity_angle) < 270:
                vector = inverse(vector)
            self.set_angle_vector(vector)
        else:
            self.set_angle(self.gravity_angle)

        self.handle_collision()

        self.update_image(delta)
        self.last_center = multiply(self.circle.center, 1)

    def handle_collision(self):
        if len(self.colliding_platforms) == 1:
            self.handle_single_platform_collision(self.colliding_platforms[0])
        elif len(self.colliding_planets) == 1:
            planet = self.colliding_planets[0]
            vector = self.circle.collide_circle_extended(planet.circle)
            self.circle.move(vector)
            self.set_angle_vector(vector)
            self.on_ground = True
        elif len(self.colliding_platforms) > 1:
            self.handle_multiple_collisions()

    def handle_single_platform_collision(self, platform):
        vector = self.circle.collide_line_extended(platform.line,
                                                   PLATFORM.BORDER)
        if vector == [0, 0]:
            return
        self.circle.move(vector)
        angle = vector_to_angle(vector)
        if PLATFORM.MIN_ANGLE < abs(angle -
                                    self.gravity_angle) < PLATFORM.MAX_ANGLE:
            self.on_ground = False
            if 90 < abs(angle - self.gravity_angle) < 270:
                x, y = tangent(vector, platform.line.vector)
                self.speed = [x, y]
        else:
            self.on_ground = True
        self.set_angle_vector(vector)
        self.ground_speed = -tangent_size(self.speed,
                                          perpendicular(self.angle_vector))

    def handle_multiple_collisions(self):
        platforms = []
        if len(self.colliding_platforms) == 0:
            return
        for platform in self.colliding_platforms:
            distance = 1
            if not self.circle.collide_line(platform.line, PLATFORM.BORDER):
                return
            vector = self.circle.collide_line_extended(platform.line,
                                                       PLATFORM.BORDER)
            perpendicular_v = perpendicular(vector)
            if tangent_size(perpendicular_v, self.speed) < 0:
                perpendicular_v = inverse(perpendicular_v)
            pom = sum(self.circle.center, vector)
            point = collide_line_line_extended(self.last_center,
                                               self.circle.center, pom,
                                               subtract(pom, perpendicular_v))
            if point == self.last_center:
                distance = 0
            elif self.circle.center != self.last_center:
                distance = pythagory(
                    point[0] - self.last_center[0],
                    point[1] - self.last_center[1]) / pythagory(
                        self.circle.center[0] - self.last_center[0],
                        self.circle.center[1] - self.last_center[1])
            platforms.append([platform, distance, point, perpendicular_v])
        platforms = sorted(platforms, key=lambda student: student[1])
        min_ground_speed = None
        for platform in platforms:
            self.handle_single_platform_collision(platform[0])
            if min_ground_speed == None:
                min_ground_speed = self.ground_speed
            elif abs(min_ground_speed) > abs(self.ground_speed):
                min_ground_speed = self.ground_speed
        self.ground_speed = min_ground_speed

    def check_keys(self, keys):  # u,l,d,r
        d = {
            'u': keys[PLAYER.CONTROLS[0]],
            'l': keys[PLAYER.CONTROLS[1]],
            'd': keys[PLAYER.CONTROLS[2]],
            'r': keys[PLAYER.CONTROLS[3]]
        }
        left = right = jump = False
        jump_affected = False

        if self.keep_keys:
            if d[self.keep_keys[0]]:
                if self.keep_keys[2] == 'l':
                    left = True
                else:
                    right = True
                d[self.keep_keys[0]] = False

                # jump
                if d[self.keep_keys[1]]:
                    jump = True
                    d[self.keep_keys[1]] = False
            else:
                self.keep_keys = None

        if 315 <= self.angle or self.angle < 45 or 1:
            if d['u']:
                jump = True
            if d['l']:
                left = True
                self.keep_keys = [
                    'l', 'u', 'l'
                ]  # the key to hold, jump key to remember and use, direction of movement
            if d['r']:
                right = True
                self.keep_keys = ['r', 'u', 'r']
            if d['d'] and not (right or left or jump):
                if 315 <= self.angle:
                    left = True
                    self.keep_keys = ['d', 'l', 'l']
                else:
                    right = True
                    self.keep_keys = ['d', 'r', 'r']

        elif 45 <= self.angle < 135:
            if d['r']:
                jump = True
            if d['u']:
                left = True
                self.keep_keys = ['u', 'r', 'l']
            if d['d']:
                right = True
                self.keep_keys = ['d', 'r', 'r']
            if d['l'] and not (right or left or jump):
                if self.angle < 90:
                    left = True
                    self.keep_keys = ['l', 'u', 'l']
                else:
                    right = True
                    self.keep_keys = ['l', 'd', 'r']
        elif 135 <= self.angle < 225:
            if d['d']:
                jump = True
            if d['r']:
                left = True
                self.keep_keys = ['r', 'd', 'l']
            if d['l']:
                right = True
                self.keep_keys = ['l', 'd', 'r']
            if d['u'] and not (right or left or jump):
                if self.angle < 180:
                    left = True
                    self.keep_keys = ['u', 'r', 'l']
                else:
                    right = True
                    self.keep_keys = ['u', 'l', 'r']
        elif 225 <= self.angle < 315:
            if d['l']:
                jump = True
            if d['d']:
                left = True
                self.keep_keys = ['d', 'l', 'l']
            if d['u']:
                right = True
                self.keep_keys = ['u', 'l', 'r']
            if d['r'] and not (right or left or jump):
                if self.angle < 270:
                    left = True
                    self.keep_keys = ['r', 'd', 'l']
                else:
                    right = True
                    self.keep_keys = ['r', 'u', 'r']
        return left, right, jump