This question already has answers here:
Why doesn't PyGame draw in the window before the delay or sleep?
(1 answer)
How to wait some time in pygame?
(3 answers)
Closed 2 years ago.
I am trying to make a program that displays a still image(IM1) on a screen all the time, then when a gpio port(Relay 1) is brought to ground have a new image(IM2) pop up and alternate between IM2 and its counterpart(IM3). Here is my code as of now:
import RPi.GPIO as GPIO
import pygame
from pygame.locals import *
clock = pygame.time.Clock()
pygame.init()
clock.tick(60)
screen = pygame.display.set_mode((1080, 1920))
IM1 = pygame.image.load("/home/pi/Desktop/Slides/Logo.jpg")
IM2 = pygame.image.load("/home/pi/Desktop/Slides/Works-1.jpg")
IM3 = pygame.image.load("/home/pi/Desktop/Slides/Works-2.jpg")
GPIO.setmode(GPIO.BOARD)
Relay1 = 11
GPIO.setup(Relay1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
while(1):
if(GPIO.input(Relay1) == 0):
screen.blit(IM2, (0,0))
sleep(.5)
screen.blit(IM3, (0,0))
sleep(.5)
pygame.display.update()
else:
screen.blit(IM1, (0,0))
pygame.display.update()
#I can get IM1 to function but when Relay 1 is triggered only IM3 is displayed. I have tried using sprite and cant get that to work i was hoping to get this method to work.
You need to update the display after each blit. Do this:
screen.blit(IM2, (0,0))
pygame.display.update()
sleep(.5)
screen.blit(IM3, (0,0)
pygame.display.update()
sleep(.5)
The display is updated only if either pygame.display.update() or pygame.display.flip()
is called. See pygame.display.flip():
This will update the contents of the entire display.
Further you've to handles the events with pygame.event.pump(), before the update of the display becomes visible in the window.
See 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.
If you want to display an image and delay the game, then you've to update the display and handle the events.
screen.blit(IM2, (0,0))
pygame.display.flip()
pygame.event.pump()
pygame.time.delay(delay * 500) # 0.5 second == 500 milliseconds
Related
import pygame
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
fps = 60
screen_width = 864
screen_height = 936
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('Flappy Bird')
#define game variables
ground_scroll = 0
scroll_speed = 4
flying = False
game_over = False
#load images
bg = pygame.image.load('forest.png')
ground_img = pygame.image.load('ground.png')
Monkey = pygame.sprite.Sprite()
Monkey.image = pygame.image.load("monkey.png")
#boundaries
Monkey.rect = Monkey.image.get_rect()
x=400
y=200
movex=0
movey=0
#draw background
screen.blit(bg, (0,0))
#draw the ground
screen.blit(ground_img, (ground_scroll, 768))
while(True):
Monkey.rect.topleft=(x,y)
screen.blit(Monkey.image, Monkey.rect)
x=x+movex
y=y+movey
pygame.display.update()
event=pygame.event.poll()
if(event.type==pygame.QUIT):
break
elif(event.type==pygame.KEYDOWN):
#KEYDOWN means a key is pressed
if(event.key==pygame.K_RIGHT):
movex=3
elif(event.key==pygame.K_LEFT):
movex=-3
elif(event.key==pygame.K_UP):
movey=-3
elif(event.key==pygame.K_DOWN):
movey=3
elif(event.type==pygame.KEYUP):
movex=0
elif (event.type==pygame.KEYUP):
movey = 0
movex = 0
pygame.display.update()
pygame.quit()
This is my code, it's supposed to be a monkey in a forest and I want to be able to control it with the arrow keys without the monkey leaving black trail behind.For some reason every time I move the monkey, these black like leave a trail and cover the whole screen. I just can't figure out how to get rid of them.
So pygame is interesting in the way it implements animation. It is not moving your monkey but actually redrawing it over and over again on the same screen. What you need to do is redraw your background over and over on top of the old images.
<code>
#draw background
screen.blit(bg, (0,0))
#draw the ground
screen.blit(ground_img, (ground_scroll, 768))
while(True):
Monkey.rect.topleft=(x,y)
</code>
instead
<code>
while(True):
#draw background
screen.blit(bg, (0,0))
#draw the ground
screen.blit(ground_img, (ground_scroll, 768))
Monkey.rect.topleft=(x,y)
</code>
Generally you need to clean the whole screen and render all itens again for don't leave a black trail through the item was moved.
FPS = Frames Per Second. For each time that something move in a frame the frame need be deleted and a new frame need be render again, with the new position of the object, without It you just are rendering new object's movement without clean the previous and make that image of "black trail".
Solution: for each frame draw the background again, then ground, etc... You'll see that the game will be fine
CAUTION: you need find the right sequence of each event, with the wrong you will just see the background's color
This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 1 year ago.
Hey i am trying to make fruit catcher game in python using pygame but the fruits somehow get struck on screen(screenshot attached).The fruits and basket are getting screeched on the screen. I have also tried adding user defined events but then also the fruits images are getting screeched on the output screen. Can someone tell me what I am doing wrong?
import pygame
import time,random,sys
from pygame.locals import *
screenWidth=800
screenHeight=600
pygame.init()
screen=pygame.display.set_mode((screenWidth,screenHeight))
pygame.display.set_caption("Fruit Catcher")
white=(255,255,255)
black=(0,0,0)
red=(255,0,0)
pygame.mixer.init()
clock=pygame.time.Clock()
font=pygame.font.SysFont("City Blueprint",50)
smallfont=pygame.font.SysFont("City Blueprint",20)
class Basket(pygame.sprite.Sprite):
def __init__(self):
super(Basket,self).__init__()
self.image=pygame.image.load("basket.png").convert_alpha()
self.image=pygame.transform.scale(self.image,(100,70))
self.rect=self.image.get_rect()
self.rect.x=0
self.rect.y=screenHeight-100
def update(self,pressed_keys):
if pressed_keys[K_LEFT]:
self.rect.move_ip(-5,0)
if pressed_keys[K_RIGHT]:
self.rect.move_ip(5,0)
if self.rect.left<0:
self.rect.left=0
if self.rect.right>screenWidth:
self.rect.right=screenWidth
class Fruits(pygame.sprite.Sprite):
def __init__(self,img):
super(Fruits,self).__init__()
self.image=pygame.image.load(img).convert_alpha()
self.image=pygame.transform.scale(self.image,(20,20))
self.rect=self.image.get_rect()
self.rect.x=random.randrange(screenWidth)
self.rect.y=0
self.speed=random.randint(1,7)
def update(self):
self.rect.y+=self.speed
if self.rect.bottom>screenHeight:
self.kill()
fruitsgroup=pygame.sprite.Group()
allsprites=pygame.sprite.Group()
fruits=["apple.png","guava.png","strawberry.png"]
def createBasket():
basket=Basket()
allsprites.add(basket)
return basket
def createFruits():
fruit=Fruits(random.choice(fruits))
fruitsgroup.add(fruit)
allsprites.add(fruit)
return fruit
def start():
screen.blit(pygame.image.load("background.jpg"),(0,0))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
pressedkeys=pygame.key.get_pressed()
basket.update(pressedkeys)
fruitsgroup.update()
if random.randrange(100)<2:
createFruits()
allsprites.draw(screen)
clock.tick(30)
pygame.display.update()
start()
pygame.quit()
You have to clear the display or draw the background in the application loop. Loading an image is a very time consuming operation. Load the background image once before the application loop, but blit it continuously in the loop:
def start():
# load and scale background
background = pygame.image.load("background.jpg"))
background = pygame.transform.scale(background, (screenWidth,screenHeight))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
pressedkeys=pygame.key.get_pressed()
basket.update(pressedkeys)
fruitsgroup.update()
if random.randrange(100)<2:
createFruits()
# clear screen / draw background
screen.blit(background, (0, 0))
allsprites.draw(screen)
pygame.display.update()
clock.tick(30)
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 the frames per second to limit CPU usage with pygame.time.Clock.tick
Credit: https://stackoverflow.com/a/44686333/6660373
You need to add background before updating your fruits and basket.
add these two lines:
screen.fill((0,0,0))
screen.blit(pygame.image.load("background.jpg"),(0,0))
def start():
screen.blit(pygame.image.load("background.jpg"),(0,0))
fruitsgroup.empty()
allsprites.empty()
basket=createBasket()
while True:
for event in pygame.event.get():
if event.type==QUIT:
return
screen.fill((0,0,0)) # <--------------- here
screen.blit(pygame.image.load("background.jpg"),(0,0)) #<-----------here
pressedkeys=pygame.key.get_pressed()
This question already has answers here:
Lag when win.blit() background pygame
(2 answers)
Closed 2 years ago.
I want to make a (a bit bigger) game in PyGame, but even with this simple code I just get arround 10 fps instead of 60? Here's the code:
import pygame
res = 1280,720
display = pygame.display.set_mode(res, pygame.RESIZABLE)
pygame.display.set_caption("Test")
background = pygame.transform.smoothscale(pygame.image.load("Background.png"), res)
a = 0
while True:
pygame.time.Clock().tick(60)
display.fill((0,0,0))
a += 10
display.blit(background, (0,0)) #Without this line: arround 20 fps
pygame.draw.rect(display,(255,0,0), (a,8,339,205))
pygame.display.update()
pygame.quit()
What am I doing wrong?
Thank you!
Try the following optimizations:
Use the convert() method on your image pygame.image.load("Background.png").convert()). This makes the animation about 5 times faster.
Instead of re-blitting entire background every frame, only update the changed parts of the screen.
You don't need to clear the screen before drawing the background.
Use the same Clock instance every frame.
Here's the code:
import pygame
pygame.init()
res = (1280, 720)
display = pygame.display.set_mode(res, pygame.RESIZABLE)
pygame.display.set_caption("Test")
background = pygame.transform.smoothscale(pygame.image.load(r"E:\Slike\Bing\63.jpg").convert(), res)
a = 0
clock = pygame.time.Clock()
display.blit(background, (0, 0))
pygame.display.update()
while True:
clock.tick(60)
rect = (a,8,339,205)
display.blit(background, rect, rect) # draw the needed part of the background
pygame.display.update(rect) # update the changed area
a += 10
rect = (a,8,339,205)
pygame.draw.rect(display, (255,0,0), rect)
pygame.display.update(rect) # update the changed area
This question already has an answer here:
How to center an image in the middle of the window in pygame?
(1 answer)
Closed 6 months ago.
I am using python 2.7, I would like to know if there is a way to centre an image in pygame. I have set the screen to fullscreen, is this possible? If it helps i will attach the code, thanks.
import pygame
import os
_image_library = {}
def get_image(path):
global _image_library
image = _image_library.get(path)
if image == None:
canonicalized_path = path.replace('/', os.sep).replace('\\', os.sep)
image = pygame.image.load(canonicalized_path)
_image_library[path] = image
return image
pygame.init()
screen = pygame.display.set_mode((0, 0))
done = False
clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill((0, 0, 0))
screen.blit(get_image('sw.png'), (0, 0)
pygame.display.flip()
clock.tick(60)
Yeah, it's possible.
You have to create a rect object of the image:
image = "insert image"
rect = image.get_rect ()
And then:
rect.center = ("coordinates of center")
This StackOverflow question might be able to help you.
Pygame Image position
Basically though, you'd get the image rectangle. From there there are a lot of useful functions you can call to position it.
If I set a pygame window to resizable and then click and drag on the border of the window the window will get larger but nothing blit onto the surface will get larger with it. (Which is understandable) How would I make it so that when I resize a window all blit objects resize with it and fill the window properly?
For example: Say I have a window of 200 x 200 and I blit a button at window_width/2 and window_height/2. The button would be in the center of the window at 100 x 100. Now if I resize the window to 300 x 300 the button stays at 100 x 100 instead of 150 x 150.
I tried messing around with pygame.Surface.get_width ect, but had no luck.
Basically I'm trying to resize a program's window and have all blit images stay proportionate.
Don't draw on the screen directly, but on another surface. Then scale that other surface to size of the screen and blit it on the screen.
Here's a simple example:
import pygame
from pygame.locals import *
def main():
pygame.init()
screen = pygame.display.set_mode((200, 200),HWSURFACE|DOUBLEBUF|RESIZABLE)
fake_screen = screen.copy()
pic = pygame.surface.Surface((50, 50))
pic.fill((255, 100, 200))
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.display.quit()
elif event.type == VIDEORESIZE:
screen = pygame.display.set_mode(event.size, HWSURFACE|DOUBLEBUF|RESIZABLE)
fake_screen.fill('black')
fake_screen.blit(pic, (100, 100))
screen.blit(pygame.transform.scale(fake_screen, screen.get_rect().size), (0, 0))
pygame.display.flip()
main()
so without the gui initialization (pygame init, and setmode comands ) in the section where you have existing pygame event get()(which your only allowed one time (or just put in ''for inkey in pygame.event.get(VIDEORESIZE):''(
if you want to be redundant))(note you can only use ''for inkey in pygame.event.get(VIDEORESIZE):'' one time per loop because it is really a stack that unstacks when you read the event list so you should really use ''for inkey in pygame.event.get():'' snd put all your key recognission statements after this one occurrance of ''for inkey in pygame.event.get():'':
for inkey in pygame.event.get(VIDEORESIZE)
if inkey.type == pygame.VIDEORESIZE:
winwidth,winhight = inkey.size # or event.w, event.h
Window1copy = Window1.copy()# make copy of existing window
Window1=pygame.display.set_mode((winwidth,winhight),pygame.RESIZABLE)
Window1.blit(Window1copy, (0, 0))
pygame.display.update()
Recently with pygame2.0 You can use the SCALED flag