I am having an issue with PyGame i can’t resolve. So: my idea is that I have a map I can zoom in/out on. zooming in works fine. But zooming out shows that the rest of the picture got deleted and only the part of the image that was previously visible on the window exists now. This is my code:
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()
Here are the screenshots of my problem:
so far so good:
zooming in works fine:
zooming out causes this:
Advertisement
Answer
You’ll need to scale and blit
the original image when you zoom. Use the attribute maprect
to define the scaled size and relative location of the map. Add a method blit
map that can scale and blit the map. Use the method in the constructor of the 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) # [...]
When the image is zoomed, calculate the new mapping rectangle (self.maprect
) and call the method again:
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()
See also Scale and zoom window
Complete example:
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()