我正在使用PyGame创建随机生成的地图。但是,我遇到了一个问题,即如果用户从地图的左上角滚动离开并更改了显示的PyGame曲面,则会发生问题。
问题是,PyGame仍将它们从表面的左上角开始,然后允许它们滚动到表面的边缘,因为跟踪该列表的列表camera_pos
现在具有值不正确。
所有表面都具有相同的尺寸,我想制作成这样,以便用户在更改显示的表面时位于同一位置。但是,我不确定pygame切换表面时如何设置用户视图的位置。
如何将用户视图的位置切换回切换表面时的位置?
我在下面做了一个MCV示例,希望对您有所帮助。它不显示地图,而只是在纯色周围绘制边框。抱歉,请多久。我不确定如何使其更短。
在此示例中,使用箭头键进行滚动。您可以在键盘上按r,g或b以显示不同颜色的表面。
import pygame
import numpy as np
import sys
def scroll_y(display_surface, offset):
"""
Handles vertical scrolling.
:param display_surface: A pyGame surface object.
:param offset: The speed of the scroll
"""
width, height = display_surface.get_size()
map_copy = display_surface.copy()
display_surface.blit(map_copy, (0, offset))
# handle scrolling down
if offset < 0:
display_surface.blit(map_copy,
(0, height + offset),
(0, 0, width, -offset))
# handle scrolling up
else:
display_surface.blit(map_copy,
(0, 0),
(0, height - offset, width, offset))
def scroll_x(display_surface, offset):
"""
Handles horizontal scrolling.
:param display_surface: A pyGame surface object.
:param offset: The speed of the scroll
"""
width, height = display_surface.get_size()
map_copy = display_surface.copy()
display_surface.blit(map_copy, (offset, 0))
# handle scrolling right
if offset < 0:
display_surface.blit(map_copy,
(width + offset, 0),
(0, 0, -offset, height))
# handle scrolling left
else:
display_surface.blit(map_copy,
(0, 0),
(width - offset, 0, offset, height))
def main():
"""
This function displays the three surfaces.
Press r to show the red surface (which is displayed by default).
Press g to show the green surface.
Press b to show the blue surface.
"""
pygame.init()
window = pygame.display.set_mode((1600, 900))
red_surface = pygame.Surface([3200, 1800]).convert(window)
green_surface = pygame.Surface([3200, 1800]).convert(window)
blue_surface = pygame.Surface([3200, 1800]).convert(window)
red_surface.fill((255, 145, 145))
green_surface.fill((145, 255, 145))
blue_surface.fill((145, 145, 255))
# draw thick black lines on surface borders
pygame.draw.rect(red_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
pygame.draw.rect(green_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
pygame.draw.rect(blue_surface, (0, 0, 0), (0, 0, 3200, 1800), 40)
display_surface = red_surface.copy()
camera_pos = np.array([0, 0])
while True: # <-- the pyGame loop
event = pygame.event.poll()
pressed = pygame.key.get_pressed()
# handle closing the window
if event.type == pygame.QUIT:
break
window.blit(display_surface, (0, 0))
# handle switching display modes
if pressed[pygame.K_g]:
display_surface = green_surface
elif pressed[pygame.K_b]:
display_surface = blue_surface
elif pressed[pygame.K_r]:
display_surface = red_surface
# handle scrolling, make sure you can't scroll past the borders
if pressed[pygame.K_UP] and camera_pos[1] > 0:
scroll_y(display_surface, 5)
camera_pos[1] -= 5
elif pressed[pygame.K_DOWN] and camera_pos[1] < (1800 / 2):
scroll_y(display_surface, -5)
camera_pos[1] += 5
elif pressed[pygame.K_LEFT] and camera_pos[0] > 0:
scroll_x(display_surface, 5)
camera_pos[0] -= 5
elif pressed[pygame.K_RIGHT] and camera_pos[0] < (3200 / 2):
scroll_x(display_surface, -5)
camera_pos[0] += 5
# updates what the window displays
pygame.display.update()
pygame.quit()
sys.exit(0)
if __name__ == "__main__":
# runs the pyGame loop
main()
答案 0 :(得分:2)
我认为这是一个相当优雅的解决方案,不需要您拥有两个滚动功能scroll_x()
和scroll_y()
。因为不使用它们是如此之快,所以主循环正在检测到与多次按下相同的滚动键,因此必须添加pygame.time.Clock
才能将帧速率降低到合理的水平。
此版本并没有像您的代码那样通过那些滚动功能来滚动显示表面本身,而是仅更新当前的“相机”位置,然后将当前display_surface
的相应区域涂抹到窗口中。改性。通过确保其x和y分量保持在某些边界极限常数(MINX
,MINY
和MAXX
,MAXY
)中来约束摄像机的位置,这些常数是根据值计算得出的其他一些先前定义的常量。
使用符号常量而不是将代码中的文字值硬编码在代码中的多个位置被认为是一种很好的编程习惯,因为这样做使更改它们变得更加容易,因为这样做只需要将源代码更改一次即可。
import pygame
import sys
def main():
"""
This function displays the three surfaces.
Press r to show the red surface (which is displayed by default).
Press g to show the green surface.
Press b to show the blue surface.
"""
FPS = 60 # Frames per second
SURF_WIDTH, SURF_HEIGHT = 3200, 1800
WIN_WIDTH, WIN_HEIGHT = 1600, 900
DX, DY = 5, 5 # Scroll amounts.
MINX, MAXX = DX, SURF_WIDTH - WIN_WIDTH + DX - 1
MINY, MAXY = DY, SURF_HEIGHT - WIN_HEIGHT + DY - 1
pygame.init()
pygame.font.init()
fonts = pygame.font.get_fonts()
clock = pygame.time.Clock()
window = pygame.display.set_mode((WIN_WIDTH, WIN_HEIGHT))
red_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
green_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
blue_surface = pygame.Surface([SURF_WIDTH, SURF_HEIGHT]).convert(window)
red_surface.fill((255, 145, 145))
green_surface.fill((145, 255, 145))
blue_surface.fill((145, 145, 255))
# Draw thick black lines on surface borders
pygame.draw.rect(red_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
pygame.draw.rect(green_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
pygame.draw.rect(blue_surface, (0, 0, 0), (0, 0, SURF_WIDTH, SURF_HEIGHT), 40)
# Draw label on each of the surfaces for testing. (ADDED)
font = pygame.font.SysFont(None, 35)
rtext = font.render('red surface', True, (255, 0, 0))
textpos = rtext.get_rect(centerx=300, centery=200) # Reused.
red_surface.blit(rtext, textpos)
rtext = font.render('green surface', True, (0, 192, 0))
green_surface.blit(rtext, textpos)
rtext = font.render('blue surface', True, (0, 0, 255))
blue_surface.blit(rtext, textpos)
display_surface = red_surface
camera_pos = pygame.math.Vector2(0, 0)
update_surface = True
while True: # Game loop
if update_surface:
window.blit(display_surface, (0, 0), (camera_pos[0], camera_pos[1],
WIN_WIDTH, WIN_HEIGHT))
update_surface = False
event = pygame.event.poll()
pressed = pygame.key.get_pressed()
# Close window?
if event.type == pygame.QUIT or pressed[pygame.K_ESCAPE]:
break
# Switch display surface?
if pressed[pygame.K_g]:
display_surface = green_surface
update_surface = True
elif pressed[pygame.K_b]:
display_surface = blue_surface
update_surface = True
elif pressed[pygame.K_r]:
display_surface = red_surface
update_surface = True
# Constrain scrolling to within borders
if pressed[pygame.K_LEFT] and camera_pos[0] >= MINX:
camera_pos[0] -= DX
update_surface = True
elif pressed[pygame.K_RIGHT] and camera_pos[0] <= MAXX:
camera_pos[0] += DX
update_surface = True
elif pressed[pygame.K_UP] and camera_pos[1] >= MINY:
camera_pos[1] -= DY
update_surface = True
elif pressed[pygame.K_DOWN] and camera_pos[1] <= MAXY:
camera_pos[1] += DY
update_surface = True
# updates what the window displays
pygame.display.update()
clock.tick(FPS)
pygame.quit()
sys.exit(0)
if __name__ == "__main__":
main() # runs the pyGame loop