This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
My friends and I are making a quiz game in PyGame and would like to know how, when the user presses a button, he can go to next question (without leaving the previous text behind).
First of all I would suggest that you go to the PyGame documentation and read up a little about PyGame. (Link)
However to save you time what you have to do is before you draw your new set of shapes/writings on the screen you have to use the function screen.fill(#Your chosen colour). That is the function in PyGame that gets rid of the old screen and allows you to draw new items on to a clear screen without the pervious drawings left on there.
Example:
import pygame
import sys
from pygame.locals import *
white = (255,255,255)
black = (0,0,0)
red = (255, 0, 0)
class Pane(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('Box Test')
self.screen = pygame.display.set_mode((600,400), 0, 32)
self.screen.fill((white))
pygame.display.update()
def addRect(self):
self.rect = pygame.draw.rect(self.screen, (black), (175, 75, 200, 100), 2)
pygame.display.update()
def addText(self):
self.screen.blit(self.font.render('Hello!', True, black), (200, 100))
pygame.display.update()
def addText2(self):
self.screen.blit(self.font.render('Hello!', True, red), (200, 100))
pygame.display.update()
def functionApp(self):
if __name__ == '__main__':
self.addRect()
self.addText()
while True:
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:
self.screen.fill(white)
self.addRect()
self.addText2() #i made it so it only changes colour once.
display = Pane()
display.functionApp()
In your game loop, before drawing the new frame, fill the frame with the background color.
Example:
ball = pygame.Rect(0,0,10,10)
while True:
mainSurface.fill((0,0,0))
pygame.draw.circle(display,(255,255,255),ball.center,5)
ball.move_ip(1,1)
pygame.display.update()
The key point is the mainSurface.fill which will clear the previous frame.
Related
This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
I ran into a problem that if I run my project it is not showing the image the image is very big so I resized it and it was not helping.
The Code:
import pygame
import sys
def title(title):
pygame.display.set_caption(title)
def background(Color1, Color2, Color3):
pygame.draw.rect(screen, (Color1, Color2, Color3), pygame.Rect(0, 0, 2000, 3000))
pygame.display.flip()
screen = pygame.display.set_mode((1280, 720))
Card1Img = pygame.image.load('Card1.png')
Card1Img = pygame.transform.scale(Card1Img, (100,100))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
background(255, 255, 255)
title("Card-Jitsu")
screen.blit(Card1Img, (0, 0))
The Image is 1000 x 1126 px:
I did just want to make a copy of Card-Jitsu in python and pygame
The problem is that the display is not updating and drawing the image. You need to have the display update at the end of your while loop. The below code should work:
import pygame
import sys
def title(title):
pygame.display.set_caption(title)
def background(Color1, Color2, Color3):
pygame.draw.rect(screen, (Color1, Color2, Color3), pygame.Rect(0, 0, 2000, 3000))
#Having the display update here causes flickering
screen = pygame.display.set_mode((1280, 720))
Card1Img = pygame.image.load('Card1.png')
Card1Img = pygame.transform.scale(Card1Img, (100,100))
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit(0)
background(255, 255, 255)
title("Card-Jitsu")
screen.blit(Card1Img, (0, 0))
pygame.display.flip() #update the display after the image and background have been drawn
This question already has answers here:
Why is my PyGame application not running at all?
(2 answers)
Closed 1 year ago.
When running this code:
import pygame,time
GREEN = (30, 156, 38)
WHITE = (255,255,255)
pygame.init()
screen = pygame.display.set_mode((640, 480))
screen.fill(WHITE)
pygame.draw.rect(screen, GREEN, (0,0,100,100))
time.sleep(3)
Pygame shows a black screen for 3 seconds, but doesn't draw a rectangle.
I am using Atom using script package to run code
You have to implement an application loop. The typical PyGame application loop has to:
handle the events by 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 either pygame.display.update() or pygame.display.flip()
limit frames per second to limit CPU usage
import pygame
GREEN = (30, 156, 38)
WHITE = (255,255,255)
pygame.init()
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock()
# applicaition loop
run = True
while run:
# limit frames per second
clock.tick(60)
# event loop
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
# clear display
screen.fill(WHITE)
# draw objects
pygame.draw.rect(screen, GREEN, (0, 0, 100, 100))
# update display
pygame.display.flip()
pygame.quit()
exit()
Note, you must do the event handling. See pygame.event.get() respectively pygame.event.pump():
For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.
Update the screen with:
pygame.display.update()
at the end of your code you have posted.
You have to update the screen like that:
pygame.display.flip()
to render what you just drew.
Your code should look like this:
import pygame
import time
pygame.init()
GREEN = (30, 156, 38)
WHITE = (255,255,255)
screen = pygame.display.set_mode((640, 480))
# draw on screen
screen.fill(WHITE)
pygame.draw.rect(screen, GREEN, (0,0,100,100))
# show that to the user
pygame.display.flip()
time.sleep(3)
Off-topic: You should also get the events to allow the user to close the window:
import pygame
from pygame.locals import QUIT
import time
pygame.init()
GREEN = (30, 156, 38)
WHITE = (255, 255, 255)
screen = pygame.display.set_mode((640, 480))
clock = pygame.time.Clock() # to slow down the code to a given FPS
# draw on screen
screen.fill(WHITE)
pygame.draw.rect(screen, GREEN, (0, 0, 100, 100))
# show that to the user
pygame.display.flip()
start_counter = time.time()
while time.time() - start_counter < 3: # wait for 3 seconds to elapse
for event in pygame.event.get(): # get the events
if event.type == QUIT: # if the user clicks "X"
exit() # quit pygame and exit the program
clock.tick(10) # limit to 10 FPS
# (no animation, you don't have to have a great framerate)
Note that you must put all of this into a game loop if you want to repeat it like a classic game.
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.
You probably know what I want to do from the title but here's a simple example:
#User clicks somewhere in the pygame window
pos = cursorPosition()
#Function/Class that creates a square where the user clicked.
I have tried this:
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
create.cube()
screen.fill((0, 255, 0))
pygame.display.flip()
pygame.quit()
sys.exit()
But it just gives me a Blue screen and when I click anywhere it doesn't do anything, so if you can help me it would be much appreciated. Thanks!
EDIT: I've managed to do it but now I face another problem:
The square would appear only if I hold down the mouse button.
This is the code
import pygame
import sys
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
pos = pygame.mouse.get_pos()
class Create():
cx, cy = pygame.mouse.get_pos()
square = pygame.Rect(cx, cy, 50, 50)
def cube(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
pygame.draw.rect(screen, (255, 0, 0), self.square)
pygame.display.flip()
create = Create()
while running:
screen.fill((0, 255, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
create.cube()
pygame.display.flip()
pygame.quit()
sys.exit()
It's great to see that you are making a good effort to solve the by yourself, and that you are editing the question with the work you've done so far!
What I added to the code basically allows the user to change where the cube is being drawn. If you would like to draw multiple cubes, with their positions based on the mouse clicks from the user, edit your question to add those details, and leave a comment below.
First, I wrote a new class called Cube, which essentially has the same code as Create. I won't go into it in detail, but generally in object-oriented programming, objects are nouns, and their methods are actions. Your class is the opposite, which isn't how object-oriented code is generally written.
I added the update() method which simply updates some of the object's fields with the position of the mouse. Your original code was defining class fields or static variables. I won't go into to too much detail here, but if we were to make 100 instances of cube, we would want to have the positions for all the cubes, right? In cases like these, you are operating on the objects, not the class.
Then, there is one variable which gets set to true after the first mouse click, and, as a result, the cube starts being drawn to the screen.
Here is the fixed code:
import pygame
running = True
pygame.init()
screen = pygame.display.set_mode((800, 500))
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx, self.cy, 50, 50)
def draw(self):
pygame.draw.rect(screen, (255, 0, 0), self.square)
cube = Cube()
drawing_cube = False
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
cube.update()
drawing_cube = True
screen.fill((0, 255, 0))
if drawing_cube:
cube.draw()
pygame.display.flip()
pygame.quit()
quit()
I hope this answer helped you, and if you have any further questions, please feel free to leave a comment below!
I have also come across this problem and after a lot of messing around and frustration came up with the following:
import sys
import pygame
import time
pygame.init()
white = (255, 255, 255)
red = (255, 0, 0)
size = (700, 500)
screen = pygame.display.set_mode(size)
pygame.display.set_caption("OwO")
mouse_cords = []
clicked = False
def draw(cord_list, zero):
''' This is what will draw on the screen when the mouse clicks using recursion'''
pygame.draw.circle(screen, red, cord_list[zero], 100, 1)
zero += 1
if len(cord_list) > zero:
draw(cord_list, zero)
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(white)
if pygame.mouse.get_pressed()[0]:
mouse_cords.append(pygame.mouse.get_pos())
clicked = True
if clicked == True:
draw(mouse_cords, 0)
pygame.display.flip()
clock.tick(60)
pygame.quit()
As you can tell I used recursion to solve this problem. Sorry it's circles not boxes but Im sure you can figure out how to change that.
I am a beginner developer and my method is probably not the most efficient, however it does work. I know that I am writing 2 years late, but I am writing this incase anyone has the same question as I did which is to create multiple rectangles, squares or circles with a mousebutton press or in general any event.
I implemented a class to create a Cube object just like Michael O'Dwyer wrote in his explanation, and while his solution works to create one cube at a time, I needed to create multiple for myself.
In addition to his solution, I just created a list "cubeList" and with each mousebutton event I created a new cube object and appended it to that cubeList. Then, I used a for loop in order to iterate through each cube object in the cubeList and used the draw method. This way, I am able to have multiple cubes drawn at the same time, and I am sure there might be a more efficient or better method to do this, but this worked for me.
import pygame
WIDTH, HEIGHT = 900, 500
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLUE = (0,0,255)
Square1 = pygame.Rect(30,30,60,60)
Square2 = pygame.Rect(90,30,60,60)
class Cube:
def update(self):
self.cx, self.cy = pygame.mouse.get_pos()
self.square = pygame.Rect(self.cx - 25, self.cy - 25, 50, 50)
def draw(self):
pygame.draw.rect(WIN, GREEN, self.square)
def main():
cubeCount = 0
run = True
cubeList = []
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
print("Ending")
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
cube = Cube()
cubeList.append(cube)
cube.update()
clock.tick(60)
WIN.fill((BLUE))
pygame.draw.rect(WIN,RED, Square1)
pygame.draw.rect(WIN, GREEN, Square2)
for x in cubeList:
x.draw()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
main()
This question already has an answer here:
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
Basically, here is a section of my code in Pygame:
button_text=pygame.font.Font("C:\Windows\Fonts\Another Danger - Demo.otf",35)
textSurface,textRect=text_objects("Start game",button_text)
textRect.center=(105,295)
screen.blit(textSurface,textRect)
This is the text I'd like to turn into a clickable format, so that when someone presses the text, it can run a function, such as running the next thing possible.
Any help would be greatly appreciated.
Thanks.
Get the rect from the surface that font.render returns and use it for collision detection and the blit position.
import sys
import pygame as pg
def main():
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
font = pg.font.Font(None, 30)
text_surface = font.render('text button', True, pg.Color('steelblue3'))
# Use this rect for collision detection with the mouse pos.
button_rect = text_surface.get_rect(topleft=(200, 200))
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
# Use event.pos or pg.mouse.get_pos().
if button_rect.collidepoint(event.pos):
print('Button pressed.')
screen.fill((40, 60, 70))
screen.blit(text_surface, button_rect)
pg.display.flip()
clock.tick(30)
if __name__ == '__main__':
pg.init()
main()
pg.quit()
sys.exit()
PyGame does not have buttons, so what you can do here is get the mouse cursor position when clicking with pygame.mouse.get_pos(). If the mouse cursor position is inside the text then you know the text was selected.
Here is an example:
import pygame, sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((1000, 700))
clock = pygame.time.Clock()
tx, ty = 250, 250
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
quit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mouse = pygame.mouse.get_pos()
if mouse[0]in range (tx, tx + 130) and mouse[1] in range (ty, ty + 20):
print("You clicked on the text.")
myfont = pygame.font.SysFont("Marlett", 35)
textsurface = myfont.render(("Start game"), True, (230, 230, 230))
screen.blit(textsurface,(tx, ty))
pygame.display.update()
clock.tick(60)
In this example, I used tx and ty for sizes but you can use rect, it's the same thing.