Zooming in and out of a PyGame window with all objects still in place

无人久伴 提交于 2021-02-05 07:58:47

问题


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:


回答1:


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:

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


来源:https://stackoverflow.com/questions/64936805/zooming-in-and-out-of-a-pygame-window-with-all-objects-still-in-place

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!