放大和缩小 PyGame window,所有对象仍然在原位
Zooming in and out of a PyGame window with all objects still in place
我遇到了 PyGame 无法解决的问题。所以:
我的想法是我有一张可以放大 in/out 的地图。放大效果很好。但是缩小显示图片的其余部分已被删除,现在只存在以前在 window 上可见的图像部分。
这是我的代码:
import pygame
from pygame.locals import *
import os
class App:
def __init__(self):
self.running = True
self.size = (800,600)
#create window
self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
#create map
currentdir = os.path.dirname(os.path.realpath(__file__))
imagedir = currentdir+'/images/europe.png'
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect()
self.mapsurface = pygame.Surface(self.size)
self.mapsurface.blit(pygame.transform.scale(self.map,(self.size)),(0,0))
self.window.blit(self.mapsurface,(0,0))
self.scale = 1
#create window
pygame.display.flip()
def on_init(self):
self.country = Country()
def on_cleanup(self):
pygame.quit()
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.window.blit(pygame.transform.scale(self.map,(event.dict['size'])),(0,0))
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4:
zoom = 2
wnd_w,wnd_h = self.window.get_size()
zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
zoom_area = pygame.Rect(0,0, *zoom_size)
pos_x,pos_y = pygame.mouse.get_pos()
zoom_area.center = (pos_x, pos_y)
zoom_surf = pygame.Surface(zoom_area.size)
zoom_surf.blit(self.window, (0, 0), zoom_area)
zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
self.window.blit(zoom_surf, (0, 0))
elif event.button == 5:
zoom = 0.5
wnd_w,wnd_h = self.window.get_size()
zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
zoom_area = pygame.Rect(0,0,*zoom_size)
pos_x,pos_y = pygame.mouse.get_pos()
zoom_area.center = (pos_x, pos_y)
zoom_surf = pygame.Surface(zoom_area.size)
zoom_surf.blit(self.window, (0, 0), zoom_area)
zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
self.window.blit(zoom_surf, (0, 0))
pygame.display.flip()
pygame.display.update()
def on_execute(self):
while self.running == True:
for event in pygame.event.get():
self.check_event(event)
self.on_cleanup()
class Country(App):
def __init__(self):
super().__init__()
start = App()
start.on_init()
start.on_execute()
这是我的问题的截图:
到目前为止一切顺利:
放大效果很好:
缩小会导致:
缩放时需要缩放 blit
原始图像。使用属性 maprect
定义地图的比例大小和相对位置。添加一个方法 blit
地图,可以缩放和 blit 地图。在 class App
:
的构造函数中使用方法
class App:
def __init__(self):
# [...]
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect(center = self.window.get_rect().center)
self.blitmap()
#create window
pygame.display.flip()
def blitmap(self):
self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
self.window.fill(0)
self.window.blit(self.mapsurface, self.maprect)
# [...]
图片缩放后,计算新的映射矩形(self.maprect
),再次调用方法:
class App:
# [...]
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.blitmap()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4 or event.button == 5:
zoom = 2 if event.button == 4 else 0.5
mx, my = event.pos
left = mx + (self.maprect.left - mx) * zoom
right = mx + (self.maprect.right - mx) * zoom
top = my + (self.maprect.top - my) * zoom
bottom = my + (self.maprect.bottom - my) * zoom
self.maprect = pygame.Rect(left, top, right-left, bottom-top)
self.blitmap()
完整示例:
repl.it/@Rabbid76/PyGame-ZoomInAndOut
import pygame
from pygame.locals import *
import os
class App:
def __init__(self):
self.running = True
self.size = (800,600)
#create window
self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
#create map
currentdir = os.path.dirname(os.path.realpath(__file__))
imagedir = currentdir+'/images/europe.png'
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect(center = self.window.get_rect().center)
self.blitmap()
#create window
pygame.display.flip()
def blitmap(self):
self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
self.window.fill(0)
self.window.blit(self.mapsurface, self.maprect)
def on_init(self):
self.country = Country()
def on_cleanup(self):
pygame.quit()
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.blitmap()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4 or event.button == 5:
zoom = 2 if event.button == 4 else 0.5
mx, my = event.pos
left = mx + (self.maprect.left - mx) * zoom
right = mx + (self.maprect.right - mx) * zoom
top = my + (self.maprect.top - my) * zoom
bottom = my + (self.maprect.bottom - my) * zoom
self.maprect = pygame.Rect(left, top, right-left, bottom-top)
self.blitmap()
pygame.display.update()
def on_execute(self):
while self.running == True:
for event in pygame.event.get():
self.check_event(event)
self.on_cleanup()
class Country(App):
def __init__(self):
super().__init__()
start = App()
start.on_init()
start.on_execute()
我遇到了 PyGame 无法解决的问题。所以: 我的想法是我有一张可以放大 in/out 的地图。放大效果很好。但是缩小显示图片的其余部分已被删除,现在只存在以前在 window 上可见的图像部分。 这是我的代码:
import pygame
from pygame.locals import *
import os
class App:
def __init__(self):
self.running = True
self.size = (800,600)
#create window
self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
#create map
currentdir = os.path.dirname(os.path.realpath(__file__))
imagedir = currentdir+'/images/europe.png'
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect()
self.mapsurface = pygame.Surface(self.size)
self.mapsurface.blit(pygame.transform.scale(self.map,(self.size)),(0,0))
self.window.blit(self.mapsurface,(0,0))
self.scale = 1
#create window
pygame.display.flip()
def on_init(self):
self.country = Country()
def on_cleanup(self):
pygame.quit()
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.window.blit(pygame.transform.scale(self.map,(event.dict['size'])),(0,0))
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4:
zoom = 2
wnd_w,wnd_h = self.window.get_size()
zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
zoom_area = pygame.Rect(0,0, *zoom_size)
pos_x,pos_y = pygame.mouse.get_pos()
zoom_area.center = (pos_x, pos_y)
zoom_surf = pygame.Surface(zoom_area.size)
zoom_surf.blit(self.window, (0, 0), zoom_area)
zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
self.window.blit(zoom_surf, (0, 0))
elif event.button == 5:
zoom = 0.5
wnd_w,wnd_h = self.window.get_size()
zoom_size = (round(wnd_w/zoom), round(wnd_h/zoom))
zoom_area = pygame.Rect(0,0,*zoom_size)
pos_x,pos_y = pygame.mouse.get_pos()
zoom_area.center = (pos_x, pos_y)
zoom_surf = pygame.Surface(zoom_area.size)
zoom_surf.blit(self.window, (0, 0), zoom_area)
zoom_surf = pygame.transform.smoothscale(zoom_surf, (wnd_w, wnd_h))
self.window.blit(zoom_surf, (0, 0))
pygame.display.flip()
pygame.display.update()
def on_execute(self):
while self.running == True:
for event in pygame.event.get():
self.check_event(event)
self.on_cleanup()
class Country(App):
def __init__(self):
super().__init__()
start = App()
start.on_init()
start.on_execute()
这是我的问题的截图:
到目前为止一切顺利:
放大效果很好:
缩小会导致:
缩放时需要缩放 blit
原始图像。使用属性 maprect
定义地图的比例大小和相对位置。添加一个方法 blit
地图,可以缩放和 blit 地图。在 class App
:
class App:
def __init__(self):
# [...]
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect(center = self.window.get_rect().center)
self.blitmap()
#create window
pygame.display.flip()
def blitmap(self):
self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
self.window.fill(0)
self.window.blit(self.mapsurface, self.maprect)
# [...]
图片缩放后,计算新的映射矩形(self.maprect
),再次调用方法:
class App:
# [...]
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.blitmap()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4 or event.button == 5:
zoom = 2 if event.button == 4 else 0.5
mx, my = event.pos
left = mx + (self.maprect.left - mx) * zoom
right = mx + (self.maprect.right - mx) * zoom
top = my + (self.maprect.top - my) * zoom
bottom = my + (self.maprect.bottom - my) * zoom
self.maprect = pygame.Rect(left, top, right-left, bottom-top)
self.blitmap()
完整示例:
import pygame
from pygame.locals import *
import os
class App:
def __init__(self):
self.running = True
self.size = (800,600)
#create window
self.window = pygame.display.set_mode(self.size, pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
#create map
currentdir = os.path.dirname(os.path.realpath(__file__))
imagedir = currentdir+'/images/europe.png'
self.map = pygame.image.load(imagedir)
self.maprect = self.map.get_rect(center = self.window.get_rect().center)
self.blitmap()
#create window
pygame.display.flip()
def blitmap(self):
self.mapsurface = pygame.transform.smoothscale(self.map, self.maprect.size)
self.window.fill(0)
self.window.blit(self.mapsurface, self.maprect)
def on_init(self):
self.country = Country()
def on_cleanup(self):
pygame.quit()
def check_event(self,event):
if event.type == pygame.QUIT:
self.running = False
elif event.type == pygame.VIDEORESIZE:
self.window = pygame.display.set_mode(event.dict['size'], pygame.DOUBLEBUF | pygame.HWSURFACE | pygame.RESIZABLE)
self.blitmap()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 4 or event.button == 5:
zoom = 2 if event.button == 4 else 0.5
mx, my = event.pos
left = mx + (self.maprect.left - mx) * zoom
right = mx + (self.maprect.right - mx) * zoom
top = my + (self.maprect.top - my) * zoom
bottom = my + (self.maprect.bottom - my) * zoom
self.maprect = pygame.Rect(left, top, right-left, bottom-top)
self.blitmap()
pygame.display.update()
def on_execute(self):
while self.running == True:
for event in pygame.event.get():
self.check_event(event)
self.on_cleanup()
class Country(App):
def __init__(self):
super().__init__()
start = App()
start.on_init()
start.on_execute()