I am trying to allow resizing for this app, I put the RESIZABLE flag, but when I try to resize, it messes up! Try my code.
It is a grid program, when the window resizes I want the grid to also resize/shrink.
import pygame,math
from pygame.locals import *
# Define some colors
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
# This sets the width and height of each grid location
width=50
height=20
size=[500,500]
# This sets the margin between each cell
margin=1
# Initialize pygame
pygame.init()
# Set the height and width of the screen
screen=pygame.display.set_mode(size,RESIZABLE)
# Set title of screen
pygame.display.set_caption("My Game")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
if event.type == pygame.MOUSEBUTTONDOWN:
height+=10
# Set the screen background
screen.fill(black)
# Draw the grid
for row in range(int(math.ceil(size[1]/height))+1):
for column in range(int(math.ceil(size[0]/width))+1):
color = white
pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])
# Limit to 20 frames per second
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit ()
Please tell me whats wrong, thanks.
The answer for this problem (allow the Pygame window and the surface inside it to resize) is simply to recreate the resizable window with an updated size, when the user changes its dimensions (done on pygame.VIDEORESIZE events).
>>> import pygame
>>> help(pygame.display.set_mode)
Help on built-in function set_mode in module pygame.display:
set_mode(...)
set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface
Initialize a window or screen for display
>>>
This removes all previous content on the window surface, so below
there's a process to continue with the current window content.
Some example code:
import pygame, sys
pygame.init()
# Create the window, saving it to a variable.
surface = pygame.display.set_mode((350, 250), pygame.RESIZABLE)
pygame.display.set_caption("Example resizable window")
while True:
surface.fill((255,255,255))
# Draw a red rectangle that resizes with the window.
pygame.draw.rect(surface, (200,0,0), (surface.get_width()/3,
surface.get_height()/3, surface.get_width()/3,
surface.get_height()/3))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == pygame.VIDEORESIZE:
# There's some code to add back window content here.
surface = pygame.display.set_mode((event.w, event.h),
pygame.RESIZABLE)
How to continue with the current window content:
Here's some steps to add back the previous window content:
make a second variable, set to the value of the old window surface variable.
create the new window, storing it as the old variable.
draw the second surface onto the first one (old variable) - use the blit function.
use this variable and delete the new variable (optional, use del) to not use extra memory.
Some example code for the above steps (replaces pygame.VIDEORESIZE event if statement):
if event.type == pygame.VIDEORESIZE:
old_surface_saved = surface
surface = pygame.display.set_mode((event.w, event.h),
pygame.RESIZABLE)
# On the next line, if only part of the window
# needs to be copied, there's some other options.
surface.blit(old_surface_saved, (0,0))
del old_surface_saved
You are not updating your width, height, or size when the window changes.
From the docs: http://www.pygame.org/docs/ref/display.html
If the display is set with the pygame.RESIZABLE flag,
pygame.VIDEORESIZE events will be sent when the user adjusts the
window dimensions.
You can get the new size, w, h from the event VIDEORESIZE http://www.pygame.org/docs/ref/event.html
A simple Hello World window that is resizable, plus I was playing around with classes.
Broken down into two files, one for defining the colour constants.
import pygame, sys
from pygame.locals import *
from colors import *
# Data Definition
class helloWorld:
'''Create a resizable hello world window'''
def __init__(self):
pygame.init()
self.width = 300
self.height = 300
DISPLAYSURF = pygame.display.set_mode((self.width,self.height), RESIZABLE)
DISPLAYSURF.fill(WHITE)
def run(self):
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == VIDEORESIZE:
self.CreateWindow(event.w,event.h)
pygame.display.update()
def CreateWindow(self,width,height):
'''Updates the window width and height '''
pygame.display.set_caption("Press ESC to quit")
DISPLAYSURF = pygame.display.set_mode((width,height),RESIZABLE)
DISPLAYSURF.fill(WHITE)
if __name__ == '__main__':
helloWorld().run()
colors.py:
BLACK = (0, 0,0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLUE = (0,0,255)
GREEN = (0,255,0)
A simple way to do which I found was the following code snippet
# Imports
from vars import *
from pygame.locals import *
# Main init
pygame.init()
# Basic vars
run = True
s_width = 1000
s_height = 600
# Making display screen. Don't forget the last tag!
screen = pygame.display.set_mode((s_width, s_height), RESIZABLE)
# Main loop
while run:
# event detection
for event in pygame.event.get():
if event.type == QUIT:
run = False
# The part which matters for our purposes
if event.type == WINDOWRESIZED:
s_width, s_height = screen.get_width(), screen.get_height()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
# Test line to see if the window resizing works properly
pygame.draw.line(screen, (255, 255, 255), (int(0.3*s_width), int(0.25*s_height)), (int(0.8*s_width), int(0.25*s_height)))
# Final flip
pygame.display.flip()
# Quit
pygame.quit()
What this does is allows the pygame window to be resized. But since you often have the placing and sizes of a lot of elements/sprites depending on the s_width and s_height, it also detects when the window size is changed and adjusts the dimensions accordingly.
First, You don't detect the new window size before redrawing the screen.
Add the get_size() method at line 45 and it works:
#--------------------------------------------------------------
# Draw the grid
size = pygame.display.get_surface().get_size() // size update
for row in range(int(math.ceil(size[1]/height))+1):
#---------------------------------------------------------
Then you work with a fixed cell size (50, 20) and fill as many cells as possible. If You want to GROW/SHRINK the cells when resizing the window, You will have to define the NUMBER of cells per line/row, then calculate the cell size, then draw them.
Related
I'm working on this pygame game and i'm just getting started but got a bit confused because i want the image to move in the x-axis along with the mouse but when i run the program i want the image to show up at the center or the 'floor' but appears at the left side instead. This is my code and a screenshot of what's happening.
import pygame
import sys
pygame.init()
pygame.mixer.init()
WIDTH, HEIGHT = 400, 500
FPS = 60
TITLE = 'FOOD DROP'
SIZE = 190
# Colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE_SKY = (152, 166, 255)
# Display
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(TITLE)
# Surfaces
floor_surface = pygame.Surface((WIDTH, 100))
floor_surface.fill(BLUE_SKY)
floor_rect = floor_surface.get_rect(midbottom=(200, 500))
# Images
LOAD_DITTO = pygame.image.load('Graphics/ditto.png')
DITTO = pygame.transform.scale(LOAD_DITTO, (SIZE, SIZE))
# Time
CLOCK = pygame.time.Clock()
class Figure:
def draw_figure(self, mouse_x):
SCREEN.blit(DITTO, (mouse_x - 90, 330))
# Game loop
SCREEN_UPDATE = pygame.USEREVENT
# main_game = Main()
figure = Figure()
running = True
while running:
CLOCK.tick(FPS)
mx, my = pygame.mouse.get_pos()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
When i run the program, this happens:
And i want the image to appear right at the center or the x-axis, not the border, i don't know why is this happening. Just to state, that screenshot was taken when the mouse hadn't been placed over the display.
If the mouse pointer is not in the window (out of focus), the initial position of the mouse pointer is (0, 0). Therefore pygame.mouse.get_pos returns (0, 0). It is also not possible to set the mouse position with pygame.mouse.set_pos if it is not in the window.
Initialize the variables mx and mx with the center of the window. Change the mouse position only when the mouse pointer is in the window (in focus). pygame.mouse.get_focused can be used to test whether the mouse is in the window.
mx, my = SCREEN.get_rect().center
running = True
while running:
CLOCK.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if pygame.mouse.get_focused():
mx, my = pygame.mouse.get_pos()
SCREEN.fill(WHITE)
SCREEN.blit(floor_surface, floor_rect)
figure.draw_figure(mx)
pygame.display.update()
pygame.quit()
sys.exit()
I'm pretty new to Python and programming in general.
I'm trying to draw a square (200px by 200px) on the screen when the user clicks on the screen.
I tried to create a surface and a rect around the surface ( when the user clicks on the screen) and then using the rect, placed the surface on the screen using the blit method.
for the x and y of the rect I used mouse position.
So, this in my head should have changed the position of the square whenever a user clicks somewhere else on the screen but it rather creates a new square every time.
so I have a couple of questions:
If the way I'm implementing this is wrong, then how can I implement this feature?
Shouldn't the square change place as Pygame draws it every frame?
Thank you :)
pygame.init()
# --- Column --------------- #
col_num = 8
col_size = 120
# --- Screen --------------- #
screen = pygame.display.set_mode((col_num * col_size, col_num * col_size))
screen.fill((255, 255, 255))
draw_board()
# --- Clock ---------------- #
clock = pygame.time.Clock()
white_player = Player()
# --- test surface --------- #
surface = pygame.Surface((200, 200))
surface.fill((255, 255, 255))
# --- Main Loop ------------ #
check = False
while True:
white_player.draw_piece()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(), sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN:
check = True
a_rect = surface.get_rect(center=pygame.mouse.get_pos())
print('here!')
if check:
screen.blit(surface, a_rect)
pygame.display.update()
clock.tick(60)
Output:
Even trying with a simple surface and a screen it doesn't work.
It adds another surface to the screen with the new x.
import pygame as pg
import sys
pg.init()
screen = pg.display.set_mode((400, 400))
clock = pg.time.Clock()
surface = pg.Surface((200, 200))
surface.fill((255, 255, 255))
xpos = 50
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit(), sys.exit()
xpos += 1
screen.blit(surface, (xpos, 100))
pg.display.flip()
clock.tick(60)
Oh, I just realized I forgot to fill the screen before each frame. fixed
I am trying to allow resizing for this app, I put the RESIZABLE flag, but when I try to resize, it messes up! Try my code.
It is a grid program, when the window resizes I want the grid to also resize/shrink.
import pygame,math
from pygame.locals import *
# Define some colors
black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)
# This sets the width and height of each grid location
width=50
height=20
size=[500,500]
# This sets the margin between each cell
margin=1
# Initialize pygame
pygame.init()
# Set the height and width of the screen
screen=pygame.display.set_mode(size,RESIZABLE)
# Set title of screen
pygame.display.set_caption("My Game")
#Loop until the user clicks the close button.
done=False
# Used to manage how fast the screen updates
clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while done==False:
for event in pygame.event.get(): # User did something
if event.type == pygame.QUIT: # If user clicked close
done=True # Flag that we are done so we exit this loop
if event.type == pygame.MOUSEBUTTONDOWN:
height+=10
# Set the screen background
screen.fill(black)
# Draw the grid
for row in range(int(math.ceil(size[1]/height))+1):
for column in range(int(math.ceil(size[0]/width))+1):
color = white
pygame.draw.rect(screen,color,[(margin+width)*column+margin,(margin+height)*row+margin,width,height])
# Limit to 20 frames per second
clock.tick(20)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit ()
Please tell me whats wrong, thanks.
The answer for this problem (allow the Pygame window and the surface inside it to resize) is simply to recreate the resizable window with an updated size, when the user changes its dimensions (done on pygame.VIDEORESIZE events).
>>> import pygame
>>> help(pygame.display.set_mode)
Help on built-in function set_mode in module pygame.display:
set_mode(...)
set_mode(size=(0, 0), flags=0, depth=0, display=0, vsync=0) -> Surface
Initialize a window or screen for display
>>>
This removes all previous content on the window surface, so below
there's a process to continue with the current window content.
Some example code:
import pygame, sys
pygame.init()
# Create the window, saving it to a variable.
surface = pygame.display.set_mode((350, 250), pygame.RESIZABLE)
pygame.display.set_caption("Example resizable window")
while True:
surface.fill((255,255,255))
# Draw a red rectangle that resizes with the window.
pygame.draw.rect(surface, (200,0,0), (surface.get_width()/3,
surface.get_height()/3, surface.get_width()/3,
surface.get_height()/3))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.type == pygame.VIDEORESIZE:
# There's some code to add back window content here.
surface = pygame.display.set_mode((event.w, event.h),
pygame.RESIZABLE)
How to continue with the current window content:
Here's some steps to add back the previous window content:
make a second variable, set to the value of the old window surface variable.
create the new window, storing it as the old variable.
draw the second surface onto the first one (old variable) - use the blit function.
use this variable and delete the new variable (optional, use del) to not use extra memory.
Some example code for the above steps (replaces pygame.VIDEORESIZE event if statement):
if event.type == pygame.VIDEORESIZE:
old_surface_saved = surface
surface = pygame.display.set_mode((event.w, event.h),
pygame.RESIZABLE)
# On the next line, if only part of the window
# needs to be copied, there's some other options.
surface.blit(old_surface_saved, (0,0))
del old_surface_saved
You are not updating your width, height, or size when the window changes.
From the docs: http://www.pygame.org/docs/ref/display.html
If the display is set with the pygame.RESIZABLE flag,
pygame.VIDEORESIZE events will be sent when the user adjusts the
window dimensions.
You can get the new size, w, h from the event VIDEORESIZE http://www.pygame.org/docs/ref/event.html
A simple Hello World window that is resizable, plus I was playing around with classes.
Broken down into two files, one for defining the colour constants.
import pygame, sys
from pygame.locals import *
from colors import *
# Data Definition
class helloWorld:
'''Create a resizable hello world window'''
def __init__(self):
pygame.init()
self.width = 300
self.height = 300
DISPLAYSURF = pygame.display.set_mode((self.width,self.height), RESIZABLE)
DISPLAYSURF.fill(WHITE)
def run(self):
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == VIDEORESIZE:
self.CreateWindow(event.w,event.h)
pygame.display.update()
def CreateWindow(self,width,height):
'''Updates the window width and height '''
pygame.display.set_caption("Press ESC to quit")
DISPLAYSURF = pygame.display.set_mode((width,height),RESIZABLE)
DISPLAYSURF.fill(WHITE)
if __name__ == '__main__':
helloWorld().run()
colors.py:
BLACK = (0, 0,0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
YELLOW = (255, 255, 0)
BLUE = (0,0,255)
GREEN = (0,255,0)
A simple way to do which I found was the following code snippet
# Imports
from vars import *
from pygame.locals import *
# Main init
pygame.init()
# Basic vars
run = True
s_width = 1000
s_height = 600
# Making display screen. Don't forget the last tag!
screen = pygame.display.set_mode((s_width, s_height), RESIZABLE)
# Main loop
while run:
# event detection
for event in pygame.event.get():
if event.type == QUIT:
run = False
# The part which matters for our purposes
if event.type == WINDOWRESIZED:
s_width, s_height = screen.get_width(), screen.get_height()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
run = False
# Test line to see if the window resizing works properly
pygame.draw.line(screen, (255, 255, 255), (int(0.3*s_width), int(0.25*s_height)), (int(0.8*s_width), int(0.25*s_height)))
# Final flip
pygame.display.flip()
# Quit
pygame.quit()
What this does is allows the pygame window to be resized. But since you often have the placing and sizes of a lot of elements/sprites depending on the s_width and s_height, it also detects when the window size is changed and adjusts the dimensions accordingly.
First, You don't detect the new window size before redrawing the screen.
Add the get_size() method at line 45 and it works:
#--------------------------------------------------------------
# Draw the grid
size = pygame.display.get_surface().get_size() // size update
for row in range(int(math.ceil(size[1]/height))+1):
#---------------------------------------------------------
Then you work with a fixed cell size (50, 20) and fill as many cells as possible. If You want to GROW/SHRINK the cells when resizing the window, You will have to define the NUMBER of cells per line/row, then calculate the cell size, then draw them.
I am new to Pygame and I wish to fill only certain parts of my screen, for example the half. Currently I am only able to fill the complete screen. Can someone help?
import pygame
color= (255, 0, 0)
screen = pygame.display.set_mode((740, 780))
screen.fill(color)
The 2nd parameter of .fill() is a rectangle, which defines the area to be filled.
The width and height of a pygame.Surface object can be get by .get_width() respectively .get_height():
e.g.
screen.fill(color, (0, 0, screen.get_width()// 2, screen.get_height()))
import pygame
size = w,h = 300, 400
scr = pygame.display.set_mode((w,h))
pygame.display.set_caption("Hello")
scr.fill((0,255,0), rect=(0,0,w,h/2))
pygame.display.flip()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
running = False
One way to have partial fill may include "drawing" a shape (i.e. rectangle) on half of the screen.
import sys
import pygame
def half_screen():
#Initialize game and create screen object.
pygame.init()
color= (255, 0, 0)
screen = pygame.display.set_mode((200, 400))
#Draw rectangle to fill the left half of the screen.
left_half = pygame.draw.rect(screen, color,(0,0, 100, 400))
#Start loop for game- keeps screen open until you decide to quit.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
#Make the current screen visible.
pygame.display.flip()
half_screen()
You can find more information on the draw module - pygame.draw - by going to https://www.pygame.org/docs/ref/draw.html
I have this sort of code:
width = 100
height = 50
gameDisplay.blit(button, (width, height))
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
# replace the button's image with another
Is there any function or something that would let me replace the image with another?
You cannot 'replace' anything you've drawn. What you do is that you draw new images over the existing ones. Usually, you clear the screen and redraw your images every loop. Here's pseudo-code illustrating what a typical game loop looks like. I'll use screen as variable name instead of gameDisplay, because gameDisplay goes against PEP-8 naming convention.
while True:
handle_time() # Make sure your programs run at constant FPS.
handle_events() # Handle user interactions.
handle_game_logic() # Use the time and interactions to update game objects and such.
screen.fill(background_color) # Clear the screen / Fill the screen with a background color.
screen.blit(image, rect) # Blit an image on some destination. Usually you blit more than one image using pygame.sprite.Group.
pygame.display.update() # Or 'pygame.display.flip()'.
For your code you probably should do something like this:
rect = pygame.Rect((x_position, y_position), (button_width, button_height))
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
button = new_button # Both should be a pygame.Surface.
gameDisplay.fill(background_color, rect) # Clear the screen.
gameDisplay.blit(button, rect)
pygame.display.update()
If you only want to update the area where your image is you could pass rect inside the update method, pygame.display.update(rect).
To show changes on screen use pygame.display.update().
Your code should look like this
width = 100
height = 50
gameDisplay.blit(button, (width, height))
while True:
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONUP and event.button == 1:
gameDisplay.blit(new_button, (width, height))
pygame.display.update()