Pygame平台滚动错误



因此,在使用引擎时,我想在其中添加一个敌人,听起来很简单。即使我的敌人在游戏中,并没有违反物理定律(在大多数情况下),但很奇怪的是,我给了他0对运动的控制权,但是当我继续前进时,敌人继续跟随球员精灵。p>现在玩了一段时间,我注意到玩家移动时的敌人闩锁在滚动视图框上,因此,当玩家击中Down Viewbox时,敌人会稍微跳跃。

我目前并不试图给他任何AI,敌人只需要与玩家一起产卵,跌落到平台并在玩家移开时站立。

整个代码:

from pygame import *
import time
import pygame
# from colours import *
# from textObjects import small, medium, large
###########################################################################
#   COLOURS AND TEXT OBJECTS                                              #
###########################################################################
black = pygame.Color(0, 0, 0)
grey = pygame.Color(128, 128, 128)
white = pygame.Color(255, 255, 255)
red = pygame.Color(255, 0, 0)
green = pygame.Color(0, 255, 0)
light_blue = pygame.Color(201, 242, 255)
blue = pygame.Color(0, 0, 255)
green_yellow = pygame.Color(212, 255, 0)
yellow = pygame.Color(255, 251, 0)
orange = pygame.Color(255, 166, 0)
orange_red = pygame.Color(255, 85, 0)
pygame.font.init()
small = pygame.font.SysFont(None, 25)
medium = pygame.font.SysFont(None, 50)
large = pygame.font.SysFont(None, 80)
###########################################################################
#   CLASSES                                                               #
###########################################################################

class Player(pygame.sprite.Sprite):
# Initialise function
    def __init__(self, color=blue, width=32, height=48, health=100):
        # I assume super() inherits everything from the block class
        super(Player, self).__init__()
        # Set the image to a Surface of size width and height
        self.image = pygame.Surface((width, height))
        # Fill the image with the default color of blue
        self.image.fill(color)
        # Use the Surface of the image to get the rectangular co-ordinates
        self.set_properties()
        # Create speed for x and y
        self.speed_x = 0
        self.speed_y = 0
        # Create health
        self.health = 100
        self.level = None
    def set_properties(self):
        self.rect = self.image.get_rect()
        # Create an x and y origin position (Centered the mouse on the sprite)
        self.origin_x = self.rect.centerx
        self.origin_y = self.rect.centery
        self.speed = 5
        # Create total travel distance to check the player's position on the map
        self.travel_distance_x = 0
        self.travel_distance_y = 0
    # Function to easily set the position of any block object on the center
    def set_position(self, x, y):
        self.rect.x = x - self.origin_x
        self.rect.y = y - self.origin_y
    # Function made to print the position on the map
    def print_position(self):
        self.travel_distance_x += self.speed_x
        self.travel_distance_y += self.speed_y
        # print self.travel_distance_x, self.travel_distance_y
    def set_level(self, level):
        self.level = level
        self.set_position(level.player_start_x, level.player_start_y)
    def set_image(self, filename=None):
        if filename != None:
            self.image = pygame.image.load(filename).convert()
            self.set_properties()
    def update(self, collidable=pygame.sprite.Group(), event=True):
        self.experience_gravity()
        self.event = True
        self.rect.x += self.speed_x
        collision_list = pygame.sprite.spritecollide(self, collidable, False)
        for collided_object in collision_list:
            # Right direction
            if self.speed_x > 0:
                self.rect.right = collided_object.rect.left
            # Left direction
            elif self.speed_x < 0:
                self.rect.left = collided_object.rect.right
        self.rect.y += self.speed_y
        collision_list = pygame.sprite.spritecollide(self, collidable, False)
        for collided_object in collision_list:
            # Down direction
            if self.speed_y > 0:
                self.rect.bottom = collided_object.rect.top
                self.speed_y = 0
            # Up direction
            elif self.speed_y < 0:
                self.rect.top = collided_object.rect.bottom
                self.speed_y = 0
        if not event == None:
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    self.speed_x = -self.speed
                    # self.change_speed(-self.speed, 0)
                if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    self.speed_x = self.speed
                    # self.change_speed(self.speed, 0)
                if event.key == pygame.K_UP or event.key == pygame.K_w:
                    if len(collision_list) >= 1:
                        self.speed_y = -(self.speed) * 2
                        # self.change_speed(0, -self.speed * 2)
                if event.key == pygame.K_DOWN:
                    # self.change_speed(0, self.speed)
                    pass
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT or event.key == pygame.K_a:
                    if self.speed_x < 0:
                        self.speed_x = 0
                if event.key == pygame.K_RIGHT or event.key == pygame.K_d:
                    if self.speed_x > 0:
                        self.speed_x = 0
    def experience_gravity(self, gravity=0.35):
        if self.speed_y == 0:
            self.speed_y = 1
        else:
            self.speed_y += gravity

class Enemy(pygame.sprite.Sprite):
# Initialise function
    def __init__(self, color=red, width=32, height=48, health=100):
        # I assume super() inherits everything from the block class
        super(Enemy, self).__init__()
        # Set the image to a Surface of size width and height
        self.image = pygame.Surface((width, height))
        # Fill the image with the default color of blue
        self.image.fill(color)
        # Use the Surface of the image to get the rectangular co-ordinates
        self.set_properties()
        # Create speed for x and y
        self.speed_x = 0
        self.speed_y = 0
        # Create health
        self.health = 100
        self.level = None
    def set_properties(self):
        self.rect = self.image.get_rect()
        # Create an x and y origin position (Centered the mouse on the sprite)
        self.origin_x = self.rect.centerx
        self.origin_y = self.rect.centery
        self.speed = 5
        # Create total travel distance to check the player's position on the map
        self.travel_distance_x = 0
        self.travel_distance_y = 0
    # Function to easily set the position of any block object on the center
    def set_position(self, x, y):
        self.rect.x = x - self.origin_x
        self.rect.y = y - self.origin_y
    # Function made to print the position on the map
    def print_position(self):
        self.travel_distance_x += self.speed_x
        self.travel_distance_y += self.speed_y
        print self.travel_distance_x, self.travel_distance_y
    def set_level(self, level):
        self.level = level
        self.set_position(level.enemy_start_x, level.enemy_start_y)
    def set_image(self, filename=None):
        if filename != None:
            self.image = pygame.image.load(filename).convert()
            self.set_properties()
    def update(self, collidable=pygame.sprite.Group(), event=True):
        self.experience_gravity()
        self.event = True
        self.rect.x += self.speed_x
        collision_list = pygame.sprite.spritecollide(self, collidable, False)
        for collided_object in collision_list:
            # Right direction
            if self.speed_x > 0:
                self.rect.right = collided_object.rect.left
            # Left direction
            elif self.speed_x < 0:
                self.rect.left = collided_object.rect.right
        self.rect.y += self.speed_y
        collision_list = pygame.sprite.spritecollide(self, collidable, False)
        for collided_object in collision_list:
            # Down direction
            if self.speed_y > 0:
                self.rect.bottom = collided_object.rect.top
                self.speed_y = 0
            # Up direction
            elif self.speed_y < 0:
                self.rect.top = collided_object.rect.bottom
                self.speed_y = 0
        if not event == None:
            pass
    def experience_gravity(self, gravity=0.35):
        if self.speed_y == 0:
            self.speed_y = 1
        else:
            self.speed_y += gravity

class Block(pygame.sprite.Sprite):
    def __init__(self, x, y, width, height, color=blue):
        # I assume super() inherits everything from the block class
        super(Block, self).__init__()
        # Set the image to a Surface of size width and height
        self.image = pygame.Surface((width, height))
        # Fill the image with the default color of blue
        self.image.fill(color)
        # Get rectangle object of the block
        self.rect = self.image.get_rect()
        # Assign x and y co-ordinates of the block
        self.rect.x = x
        self.rect.y = y
    def experience_gravity(self, gravity=0.35):
        if self.speed_y == 0:
            self.speed_y = 1
        else:
            self.speed_y += gravity
class Level(object):
    def __init__(self, player_object):
        self.object_list = pygame.sprite.Group()
        self.player_object = player_object
        self.player_start = self.player_start_x, self.player_start_y = 80, 150
        self.enemy_start = self.enemy_start_x, self.enemy_start_y = 300, 200
        self.world_shift_x = 0
        self.world_shift_y = 0
        self.left_viewbox = screen_width / 2 - screen_width / 8
        self.right_viewbox = screen_width / 2 + screen_width / 8
        self.up_viewbox = screen_height / 3
        self.down_viewbox = screen_height / 2 # + screen_height / 12
    def update(self):
        self.object_list.update()
    def draw(self, screen):
        screen.fill(white)
        self.object_list.draw(screen)
    def shift_world(self, shift_x, shift_y):
        self.world_shift_x += shift_x
        self.world_shift_y += shift_y
        for each_object in self.object_list:
            each_object.rect.x += shift_x
            each_object.rect.y += shift_y

    def scroll(self):
        if self.player_object.rect.x <= self.left_viewbox:
            view_difference = self.left_viewbox - self.player_object.rect.x
            self.player_object.rect.x = self.left_viewbox
            self.shift_world(view_difference, 0)
        if self.player_object.rect.x >= self.right_viewbox:
            view_difference = self.right_viewbox - self.player_object.rect.x
            self.player_object.rect.x = self.right_viewbox
            self.shift_world(view_difference, 0)
        if self.player_object.rect.y <= self.up_viewbox:
            view_difference = self.up_viewbox - self.player_object.rect.y
            self.player_object.rect.y = self.up_viewbox
            self.shift_world(0, view_difference)
        if self.player_object.rect.y >= self.down_viewbox:
            view_difference = self.down_viewbox - self.player_object.rect.y
            self.player_object.rect.y = self.down_viewbox
            self.shift_world(0, view_difference)

class Level_01(Level):
    def __init__(self, player_object):
        super(Level_01, self).__init__(player_object)
        level = [
            #[x, y, width, height, color]
            [0, 0, 38, 899, black],
            [7, 874, 1592, 25, black],
            [1564, 0, 35, 887, black],
            [0, 0, 1593, 40, black],
            [330, 731, 282, 31, black],
            [898, 678, 307, 28, black],
            [603, 528, 280, 28, black],
            [1279, 616, 301, 32, black],
            [1046, 468, 194, 35, black],
            [208, 348, 306, 28, black],
            [708, 294, 335, 24, black],
            [22, 487, 170, 26, black]
        ]
        for block in level:
            block = Block(block[0], block[1], block[2], block[3], block[4])
            self.object_list.add(block)

class Camera(object):
    def __init__(self, camera_function, width, height):
        self.camera_function = camera_function
        self.state = Rect(0, 0, width, height)
    def apply(self, target):
        return target.rect.move(self.state.topleft)
    def update(self, target):
        self.state = self.camera_function(self.state, target.rect)

###########################################################################
#   TEXT AND UI FUNCTIONS                                                 #
###########################################################################

def set_message(text):
    global message, previous_message
    message = font.render(text, True, black, white)
    previous_message = message

def text_objects(text, color, size):
    if size == 'small':
        textSurface = small.render(text, True, color)
    if size == 'medium':
        textSurface = medium.render(text, True, color)
    if size == 'large':
        textSurface = large.render(text, True, color)
    return textSurface, textSurface.get_rect()

def display_message(text, color, y_displacement=0, size='small'):
    textSurface, textRectangle = text_objects(text, color, size)
    textRectangle.center = (screen_width / 2), (screen_height / 2) + y_displacement
    screen.blit(textSurface, textRectangle)

def health_bar(player_health):
    if player_health > 85:
        health_color = green
    elif player_health > 70:
        health_color = green_yellow
    elif player_health > 55:
        health_color = yellow
    elif player_health > 40:
        health_color = orange
    elif player_health > 25:
        health_color = orange_red
    else:
        health_color = red
    if player_health < 0:
        player_health = 0
    pygame.draw.rect(screen, health_color, (50, screen_height / 20, player_health, 25))
###########################################################################
#   INITIALISATION, SCREEN PROPERTIES, FPS                                #
###########################################################################
# Initialise pygame module
pygame.init()
# Initialise pygame font
pygame.font.init()
# Defining the screen size
screen_size = screen_width, screen_height = 800, 600
# Setting the display and getting the Surface object
screen = pygame.display.set_mode(screen_size)
# Getting the Clock object
clock = pygame.time.Clock()
# Setting a title to the window
pygame.display.set_caption("TODO make title")
# Defining variable for FPS
fps_limit = 60
# Clear the screen
screen.fill(white)
# Setting the FPS at which the game will run
clock.tick(fps_limit)
###########################################################################
#   MAIN LOOP, PAUSE AND DEATH FUNCTIONS                                  #
###########################################################################

def death():
    death = True
    while death:
        display_message("YOU DIED", red, size='large')
        pygame.display.update()
        time.sleep(1)
        death = False
        over = True
        game_exit = True

def pause():
    paused = True
    display_message("Paused", black)
    pygame.display.update()
    while paused:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_p:
                    paused = False
                elif event.key == pygame.K_q:
                    pygame.quit()
                    quit()

def game_intro():
    intro = True
    while intro:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:
                    run=True
                    intro=False
                if event.key == pygame.K_ESCAPE:
                    pygame.quit()
                    quit()
        screen.fill(light_blue)
        display_message("Physics Engine v0.1", black, - screen_height / 5, 'large' )
        display_message("pre-alpha stage", grey, - screen_height / 10, 'small')
        display_message("Press ENTER to start or ESCAPE to close", black, screen_height / 8, 'small')
        pygame.display.update()

def main_loop():
    # Group all the currently active objects
    active_object_list = pygame.sprite.Group()
    # Set variable player to the Player() class
    player = Player()
    # Set variable enemy to the Enemy() class
    enemy = Enemy()
    # Add player to the active object list
    active_object_list.add(player, enemy)
    # Make a list for the levels and append Level_01 to that list with player as the handler (being the character in focus)
    level_list = []
    level_list.append(Level_01(player))
    current_level_number = 0
    current_level = level_list[current_level_number]
    # Set the starting co-ordinates
    player.set_level(current_level)
    enemy.set_level(current_level)
    # run = True
    over = False
    game_exit = False
    while not game_exit:
        if over == True:
            while over:
                for event in pygame.event.get():
                    if event.type == pygame.QUIT:
                        game_exit = True
                        over = False
                    if event.type == pygame.KEYDOWN:
                        if event.key == K_RETURN:
                            main_loop()
                        if event.key == K_ESCAPE:
                            pygame.quit()
                            quit()
                screen.fill(light_blue)
                display_message("Do you want to start over?", black, -screen_height / 8, size='large')
                display_message("Press RETURN to start over or ESCAPE to quit", black, screen_height / 8)
                pygame.display.update()
        current_events = pygame.event.get()
        if current_events:
            for event in current_events:
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
                    run = False
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_p:
                        pause()
                    if event.key == pygame.K_k:
                        player.health -= 5
                # Update functions
                player.update(current_level.object_list, event)
                enemy.update(current_level.object_list, event)
                current_level.update()
        else:
            player.update(current_level.object_list, None)
            enemy.update(current_level.object_list, None)
            current_level.update()
        # Logic testing
        current_level.scroll()
        if player.health <= 0:
            player.health = 0
            over = True
            death()
        if player.travel_distance_y > 900:
            player.health = 0
            over = True
            death()
        # Draw everything
        current_level.draw(screen)
        active_object_list.draw(screen)
        health_bar(player.health)
        # Delay fps
        clock.tick(fps_limit)
        # Update screen
        pygame.display.update()
game_intro()
main_loop()

位于级别类中的视图框以检查玩家是否击中框的方式工作,如果是,世界会在玩家周围移动,而不是播放器在其中移动。

滚动功能

def shift_world(self, shift_x, shift_y):
        self.world_shift_x += shift_x
        self.world_shift_y += shift_y
        for each_object in self.object_list:
            each_object.rect.x += shift_x
            each_object.rect.y += shift_y

    def scroll(self):
        if self.player_object.rect.x <= self.left_viewbox:
            view_difference = self.left_viewbox - self.player_object.rect.x
            self.player_object.rect.x = self.left_viewbox
            self.shift_world(view_difference, 0)
        if self.player_object.rect.x >= self.right_viewbox:
            view_difference = self.right_viewbox - self.player_object.rect.x
            self.player_object.rect.x = self.right_viewbox
            self.shift_world(view_difference, 0)
        if self.player_object.rect.y <= self.up_viewbox:
            view_difference = self.up_viewbox - self.player_object.rect.y
            self.player_object.rect.y = self.up_viewbox
            self.shift_world(0, view_difference)
        if self.player_object.rect.y >= self.down_viewbox:
            view_difference = self.down_viewbox - self.player_object.rect.y
            self.player_object.rect.y = self.down_viewbox
            self.shift_world(0, view_difference)

要注意的一件事是,级别和级别_01将" plary_object"作为输入,我认为当player.update()()和eney.update()(在主循环中调用player.update()时,它被称为输入。

主循环

if current_events:
            for event in current_events:
                if event.type == pygame.QUIT:
                    pygame.quit()
                    quit()
                    run = False
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_p:
                        pause()
                    if event.key == pygame.K_k:
                        player.health -= 5
                # Update functions
                player.update(current_level.object_list, event)
                enemy.update(current_level.object_list, event)
                current_level.update()
        else:
            player.update(current_level.object_list, None)
            enemy.update(current_level.object_list, None)
            current_level.update()

因此,尽管玩家被用作第477行中的级别的处理程序:

level_list.append(Level_01(player))

我认为敌人受视线框的影响,因为他也被视为滚动功能中的" player_object"。

如果有人可以给我一些有关我做错的事情的提示,谢谢。

问题在您的scroll中,或者是您的shift_world函数。您将self.object_list中的每个对象移动。对于Level01,此列表仅包含块对象。然后,在scroll中,您将每个块和播放器移动,而不是敌人。这意味着敌人的石将停留在它的位置,并且不会像世界那样转移。因此,它似乎在移动,因为它相对于世界的位置发生了变化。实际上,它保持在画布上的同一位置。

当球员跳跃时,敌人一旦世界转移,敌人就在空中,然后重力将他拉回平台。当玩家向右移动时,敌人似乎之所以跟随,是因为世界向左移动,而敌人不会随之移动。

将敌人添加到您的object_list中,并且应该按预期工作。

最新更新