试图在 Pygame 简单的 2D 平台游戏中使屏幕中心成为玩家 [英] Trying to make screen center to player in Pygame simple 2D Platformer

查看:31
本文介绍了试图在 Pygame 简单的 2D 平台游戏中使屏幕中心成为玩家的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am creating a simple 2D platformer in Pygame. In this project I have been trying to use classes much more for good practice. My current problem is that I am trying to make the screen center on the player, however I cannot find a way to do this with the way my code is currently set up.

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

In addition, I plan to later add a way to make the screen follow the player with a small amount of lag, following faster as it gets further away. However, making the camera center on the player is my main concern.

当玩家向右移动时,我拥有所有的PlatformRects";以相同的速度向左移动.我尝试了不同的速度,将播放器设置为零速度并仅移动PlatformRects"几乎可以工作(播放器"类的更新"函数中的代码中的相关注释).我也曾尝试制作PlatformRects"移动取决于玩家的位置,但我也无法让它发挥作用.

When the player is moving right, I have all the "PlatformRects" move left at the same speed. I have tried different speeds, setting the player to zero speed and just moving the "PlatformRects" almost works (related comment in code in the "update" func of the "Player" class). I had also tried making the "PlatformRects" movement depend on the position of the player, but I couldn't get this to work either.

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

I would appreciate any help. Here's my code (I trimmed out a lot of irrelevant code, like animating and such):

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,self.players,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,x_pos,y_pos,size_x,size_y,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,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,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
            [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0],
            [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
            [0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
            [0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
            [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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,50,50,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, 50, 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)

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

I will of course clarify anything about my code if it is not clear.

推荐答案

你应该像这样移动相机:

You should move the camera like this:

# 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)

  • 摄像机跟随玩家,并将自身放置在屏幕中央,使玩家位于屏幕中央
  • 每个精灵的位置永远不会改变,这是一个非常糟糕的主意,不断改变精灵的位置.
  • 根据相机在屏幕上绘制每个精灵
  • 为了减少延迟,您应该只在每个精灵可见时才显示它:

    To reduce lag, you should display each sprite only if it is visible:

    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
    


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


    Here is a screenshot of a moving background in a game I made, using the same method:

    在这里我更平稳地移动相机.基本上我用这个方法:

    Here I move the camera more smoothly. Basically I use this method:

    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.

    And I change speed according to the FPS.

    这篇关于试图在 Pygame 简单的 2D 平台游戏中使屏幕中心成为玩家的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆