微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

试图在 Pygame 简单的 2D 平台游戏中使屏幕中心成为玩家

如何解决试图在 Pygame 简单的 2D 平台游戏中使屏幕中心成为玩家

我正在 Pygame 中创建一个简单的 2D 平台游戏。在这个项目中,我一直在尝试更多地使用类以获得良好的实践。我目前的问题是我试图让屏幕在播放器上居中,但是我找不到一种方法来使用我的代码当前设置的方式来做到这一点。

此外,我计划稍后添加一种方法,使屏幕以少量延迟跟随玩家,随着距离越远,跟随速度越快。然而,让相机以玩家为中心是我的主要关注点。

当玩家向右移动时,我让所有“PlatformRects”以相同的速度向左移动。我尝试了不同的速度,将播放器设置为零速度,然后移动“PlatformRects”几乎可以工作(“播放器”类的“更新”功能中的代码中的相关注释)。我也曾尝试让“PlatformRects”运动取决于玩家的位置,但我也无法让它发挥作用。

我将不胜感激。这是我的代码(我删除了很多不相关的代码,例如动画等):

import pygame,sys,random
#---Classes----------------------------------------#
class PlatformRect(pygame.sprite.Sprite):
    def __init__(self,x_pos,y_pos,size_x,size_y,path,players):
        super().__init__()
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.size_x = size_x
        self.size_y = size_y
        self.players = players
        self.can_jump1 = None

        if path == "null":
            self.image = pygame.Surface((self.size_x,self.size_y))
            self.rect = self.image.get_rect(topleft = (self.x_pos,self.y_pos))
        else:
            self.image = pygame.transform.scale(pygame.image.load(path).convert_alpha(),(size_x,size_y))
            self.rect = self.image.get_rect(topleft = (self.x_pos,self.y_pos))

    def collision_check(self):
        if pygame.sprite.spritecollide(self,self.players,False): 
            collision_paddle = pygame.sprite.spritecollide(self,False)[0].rect
            if player.movement_y > 0 and abs(self.rect.top - collision_paddle.bottom) < 10: #load of checks to ensure the correct side is being collided 
                collision_paddle.bottom = self.rect.top 
                player.movement_y = 0
                self.can_jump1 = True
            elif player.movement_y < 0 and abs(self.rect.bottom - collision_paddle.top) < 10 and not abs(self.rect.right - collision_paddle.left) < 10 and not abs(self.rect.left - collision_paddle.right) < 10:
                collision_paddle.top = self.rect.bottom
                player.movement_y *= -0.2
                print("moving bottom")
            elif player.movement_x < 0 and abs(self.rect.right - collision_paddle.left) < 10 and not abs(self.rect.bottom - collision_paddle.top) < 10:
                collision_paddle.left = self.rect.right
                print("moving left")
            elif player.movement_x > 0 and abs(self.rect.left - collision_paddle.right) < 10 and not abs(self.rect.bottom - collision_paddle.top) < 10:
                collision_paddle.right = self.rect.left
                print("moving right")
        else:
            self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom  

    def can_jump_check(self):
        return self.can_jump1

    def update(self):
        self.collision_check()
        self.rect.centerx -= player.movement_x #trying to get rects to move the same distance as the player,if player moves 2 pixels right,rect moves 2 pixels left?
        self.rect.centery -= 0


class Player(pygame.sprite.Sprite):
    def __init__(self,speed_x,acceleration_y): 
        super().__init__()
        self.x_pos = x_pos
        self.y_pos = y_pos
        self.size_x = size_x
        self.size_y = size_y
        self.speed_x = speed_x
        self.shift_pressed = False
        self.acceleration_y = acceleration_y
        self.movement_x = 0 
        self.movement_y = 0
        
        self.image = pygame.Surface((self.size_x,self.size_y))
        self.image.fill("red")
        self.rect = self.image.get_rect(center = (self.x_pos,self.y_pos))

    def screen_constrain(self): 
        if self.rect.bottom >= sresy:
            self.rect.bottom = sresy

    def update(self):
        if abs(self.movement_y) <= 8: 
            self.movement_y += GraviTY
        self.rect.centery += self.movement_y
        if self.shift_pressed == False:
            self.rect.centerx += self.movement_x #if set to 0,scrolling kindof works,although camera still scrolls even if player is stuck on block
        elif self.shift_pressed == True: 
            self.rect.centerx += 2*self.movement_x
        self.screen_constrain()

class GameManager:
    def __init__(self,player_group,platform_group):
        self.player_group = player_group
        self.platform_group = platform_group
        self.can_jump = True

    def run_game(self):
        #---drawing---#
        self.player_group.draw(screen)
        self.platform_group.draw(screen)

        #---updating---#
        self.player_group.update()
        self.platform_group.update()

    def game_checking(self):
        #---checking---#
        self.can_jump = any(p.can_jump_check() for p in self.platform_group)  
        return self.can_jump
        
#---Setup------------------------------------------#
#---constants-----#
global GraviTY
GraviTY = 0.25

#---Gamevariables-----#
can_jump = True
shift_pressed = False
music_playing = False

#---colour---#
bg_colour = (50,50,50)
white_colour = (255,255,255)
black_colour = (0,0)

#---res---#
resx = 900 
resy = 700
resx_moved = resx - 50
resy_moved = resy - 50
sresx = 850 #base surface size,to be scaled up to resx_moved and resy_moved
sresy = 650

#---game map---# 
game_map = [[0,1,0],[0,1],[1,1]]

#---start window-----#
pygame.init()
clock = pygame.time.Clock()

screendisplay = pygame.display.set_mode((resx,resy))
screendisplay.fill(bg_colour)
pygame.display.set_caption("PlatformerGame") 

screen = pygame.Surface((sresx,sresy))
screen.fill(white_colour)

#---startgame-----#
player = Player(425,325,2,30)
player_group = pygame.sprite.GroupSingle() 
player_group.add(player) 

platform_list = []
y_gm = 0
for row in game_map:
    x_gm = 0
    for tile in row:
        if tile == 1:
            platform_list.append(PlatformRect(x_gm * 50,y_gm * 50,"null",player_group)) #sets platform at given positions and size
        x_gm += 1
    y_gm += 1
platform_group = pygame.sprite.Group() 
platform_group.add(platform_list) 

game_manager = GameManager(player_group,platform_group)

#---Loop--------------------------------------------#
while True:
    #---events-----#
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: #emergency
                pygame.quit()
                sys.exit()

            if event.key == pygame.K_SPACE: 
                if can_jump == True:
                    player.movement_y = 0
                    player.movement_y -= player.acceleration_y * GraviTY 

            if event.key == pygame.K_LSHIFT: #sprinting
                player.shift_pressed = True

            if event.key == pygame.K_a: 
                player.movement_x -= player.speed_x

            if event.key == pygame.K_d: 
                player.movement_x += player.speed_x

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_SPACE: 
                if player.movement_y < 0: 
                    player.movement_y = 0

            if event.key == pygame.K_a: 
                player.movement_x += player.speed_x

            if event.key == pygame.K_d: 
                player.movement_x -= player.speed_x

            if event.key == pygame.K_LSHIFT: 
                player.shift_pressed = False

    #---background---#
    surf = pygame.transform.scale(screen,(resx_moved,resy_moved)) #changes resolution
    screendisplay.blit(surf,(25,25))
    screen.fill(white_colour) 

    #---running---#
    game_manager.run_game()
    if not game_manager.game_checking() == True and player.rect.bottom < sresy: #checking if can_jump is true
        can_jump = False
    else:
        can_jump = True

    #---updating-----#
    pygame.display.update()
    clock.tick(120)

如果我的代码不清楚,我当然会澄清。

解决方法

你应该像这样移动相机:

# at the beginning: set camera
camera = pygame.math.Vector2((0,0))

# in the main loop: adjust the camera position to center the player
camera.x = player.x_pos - resx / 2
camera.y = player.y_pos - resy / 2

# in each sprite class: move according to the camera instead of changing the sprite position
pos_on_the_screen = (self.x_pos - camera.x,self.y_pos - camera.y)
  • 摄像机跟随玩家,并将自身放置在屏幕中央,使玩家位于屏幕中央
  • 每个精灵的位置永远不会改变,这是一个非常糟糕的主意,不断改变精灵的位置。
  • 根据相机在屏幕上绘制每个精灵

为了减少延迟,您应该只在每个精灵可见时才显示它:

screen_rect = pygame.Rect((0,0),(resx,resy))
sprite_rect = pygame.Rect((self.x_pos - camera.x,self.y_pos - camera.y),sprite_image.get_size())
if screen_rect.colliderect(sprite_rect):
    # render if visible

这是我制作的游戏中移动背景的屏幕截图,使用相同的方法:

在这里我更平稳地移动相机。基本上我使用这种方法:

speed = 1
distance_x = player.x_pos - camera.x
distance_y = player.y_pos - camera.y
camera.x = (camera.x * speed + distance_x) / (speed + 1)
camera.y = (camera.y * speed + distance_y) / (speed + 1)

我根据 FPS 更改 speed

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。