python-3.x 如何使视差滚动正常工作的相机停止在边缘pygame

falq053o  于 2023-03-31  发布在  Python
关注(0)|答案(1)|浏览(135)

假设我们在pygame中制作了一个游戏,在这个游戏中,我们有“滚动”对象,它基本上是将相机滚动框在其中,停止在边缘。当玩家离开一个滚动并进入一个新的滚动时,相机从一个滚动移动到另一个滚动。在这种情况下,为了实现视差效果,我们需要将相机滚动的量除以一个值。然而,如果我们只做这个,当我们移动到一个新的“滚动”时,背景将出现相对于它在第一个“滚动”中滚动的量移动了不正确的量,如何解决这个问题?这里是我的相机代码,和滚动代码,

import pygame
from pygame.locals import *

class scroll_handler(list):
    def __init__(self):
        self.primary_scroll = None
        self.append(scroll_obj((50+1)*16,(2)*16,65*16,30*16))
        self.append(scroll_obj((51+65)*16,(2)*16,65*16,30*16))

    def update(self,player):
        for i in self:
            if i.entity_in_scroll(player):
                self.primary_scroll = i

class scroll_obj(pygame.Rect):
    def __init__(self,x,y,sx,sy,enable_backgrounds = True):
        super().__init__((x,y),(sx,sy))
        self.enable_backgrounds = enable_backgrounds

    def entity_in_scroll(self,entity):
        return self.contains(entity)

class camera(object):
    def __init__(self, camera_func, widthy, heighty):
        self.state = pygame.Rect((16,16),(widthy,heighty))
        self.camera_func = camera_func
        self.scroll = scroll_obj(16,16,widthy,heighty)

    def update_scroll(self, scroll):
        self.state = pygame.Rect(scroll.x, scroll.y, scroll.width, scroll.height)

    def apply(self, target, state = 0, parallax = False):
        if not parallax:
            return target.move(self.state.topleft)
        if parallax:
            return target.move(state.topleft)

    def update(self, target, parallax_x = 1, parallax_y = 1):
        self.update_scroll(self.scroll)
        self.state = self.camera_func( self.state, target, parallax_x, parallax_y)
    
def complex_camera(camera, target_rect, parallax_x=1, parallax_y=1):
    l, t, _, _ = target_rect
    _, _, w, h = camera
    l, t, _, _ = -l+(320), -t+(180), w, h
    
    l = min(-camera.x, l)                                       # stop scrolling at the left edge
    l = max(-(camera.x + camera.width-640), l)                  # stop scrolling at the right edge
    l = round(l/(parallax_x),2)                         # apply parallax in x direction
        
    t = max(-(camera.y + camera.height-360), t)                # stop scrolling at the bottom   
    t = min(-camera.y, t)                                       # stop scrolling at the top
    t = round(t/(parallax_y),2)                         # apply parallax in y direction
    return pygame.Rect(l, t, w, h)

这是我的代码为背景和应用视差效果给他们

import pygame
class background(pygame.Rect):
    def __init__(self,x,y,image):
        super().__init__(x*16,y*16,1024,512)
        self.image = image
        self.CAX = self.x
        self.CAY = self.y
        self.rect = pygame.Rect(self.CAX,self.CAY,1024,512) # an additional rect object used elsewhere in another code file, ignore this
        
    def apply_camera(self, state, GAME):
        cam = GAME.camera.apply(self, state, True)
        self.CAX = cam[0]
        self.CAY = cam[1]
        self.rect.x = self.CAX
        self.rect.y = self.CAY
        
        
class backgrounds(dict):
    def __init__(self,GAME):
        self.GAME = GAME
        

        BH = self.GAME.background_handler
        self["background_0"] = [background(0,0,BH[0])]
        self["background_1"] = [background(0,1,BH[3])]
        self["background_2"] = [background(0,2,BH[2])]
        self["background_3"] = [background(0,3,BH[1])]

    def get_background(self):
        self.background_0 = []
        self.background_1 = []
        self.background_2 = []
        self.background_3 = []
        
        original = self.GAME.camera.state
        half = pygame.Rect(int(original[0]/2), int(original[1]/2), self.GAME.camera.state.width, self.GAME.camera.state.height)
        quater = pygame.Rect(int(original[0]/4), int(original[1]/4), self.GAME.camera.state.width, self.GAME.camera.state.height)
        eighth = pygame.Rect(int(original[0]/8), int(original[1]/8), self.GAME.camera.state.width, self.GAME.camera.state.height)
        fortieth = pygame.Rect(int(original[0]/40), int(original[1]/40), self.GAME.camera.state.width, self.GAME.camera.state.height)

        for i in self["background_0"]:
            
                i.apply_camera(fortieth,self.GAME)
                self.background_0.append([(i.CAX,i.CAY),(i.image)])
        
        for i in self["background_1"]:
            
                i.apply_camera(eighth,self.GAME)
                self.background_1.append([(i.CAX,i.CAY),(i.image)])
    
        for i in self["background_2"]:

                i.apply_camera(quater,self.GAME)
                self.background_2.append([(i.CAX,i.CAY),(i.image)])

        for i in self["background_3"]:
                i.apply_camera(half,self.GAME)
                self.background_3.append([(i.CAX,i.CAY),(i.image)])
                
        return (self.background_0), (self.background_1), (self.background_2), (self.background_3)

我需要做些什么改变,以便在进入一个新的卷轴时,背景将在适当的位置,而不是明显地向右移动?
注:相机和滚动代码是在单独的模块,不要担心这一点,如果它似乎很奇怪

njthzxwz

njthzxwz1#

通过移动背景图像并在显示器上以偏移量多次绘制背景图像来实现滚动背景:

def draw_background(surf, bg_image, bg_x, bg_y):
    surf.blit(bg_image, (bg_x - surf.get_width(), bg_y))
    surf.blit(bg_image, (bg_x, bg_y))

对于背景视差效果,您需要几个背景图层,它们必须以不同的速度移动。后面的图层必须比前面的图层移动得慢。例如:

bg_layer_1_x = (bg_layer_1_x - move_x) % 600
bg_layer_2_x = (bg_layer_2_x - move_x*0.75) % 600
bg_layer_3_x = (bg_layer_3_x - move_x*0.5) % 600

最小示例

import pygame

pygame.init()
window = pygame.display.set_mode((600, 400))
clock = pygame.time.Clock()

tree1_image = pygame.Surface((100, 100), pygame.SRCALPHA)
pygame.draw.rect(tree1_image, (64, 32, 0), (45, 75, 10, 25))
pygame.draw.polygon(tree1_image, (16, 64, 0), [(50, 0), (70, 35), (65, 35), (90, 75), (10, 75), (35, 35), (30, 35)])
tree2_image = pygame.Surface((100, 100), pygame.SRCALPHA)
pygame.draw.rect(tree2_image, (128, 64, 16), (45, 75, 10, 25))
pygame.draw.polygon(tree2_image, (64, 128, 0), [(50, 0), (70, 35), (65, 35), (90, 75), (10, 75), (35, 35), (30, 35)])
tree2_image = pygame.transform.smoothscale(tree2_image, (75, 75))
tree3_image = pygame.Surface((100, 100), pygame.SRCALPHA)
pygame.draw.rect(tree3_image, (164, 128, 96), (45, 75, 10, 25))
pygame.draw.polygon(tree3_image, (128, 164, 64), [(50, 0), (70, 35), (65, 35), (90, 75), (10, 75), (35, 35), (30, 35)])
tree3_image = pygame.transform.smoothscale(tree3_image, (50, 50))

bg_layer_1_image = pygame.Surface((600, 100), pygame.SRCALPHA)
for i in range(6):
    bg_layer_1_image.blit(tree1_image, (i*100, 0))
bg_layer_2_image = pygame.Surface((600, 75), pygame.SRCALPHA)
for i in range(8):
    bg_layer_2_image.blit(tree2_image, (i*75, 0))  
bg_layer_3_image = pygame.Surface((600, 50), pygame.SRCALPHA)
for i in range(12):
    bg_layer_3_image.blit(tree3_image, (i*50, 0))    
bg_layer_1_x = 0
bg_layer_2_x = 0
bg_layer_3_x = 0
move_x = 1

def draw_background(surf, bg_image, bg_x, bg_y):
    surf.blit(bg_image, (bg_x - surf.get_width(), bg_y))
    surf.blit(bg_image, (bg_x, bg_y))

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 

    bg_layer_1_x = (bg_layer_1_x - move_x) % 600
    bg_layer_2_x = (bg_layer_2_x - move_x*0.75) % 600
    bg_layer_3_x = (bg_layer_3_x - move_x*0.5) % 600

    window.fill((192, 192, 255))
    pygame.draw.rect(window, (64, 128, 64), (0, 250, 600, 150))
    pygame.draw.rect(window, (128, 164, 192), (0, 170, 600, 80))
    draw_background(window, bg_layer_3_image, bg_layer_3_x, 120)
    draw_background(window, bg_layer_2_image, bg_layer_2_x, 135)
    draw_background(window, bg_layer_1_image, bg_layer_1_x, 150)
    pygame.display.flip()

pygame.quit()
exit()

另请参见PyGameExamplesAndAnswers - Background

相关问题