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:
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()
Related
I'm creating a pong style game for android where the paddles are controlled by dragging the touchscreen. The idea is that 2 players can play on the same device, each controlling a paddle with the touchscreen. Is it possible to drag 2 sprites to different locations at the same time using the touch events from pygame 2.0?
I've been able to move the paddles one at a time using the FINGERDOWN/FINGERMOTION/FINGERUP events but can't figure out how to use multitouch to control the paddles independantly from one another at the same time. If I drag both paddles they seem to both follow the coordinates of one FINGERDOWN event.
Here is my code, I hope the formatting is ok, it's the first time I'm posting on the site.
GIF example showing problem
import sys
import pygame
from pygame.locals import *
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((200,200))
self.image.fill(WHITE)
self.rect = self.image.get_rect(center = (x, y))
self.drag = False
def update(self, events):
for e in events:
if e.type == FINGERDOWN:
for finger, pos in fingers.items():
if self.rect.collidepoint(pos):
self.drag = True
self.mx, self.my = pos
self.offx = self.rect.x - self.mx
self.offy = self.rect.y - self.my
if e.type == FINGERMOTION:
if self.drag:
for finger, pos in fingers.items():
self.mx, self.my = pos
self.rect.y = self.my + self.offy
if e.type == FINGERUP:
self.drag = False
def handle_events():
global events
for event in events:
if pygame.event == QUIT:
pygame.quit()
sys.exit()
if event.type == VIDEORESIZE:
DW, DH = event.w, event.h
if event.type == FINGERDOWN:
x = int(event.x * DS.get_width())
y = int(event.y * DS.get_height())
fingers[event.finger_id] = x, y
if event.type == FINGERMOTION:
x = int(event.x * DS.get_width())
y = int(event.y * DS.get_height())
fingers[event.finger_id] = x, y
if event.type == FINGERUP:
fingers.pop(event.finger_id, None)
pygame.init()
#display settings
DW = 0
DH = 0
DS = pygame.display.set_mode((DW, DH), pygame.FULLSCREEN | pygame.RESIZABLE)
DW, DH = DS.get_size()
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
#player intialisation
p = Player(0 + 100, DH/2)
p2 = Player(DW - 100, DH/2)
sprites = pygame.sprite.Group()
sprites.add(p, p2)
fingers = {}
clock = pygame.time.Clock()
while True:
events = pygame.event.get()
handle_events()
DS.fill(BLACK)
sprites.draw(DS)
sprites.update(events)
pygame.display.update()
clock.tick(FPS)
The events FINGERDOWN, FINGERUP and FINGERMOTION give you the finger_id (also see How to use Pygame touch events in a mobile game?).
You must store the ID of the finger touching the object in an attribute. Drag the object only when the finger with the corresponding ID is moved:
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((200,200))
self.image.fill(WHITE)
self.rect = self.image.get_rect(center = (x, y))
self.drag = False
self.finger_id = None
def update(self, events):
for e in events:
if e.type == FINGERDOWN:
for finger, pos in fingers.items():
if self.rect.collidepoint(pos):
self.finger_id = finger
self.drag = True
self.mx, self.my = pos
self.offx = self.rect.x - self.mx
self.offy = self.rect.y - self.my
if e.type == FINGERMOTION:
if self.drag:
for finger, pos in fingers.items():
if finger == self.finger_id:
self.mx, self.my = pos
self.rect.y = self.my + self.offy
if e.type == FINGERUP:
if not self.finger_id in fingers:
self.drag = False
Actually you don't need the the global fingers map at all
import sys
import pygame
from pygame.locals import *
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((200, 200))
self.image.fill("red")
self.rect = self.image.get_rect(center = (x, y))
self.drag = False
self.finger_id = None
def update(self, events):
for e in events:
if e.type == FINGERDOWN:
x = int(e.x * DS.get_width())
y = int(e.y * DS.get_height())
if self.rect.collidepoint((x, y)):
self.finger_id = e.finger_id
self.drag = True
self.mx, self.my = x, y
self.offx = self.rect.x - self.mx
self.offy = self.rect.y - self.my
if e.type == FINGERMOTION:
if self.drag and self.finger_id == e.finger_id:
x = int(e.x * DS.get_width())
y = int(e.y * DS.get_height())
self.mx, self.my = x, y
self.rect.y = self.my + self.offy
if e.type == FINGERUP:
if self.finger_id == e.finger_id:
self.drag = False
def handle_events(events):
for event in events:
if event.type == VIDEORESIZE:
DW, DH = event.w, event.h
pygame.init()
#display settings
DW = 0
DH = 0
#DS = pygame.display.set_mode((DW, DH), pygame.FULLSCREEN | pygame.RESIZABLE)
DS = pygame.display.set_mode((640, 480))
DW, DH = DS.get_size()
FPS = 60
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
#player intialisation
p = Player(0 + 100, DH/2)
p2 = Player(DW - 100, DH/2)
sprites = pygame.sprite.Group()
sprites.add(p, p2)
clock = pygame.time.Clock()
run = True
while run:
events = pygame.event.get()
run = not any(event for event in events if event.type == QUIT)
handle_events(events)
DS.fill(BLACK)
sprites.draw(DS)
sprites.update(events)
pygame.display.update()
clock.tick(FPS)
pygame.quit()
sys.exit()
I have been following this tutorial about animated buttons in pygame. It worked perfectly until I created a button outside of the main loop in another function.
Here is my code:
import pygame
from pygame.locals import *
import sys
import random
# Constants
SCREEN = pygame.display.set_mode((1280, 720), 0, 32)
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREY = (100, 100, 100)
LIGHT_BLUE = (66, 233, 245)
# Button Class
class Button:
def __init__(self, text, width, height, pos, elevation):
# Core attributes
self.pressed = False
self.elevation = elevation
self.dynamicElevation = elevation
self.originalYPos = pos[1]
# Top Rectangle
self.topRectangle = pygame.Rect(pos, (width, height))
self.topColor = '#457B9D'
# Bottom Rectangle
self.bottomRectangle = pygame.Rect(pos, (width, elevation))
self.bottomColor = '#1D3557'
# Text
self.textSurface = gui_font.render(text, True, '#FFFFFF')
self.textRectangle = self.textSurface.get_rect(center = self.topRectangle.center)
def draw(self):
# Elevation Logic
self.topRectangle.y = self.originalYPos - self.dynamicElevation
self.textRectangle.center = self.topRectangle.center
self.bottomRectangle.midtop = self.topRectangle.midtop
self.bottomRectangle.height = self.topRectangle.height + self.dynamicElevation
bottom =pygame.draw.rect(SCREEN, self.bottomColor, self.bottomRectangle, border_radius = 12)
top = pygame.draw.rect(SCREEN, self.topColor, self.topRectangle, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', top, 1, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', bottom, 1, border_radius = 12)
SCREEN.blit(self.textSurface, self.textRectangle)
self.check_click()
def check_click(self):
mousePosition = pygame.mouse.get_pos()
if self.topRectangle.collidepoint(mousePosition):
self.topColor = '#F1FAEE'
if pygame.mouse.get_pressed()[0]:
self.dynamicElevation = 0
self.pressed = True
else:
self.dynamicElevation = self.elevation
if self.pressed == True:
print("Click")
self.pressed = False
else:
self.topColor = '#457B9D'
class GameState():
def __init__(self):
self.state = "welcome"
def welcomeScreen(self):
SCREEN.fill(WHITE)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F1:
self.state = "mainGame"
pygame.display.update()
def mainGame(self):
SCREEN.fill(GREY)
buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
buttonBack.draw()
pygame.display.update()
def stateManager(self):
if self.state == "welcome":
self.welcomeScreen()
if self.state == "mainGame":
self.mainGame()
pygame.init()
clock = pygame.time.Clock()
gameState = GameState()
pygame.display.set_caption("Button Test")
gui_font = pygame.font.Font(None, 30)
while True:
gameState.stateManager()
clock.tick(60)
I have tried to play around with putting the button in a different screen or at different stages of the loop. Is there a logic error I cannot see or lies my mistake somewhere else?
You are actually creating the button inside the main loop since you create it each time mainGame is called. mainGame is called by stateManager if the state is "mainGame", and that's called at each frame in your while True loop. So as you are recreating your button at each frame I think your problems might come from there.
I suggest you create your button in the parent's class constructor instead:
class GameState():
def __init__(self):
self.state = "welcome"
# Create the button here to make the object persistent.
self.buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
# ...
def mainGame(self):
SCREEN.fill(GREY)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
self.buttonBack.draw() # <- use your button with self.buttonBack
pygame.display.update()
# ...
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:
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()
I am making a game in pygame, but the display doesn't update. I am using the update() function and am clearing the screen at the beginning of the loop with fill(). Pygame also does not load very quickly; I have to hit "quit" on the pygame application once it shows in the running applications on my mac for the screen to appear.
"Module Imports"
import pygame as pg
import shelve
"Import Classes"
from Settings import Settings
from Settings import Screen
from Settings import Save
from Random import Random
from Input import Input
from Input import Button
# Init Classes
Settings = Settings()
Screen = Screen()
Random = Random()
Save = Save()
on = True
pg.init()
event_const = pg.event.wait()
save_file = shelve.open("/Volumes/HISTORYGAME/Game_Saves/Save_File")
clock = pg.time.Clock()
MainDisplay = pg.display.set_mode((Screen.width, Screen.height))
pg.display.set_caption(Settings.title)
pg.display.init()
class Mouse:
def __init__(self):
self.left = False
self.right = False
Mouse = Mouse()
def begin_game():
players = []
num_players = input("How Many Players (enter int): ")
save_file["num_players_var"] = num_players
for pl in range(num_players):
players.append(raw_input("Enter Player Name: "))
save_file["players_var"] = players
print(players)
def intro():
intro = True
for event in pg.event.get():
if event.get == pg.QUIT:
intro = False
on = False
if event.get == pg.event.KEYDOWN:
pass
# begin_game()
test_button = Button(0, 0, 200, 200, "Enter Text Here", MainDisplay)
buttons = []
buttons.append(test_button)
loops = 0
test_x = 10
test_y = 10
while on:
MainDisplay.fill((0, 0, 0))
for event in pg.event.get():
if event.type == pg.QUIT:
On = False
pg.quit()
exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
On = False
pg.quit()
exit()
if event.key == pg.K_RIGHT:
test_x += 10
print("right")
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
Mouse.left = True
else:
Mouse.left = False
if event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
Mouse.left = False
for button in buttons:
button.draw(pg.mouse.get_pos(), event_const)
if button.clicked is True:
print("True \n" * 100)
pg.draw.line(MainDisplay, (255, 0, 0), (100, 100), (600, 600))
pg.draw.rect(MainDisplay, (255, 0, 0), (test_x, test_y, 20, 20))
pg.display.flip()
pg.display.update()
clock.tick(Settings.FPS)
loops += 1
print(str(loops))
I suspect the waiting for an event, or reading of the stdin with input() is causing a lockup issue. But in the presented code, the call to this is commented-out. It's not possible to really know.
This version of the code, with a re-created Button class works ok, but obviously it doesn't have any of the referenced classes.
"Module Imports"
import pygame
#import shelve
"Import Classes"
#from Settings import Settings
#from Settings import Screen
#from Settings import Save
#from Random import Random
#from Input import Input
#from Input import Button
# Init Classes
#Settings = Settings()
#Screen = Screen()
#Random = Random()
#Save = Save()
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 600
class Mouse:
def __init__(self):
self.left = False
self.right = False
class Button:
def __init__( self, x, y, width, height, label, window ):
self.rect = pygame.Rect( x, y, width, height )
self.clicked = False
self.window = window
self.font = pygame.font.Font( None, 20 )
self.label = self.font.render( label, True, ( 255, 255, 255 ) ) # large white text
def draw( self, mouse_pos ):
if ( self.rect.collidepoint( mouse_pos ) ):
colour = ( 0, 200, 0 ) # green if mouse over
else:
colour = (0, 0, 200) # blue otherwise
pygame.draw.rect( self.window, colour, self.rect, 0 ) # filled rectangle
# centred text
label_rect = self.label.get_rect()
x_offset = ( self.rect.width - label_rect.width ) // 2
y_offset = ( self.rect.height - label_rect.height ) // 2
self.window.blit( self.label, ( x_offset, y_offset ) )
def checkClick( self, mouse_pos ):
if ( self.rect.collidepoint( mouse_pos ) ):
self.clicked = True
else:
self.clicked = False
def begin_game():
players = [ "Mork", "Mindy", "E.T." ] # test data
#players = []
#num_players = input("How Many Players (enter int): ")
#save_file["num_players_var"] = num_players
#for pl in range(num_players):
# players.append(raw_input("Enter Player Name: "))
#save_file["players_var"] = players
print(players)
# Initialisation
pygame.init()
pygame.font.init()
#event_const = pygame.event.wait()
#save_file = shelve.open("/Volumes/HISTORYGAME/Game_Saves/Save_File")
clock = pygame.time.Clock()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption( "Settings.title" )
pygame.display.init()
Mouse = Mouse()
begin_game()
test_button = Button(0, 0, 200, 200, "Enter Text Here", window)
buttons = []
buttons.append(test_button)
loops = 0
test_x = 10
test_y = 10
on = True
while on:
window.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
on = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
on = False
elif event.key == pygame.K_RIGHT:
test_x += 10
print("right")
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
Mouse.left = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
Mouse.left = False
for button in buttons:
button.checkClick( event.pos ) # buttons actuate on mouse-up
for button in buttons:
button.draw( pygame.mouse.get_pos() ) #, event_const)
if button.clicked is True:
print("True \n" * 5) # 100
pygame.draw.line(window, (255, 0, 0), (100, 100), (600, 600))
pygame.draw.rect(window, (255, 0, 0), (test_x, test_y, 20, 20))
pygame.display.flip()
#pygame.display.update() # only need update() or flip()
clock.tick( 60 ) #Settings.FPS)
loops += 1
#print(str(loops)) # Too noisy
# exiting
pygame.quit()
I'm making the program, that blits the 2D array as 2D map of tiles. The self.tile_size variable is used to scale the tile image that will be blit.
I want the Q to make it smaller, and E to make it bigger. The problem is, that output in in pygame window is not what i wanted. The image in link shows what happened, when i ran a program and tried to make image bigger. Image of output
Here's my code:
import pygame
from pygame.locals import *
pygame.init()
import math, sys, os, random, time
from a_star import *
tiles_list = [
pygame.image.load('Floor.png'),
pygame.image.load('Wall.png'),
]
PLAN_W = 20
PLAN_H = 20
PLAN_STATUS = [[True for i in range(PLAN_W)]for j in range(PLAN_H)]
OBSTACLES = [
[0,0],
[0,1],
[0,2]]
obsta(OBSTACLES, PLAN_STATUS) # function imported from a_star that change PLAN_STATUS cells from OBSTACLES to False
class World():
def __init__(self):
self.screen_width = 800
self.screen_height = 600
self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))
self.clock = pygame.time.Clock()
self.bg_color = (255,255,255)
self.tile_size = 48
self.map_status = PLAN_STATUS
self.tiles_list = tiles_list
self.scale_change = 0
self.run()
def scale_tiles(self):
print(self.tile_size)
self.new_list = []
for i in self.tiles_list:
i = pygame.transform.scale(i, (self.tile_size, self.tile_size))
self.new_list.append(i)
self.tiles_list = self.new_list
def render_map(self):
print(self.tile_size)
'''
self.screen.fill(self.bg_color)
for x in range(PLAN_H):
for y in range(PLAN_W):
if self.map_status[y][x]:
tile = self.tiles_list[0]
elif not self.map_status[y][x]:
tile = self.tiles_list[1]
self.screen.blit(tile, (x*self.tile_size, y*self.tile_size))
'''
self.screen.blit(self.tiles_list[0], (400, 300))
def run(self):
while True:
self.events = pygame.event.get()
self.keys = pygame.key.get_pressed()
self.mouse_pos = pygame.mouse.get_pos()
self.mouse_but = pygame.mouse.get_pressed()
#UPDATE
self.screen.fill(self.bg_color)
#self.scale_tiles()
self.render_map()
pygame.display.flip()
#EVENTS
if self.keys[ord('e')] == 1:
self.tile_size += 1
self.scale_tiles()
if self.keys[ord('q')] == 1:
self.tile_size -= 1
self.scale_tiles()
'''for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
print('q')
self.scale_change = -1
if event.key == pygame.K_e:
print('e')
self.scale_change = 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_q or event.key == pygame.K_e:
print('stopped key')
self.scale_change = 0'''
self.clock.tick(50)
if __name__=="__main__":
main = World()
Where's the problem in my code?
Thank you for the help
Floor.png
Use the images/surfaces in the original, global tiles_list to create the new_list not the already scaled images in self.tiles_list, otherwise it seems to increase the impreciseness with every scaling.
for i in tiles_list: not for i in self.tiles_list:.