When I use pygame.RESIZABLE my images get squished [duplicate] - python

I have the problem with pygame. Specifically, I stuck on how to resize the text proportionally to the window (window is re-sizable and with picture).
Here is my code.
import pygame
from pygame.locals import *
import numpy as np
import matplotlib.pyplot as plt
import argparse
import threading, os, sys, time
pygame.init()
pygame.display.set_caption("AI Battlehip Game")
FPS = pygame.time.Clock()
red = (255,0,0)
screen = pygame.display.set_mode((1200,700), HWSURFACE|DOUBLEBUF|RESIZABLE)
add_screen = screen.copy()
back_end_image_set = pygame.image.load(r'/Users/User1/Desktop/Project work/images/backgroundimage1.jpg')
screen.blit(pygame.transform.scale(back_end_image_set, (1200,700)), (0,0))
pygame.display.flip()
myFont = pygame.font.SysFont("monospace", 300)
label = myFont.render("Check 1", 40, (red))
add_screen.blit(pygame.transform.scale(label, (700, 500)), (0,0))
FPS.tick(60)
try:
while True:
pygame.event.pump()
event = pygame.event.wait()
if event.type == QUIT:
pygame.display.quit()
elif event.type == VIDEORESIZE:
screen = pygame.display.set_mode(event.dict['size'], HWSURFACE|DOUBLEBUF|RESIZABLE)
screen.blit(pygame.transform.scale(back_end_image_set, event.dict['size']), (0,0))
pygame.display.flip()
except:
raise
Any help will be fully appreciated.

First store the original size of the surface:
original_size = (1200,700)
screen = pygame.display.set_mode(original_size, HWSURFACE|DOUBLEBUF|RESIZABLE)
Then you've 2 options.
Option 1:
Use pygame.font and render the text to a surface:
myFont = pygame.font.SysFont("monospace", 300)
label = myFont.render("Check 1", 40, (red))
Scale the text surface by the ratio of the new window size and original window size and blit it to the surface:
pygame.event.pump()
event = pygame.event.wait()
if event.type == QUIT:
pygame.display.quit()
elif event.type == VIDEORESIZE:
screen = pygame.display.set_mode(event.dict['size'], HWSURFACE|DOUBLEBUF|RESIZABLE)
new_size = event.dict['size']
screen.blit(pygame.transform.scale(back_end_image_set, new_size), (0,0))
label_w = label.get_width() * new_size[0] // original_size[0]
label_h = label.get_height() * new_size[1] // original_size[1]
screen.blit(pygame.transform.scale(label, (label_w, label_h)), (0,0))
pygame.display.flip()
Option 2:
Use pygame.freetype:
import pygame.freetype
myFont = pygame.freetype.SysFont('monospace', 30)
Calculate the scaled size of the text area and render it directly to the resized screen. Note the text is scaled by the ratio of the new window width and original window width.
This implementation keeps the ration of the width and height of the text and doesn't stretch or squeeze the text:
pygame.event.pump()
event = pygame.event.wait()
if event.type == QUIT:
pygame.display.quit()
elif event.type == VIDEORESIZE:
screen = pygame.display.set_mode(event.dict['size'], HWSURFACE|DOUBLEBUF|RESIZABLE)
new_size = event.dict['size']
screen.blit(pygame.transform.scale(back_end_image_set, new_size), (0,0))
myFont.render_to(screen, (0, 0), "Check 1", fgcolor=red, size = 300 * new_size[0] // original_size[0])
pygame.display.flip()

Related

center images and add padding according to screen resolution

I'm using pygame to show two images: I've maneged to resize the images according to the screen size of my user. But I'd like to standardized also the x and the y coordination position of my images. The images should always be in the middle according to the y axis and have the a little bit of pad to stay close to the border of the monitor like this no matter what resolution my user
has:
This are the values that I'd like to standardized
WIN.blit(FIRST_IMG, (100, 280))
WIN.blit(SECOND_IMAGE, (1350, 280))
This is my code right now:
import pygame
import os
WIN = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
WHITE = (255, 255, 255)
FPS = 60
SCREEN_INFO = pygame.display.Info()
IMAGE_WIDTH, IMG_HEIGHT = SCREEN_INFO.current_w // 5, SCREEN_INFO.current_h // 3
FIRST_IMG = pygame.image.load(os.path.join("Assets", "7.png"))
FIRST_IMG = pygame.transform.scale(FIRST_IMG, (IMAGE_WIDTH, IMG_HEIGHT))
SECOND_IMAGE = pygame.image.load(os.path.join("Assets", "8.png"))
SECOND_IMAGE = pygame.transform.scale(SECOND_IMAGE, (IMAGE_WIDTH, IMG_HEIGHT))
def draw_window():
WIN.fill(WHITE)
WIN.blit(FIRST_IMG, (100, 280))
WIN.blit(SECOND_IMAGE, (1350, 280))
pygame.display.update()
def main():
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = False
draw_window()
pygame.quit()
if __name__ == "__main__":
main()
Get the bounding rectangle of the image and set the centery and left or right of the rectangle depending on the size of WIN. Use the rectangles to blit the images:
def draw_window():
width, height = WIN.get_size()
WIN.fill(WHITE)
first_rect = FIRST_IMG.get_rect(midleft = (100, height // 2))
WIN.blit(FIRST_IMG, first_rect)
second_rect = FIRST_IMG.get_rect(midright = (width - 100, height // 2))
WIN.blit(SECOND_IMAGE, second_rect)
pygame.display.update()

button class creates another screen to show buttons instead of displaying on exisiting screen

I have created a screen in pygame and want to display command buttons on it. for that i have written a code containing button class but it creates another screen instead of displaying the buttons on the same screen. can anyone tell me where i have gone wrong?
# import the pygame module
import pygame
import sys
pygame.init()
width, height =1550,800
fps = 60
fpsClock = pygame.time.Clock()
screen=pygame.display.set_mode((width, height))
font=pygame.font.SysFont('arial',40)
objects = []
pygame.display.set_caption('image')
imp=pygame.image.load("D:/PycharmProjects/flay high bangtan/flappy bird\sprites/background/main page.jpg")
screen.blit(imp,(0,0))
pygame.display.flip()
status=True
while (status):
for i in pygame.event.get():
if i.type == pygame.QUIT:
status=False
#COMMAND BUTTONS
class Button():
def __init__(self, x, y, width, height, buttonText='Button', onclickFunction=None, onePress=False):
self.x = x
self.y = y
self.width = width
self.height = height
self.onclickFunction = onclickFunction
self.onePress = onePress
self.fillColors = {
'normal': '#ffffff',
'hover': '#666666',
'pressed': '#333333',
}
self.buttonSurface = pygame.Surface((self.width, self.height))
self.buttonRect = pygame.Rect(self.x, self.y, self.width, self.height)
self.buttonSurf = font.render(buttonText, True, (20, 20, 20))
self.alreadyPressed = False
objects.append(self)
def process(self):
mousePos = pygame.mouse.get_pos()
self.buttonSurface.fill(self.fillColors['normal'])
if self.buttonRect.collidepoint(mousePos):
self.buttonSurface.fill(self.fillColors['hover'])
if pygame.mouse.get_pressed(num_buttons=3)[0]:
self.buttonSurface.fill(self.fillColors['pressed'])
if self.onePress:
self.onclickFunction()
elif not self.alreadyPressed:
self.onclickFunction()
self.alreadyPressed = True
else:
self.alreadyPressed = False
self.buttonSurface.blit(self.buttonSurf, [
self.buttonRect.width / 2 - self.buttonSurf.get_rect().width / 2,
self.buttonRect.height / 2 - self.buttonSurf.get_rect().height / 2
])
screen.blit(self.buttonSurface, self.buttonRect)
def myFunction():
print('Button Pressed')
customButton = Button(30, 30, 400, 100, 'PLAY', myFunction)
customButton = Button(30, 140, 400, 100, 'ABOUT US', myFunction)
customButton = Button(30, 250, 400, 100, 'EXIT', myFunction)
# Game loop.
while True:
screen.fill((20, 20, 20))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for object in objects:
object.process()
pygame.display.flip()
fpsClock.tick(fps)
pygame.QUIT()
this is code to create a screen in pygame and display buttons on it. but when i run it i get one screen that shows my image and after closing it i get another screen with buttons. but i am not understanding how to put those buttons on the same screen as that of the iamge.
You have 2 application loops. Remove the 1st application loop, but draw the background image in the second application loop:
# DELETE
#screen.blit(imp,(0,0))
#pygame.display.flip()
#status=True
#while (status):
# for i in pygame.event.get():
# if i.type == pygame.QUIT:
# status=False
# [...]
# Game loop.
while True:
# DELETE
# screen.fill((20, 20, 20))
# INSERT
screen.blit(imp,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
for object in objects:
object.process()
pygame.display.flip()
fpsClock.tick(fps)
pygame.quit()

Pygame WINDOWRESIZED black screen

I'm trying to resize a window in pygame but only get a black screen. See the before and after pictures below. What am I doing wrong?
import pygame as pg
from pygame.locals import *
pg.init()
yellow = (255, 255, 134)
grey = (142, 142, 142)
square_size = 100
width = 7 * square_size
height = 7 * square_size
radius = int(square_size / 2 - 10)
screen = pg.display.set_mode((width, height), RESIZABLE)
screen.fill(grey)
pg.draw.circle(screen,yellow,(square_size,square_size),radius)
pg.display.flip()
while True:
for ev in pg.event.get():
if ev.type == pg.QUIT:
print("quit game")
pg.quit()
sys.exit()
if ev.type == pg.WINDOWRESIZED:
width, height = screen.get_width(), screen.get_height()
pg.display.flip()
You need to redraw the scene after resizing the window. I recommend redrawing the scene in each frame. The typical PyGame application loop has to:
limit the frames per second to limit CPU usage with pygame.time.Clock.tick
handle the events by calling either pygame.event.pump() or pygame.event.get().
update the game states and positions of objects dependent on the input events and time (respectively frames)
clear the entire display or draw the background
draw the entire scene (blit all the objects)
update the display by calling either pygame.display.update() or pygame.display.flip()
import sys
import pygame as pg
from pygame.locals import *
pg.init()
yellow = (255, 255, 134)
grey = (142, 142, 142)
square_size = 100
width = 7 * square_size
height = 7 * square_size
radius = int(square_size / 2 - 10)
screen = pg.display.set_mode((width, height), RESIZABLE)
clock = pg.time.Clock()
run = True
while run:
# limit the frames per second
clock.tick(100)
# handle the events
for ev in pg.event.get():
if ev.type == pg.QUIT:
print("quit game")
run = False
if ev.type == pg.WINDOWRESIZED:
width, height = screen.get_width(), screen.get_height()
# clear display
screen.fill(grey)
# draw scene
pg.draw.circle(screen,yellow,(square_size,square_size),radius)
# update the display
pg.display.flip()
pg.quit()
sys.exit()

python pygame the background image changes with the screen size

I set screen=p.display.set_mode((width,height),flag,0) as my pygame screen and flag=p.RESIZABLE makes the screen can be stretch.
At this time i load an image as the background, now when i stretch the screen, the background wont change the size by the screen, how can i do it?
here's the codes:
#! /usr/bin/python
import sys
import pygame as p
pic="/home/finals/python/alien/image/muha.png"
def screen_setting(width,height):
p.init()
flag=p.RESIZABLE
screen=p.display.set_mode((width,height),flag,0)
bk=p.transform.smoothscale(p.image.load(pic).convert(),(width,height))
while True:
for event in p.event.get():
if event.type == p.QUIT:
sys.exit()
screen.blit(bk,(0,0))
p.display.flip()
screen_setting(1200,800)
You have to implement the VIDEORESIZE event (see pygame.event).
When the window is resized, then get the new size of the window from the even attributes:
width, height = event.w, event.h
Create a new Surface associated to the window and scale the background to the new size:
def screen_setting(width,height):
p.init()
flag = p.RESIZABLE
screen=p.display.set_mode((width, height), flag, 0)
bk_orig = p.image.load(pic).convert()
bk = p.transform.smoothscale(bk_orig, (width, height))
while True:
for event in p.event.get():
if event.type == p.QUIT:
sys.exit()
elif event.type == p.VIDEORESIZE:
width, height = event.w, event.h
screen = p.display.set_mode((width, height), flag, 0)
bk = p.transform.smoothscale(bk_orig, (width, height))
screen.blit(bk, (0 ,0))
p.display.flip()

Pygame keeps crashing when I open it

I've have this dodging aliens game and it's not working. I can get the front begin screen to open but then when I hit enter to start it crashes and freezes. I've tried running it from python.exe instead of just IDLE but in that case it just pops up then closes right down. A few errors popped up the first few times I tried to run it but now there are no errors indicating what might be wrong. It just stops responding. What am I doing wrong here?
import pygame, random, sys
from pygame.locals import *
def startGame():
if event.type == K_ENTER:
if event.key == K_ESCAPE:
sys.exit()
return
def playerCollision():
for a in aliens:
if playerRect.colliderect(b['rect']):
return True
return False
pygame.init()
screen = pygame.display.set_mode((750,750))
clock = pygame.time.Clock()
pygame.display.set_caption('Dodge the Aliens')
font = pygame.font.SysFont(None, 55)
playerImage = pygame.image.load('')
playerRect = playerImage.get_rect()
alienImage = pygame.image.load('')
drawText('Dodge the Aliens!', font, screen, (750 / 3), (750 / 3))
drawText('Press ENTER to start.', font, screen, (750 / 3) - 45, (750 / 3) + 65)
pygame.display.update()
topScore = 0
while True:
aliens = []
score = 0
playerRect.topleft = (750 /2, 750 - 50)
alienAdd = 0
while True:
score += 1
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]: x -=3
if pressed[pygame.K_RIGHT]: x += 3
if pressed[pygame.K_ESCAPE]: sys.exit()
alienAdd += 1
if alienAdd == addedaliens:
aliendAdd = 0
alienSize = random.randint(10, 40)
newAlien = {'rect': pygame.Rect(random.randint(0, 750 - alienSize), 0 -alienSize, alienSize, alienSize), 'speed': random.randint(1, 8), 'surface':pygame.transform.scale(alienImage, (alienSize, alienSize)), }
aliens.append(newAlien)
for a in aliens[:]:
if a['rect'].top > 750:
aliens.remove(a)
screen.fill(0,0,0)
drawText('Score %s' % (score), font, screen, 10, 0)
screen.blit(playerImage, playerRect)
for a in aliens:
screen.blit(b['surface'], b['rect'])
pygame.display.update()
if playerCollision(playerRect, aliens):
if score > topScore:
topScore = score
break
clock.tick(60)
drawText('Game Over!', font, screen, (750 / 3), ( 750 / 3))
drawText('Press ENTER To Play Again.', font, screen, ( 750 / 3) - 80, (750 / 3) + 50)
pygame.display.update()
startGame()
Here's my new code after modifying it some
import pygame, random, sys
from pygame.locals import*
alienimg = pygame.image.load('C:\Python27\alien.png')
playerimg = pygame.image.load('C:\Python27\spaceship.png')
def playerCollision(): # a function for when the player hits an alien
for a in aliens:
if playerRect.colliderect(b['rect']):
return True
return False
def screenText(text, font, screen, x, y): #text display function
textobj = font.render(text, 1, (255, 255, 255))
textrect = textobj.get_rect()
textrect.topleft = (x,y)
screen.blit(textobj, textrect)
def main(): #this is the main function that starts the game
pygame.init()
screen = pygame.display.set_mode((750,750))
clock = pygame.time.Clock()
pygame.display.set_caption('Dodge the Aliens')
font = pygame.font.SysFont("monospace", 55)
pressed = pygame.key.get_pressed()
aliens = []
score = 0
alienAdd = 0
addedaliens = 0
while True: #our while loop that actually runs the game
for event in pygame.event.get(): #key controls
if event.type == KEYDOWN and event.key == pygame.K_ESCAPE:
sys.exit()
elif event.type == KEYDOWN and event.key == pygame.K_LEFT:
playerRect.x -= 3
elif event.type == KEYDOWN and event.key == pygame.K_RIGHT:
playerRect.x += 3
playerImage = pygame.image.load('C:\\Python27\\spaceship.png').convert() # the player images
playerRect = playerImage.get_rect()
playerRect.topleft = (750 /2, 750 - 50)
alienImage = pygame.image.load('C:\\Python27\\alien.png').convert() #alien images
alienAdd += 1
pygame.display.update()
if alienAdd == addedaliens: # randomly adding aliens of different sizes and speeds
aliendAdd = 0
alienSize = random.randint(10, 40)
newAlien = {'rect': pygame.Rect(random.randint(0, 750 - alienSize), 0 -alienSize, alienSize, alienSize), 'speed': random.randint(1, 8), 'surface':pygame.transform.scale(alienImage, (alienSize, alienSize)), }
aliens.append(newAlien)
for a in aliens[:]:
if a['rect'].top > 750:
aliens.remove(a) #removes the aliens when they get to the bottom of the screen
screen.blit(screen, (0,0))
screenText('Score %s' % (score), font, screen, 10, 0)
screen.blit(playerImage, playerRect)
for a in aliens:
screen.blit(b['surface'], b['rect'])
pygame.display.flip()
if playerCollision(playerRect, aliens):
if score > topScore:
topScore = score
break
clock.tick(60)
screenText('Game Over!', font, screen, (750 / 6), ( 750 / 6))
screenText('Press ENTER To Play Again.', font, screen, ( 750 / 6) - 80, (750 / 6) + 50)
pygame.display.update()
main()
I still see several issues with your code and I think you're trying to do too much at once for the very beginning. Try to keep it as simple as possible. Try creating a display and draw some image:
import pygame
pygame.init()
display = pygame.display.set_mode((750, 750))
img = pygame.image.load("""C:\\Game Dev\\alien.png""")
display.blit(img, (0, 0))
pygame.display.flip()
You'll have to adjust the img path of course. Running this you should either get an explicit Error (which you should then post in another thread) or see your img on the screen. BUT the program will not respond as there's no event handling and no main loop at all.
To avoid this, you could introduce a main loop like:
import sys
import pygame
pygame.init()
RESOLUTION = (750, 750)
FPS = 60
display = pygame.display.set_mode(RESOLUTION)
clock = pygame.time.Clock()
img = pygame.image.load("""C:\\Game Dev\\alien.png""")
while True: # <--- game loop
# check quit program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# clear the screen
display.fill((0, 0, 0))
# draw the image
display.blit(img, (0, 0))
# update the screen
pygame.display.flip()
# tick the clock
clock.tick(FPS)
This should result in a program that displays the same img over and over, and it can be quit properly using the mouse. But still it's like a script, and if someone imported this, it would execute immediately, which is not what we want. So let's fix that as well and wrap it all up in a main function like this:
import sys
import pygame
#defining some constants
RESOLUTION = (750, 750)
FPS = 60
def main(): # <--- program starts here
# setting things up
pygame.init()
display = pygame.display.set_mode(RESOLUTION)
clock = pygame.time.Clock()
img = pygame.image.load("""C:\\Game Dev\\alien.png""")
while True: # <--- game loop
# check quit program
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# clear the screen
display.fill((0, 0, 0))
# draw the image
display.blit(img, (0, 0))
# update the screen
pygame.display.flip()
# tick the clock
clock.tick(FPS)
if __name__ == "__main__":
main()
The 'if name == "main":' ensures that the program does not execute when it's imported.
I hope this helps. And remember: Don't try too much all at once. Take small steps, one after another, and try to keep the control over your program. If needed, you can even put a print statement after every single line of code to exactly let you know what your program does and in what order.

Categories

Resources