I'm making a game with pygame and want to show an introduction. My issue is I want the player to be able to click through each slide until the end, where it would transition to the game itself. Currently I have a loop where it goes through all of the slides immediately.
Is there a way I can format this so a player could click slide by slide? Thank you!
I've tried various types of looping and iteration. A work around I found was to make a ton of different while statements, e.g. "while intro1" go into "while intro2", but it is very cumbersome. I'm hoping there's a better way.
#introduction screen
while intro:
img1 = pygame.image.load("./sprites/img1.png")
img2 = pygame.image.load("./sprites/img2.png")
img3 = pygame.image.load("./sprites/img3.png")
img4 = pygame.image.load("./sprites/img4.png")
imgs = [img1, img2, img3, img4]
display_surface = pygame.display.set_mode((0, 0))
display_surface.blit(img1, (0, 0))
pygame.display.update()
events = pygame.event.get()
for event in events:
if event.type == pygame.MOUSEBUTTONUP:
for i in range(len(imgs)):
display_surface.blit(imgs[i], (0, 0))
i += 1
pygame.display.update()
if i >= 3:
intro = False
run = True
A bit of reorganizing is in order. First off, you will keep track of which image you are on using current_image. It is set to 0 before the loop, meaning we'll start at the first image.
The images themselves don't change on each pass through the loop. They only need to be loaded once BEFORE the loop.
You have too much in your for event in events: loop. In here you should do the bare minimum changes that a certain key press will change. So on click, we change the current_image to increase by 1 and that's it.
After everything, you blit the image to the screen and update. Hopefully this helps.
#introduction screen
current_image = 0
img_names = ["./sprites/img1.png", "./sprites/img2.png", "./sprites/img3.png", "./sprites/img4.png"]
imgs = [pygame.image.load(img) for img in img_names]
display_surface = pygame.display.set_mode((0, 0))
while intro:
events = pygame.event.get()
for event in events:
if event.type == pygame.MOUSEBUTTONUP:
current_image +=1
display_surface.blit(imgs[current_image], (0, 0))
pygame.display.update()
if current_image >= 3:
intro = False
run = True
Related
I'm making a game analyser, and I thought it would be nice if I had a user iterface instead of just using text and raw input to communicate. I am having problems with 'blitting' an image to my screen.
My image is inside the pycharm file called 'CATANYLISER' as is my code.
import pygame
pygame.init()
# py-game variables
(width, height) = (1000, 600)
window = pygame.display.set_mode((width, height))
window_title = pygame.display.set_caption('the CATANALYSER')
does_quit = False
# py-game images
empty_board = pygame.image.load('empty_board.png')
# py-game window loop
while not does_quit:
# receives input from window
for event in pygame.event.get():
# stops program when red x clicked
if event.type == pygame.QUIT:
does_quit = True
window.blit(empty_board, (0, 0))
pygame.display.update()
# activates when the loop finishes, just makes sure everything shuts down properly
pygame.quit()
The expected result is the image on the screen in the top left corner. However when I run the program, I have an empty screen (pygame.QUIT still works).
When I run this code there is no error message, and I am completely lost about how to fix this.
first, make sure that the empty_board.png is in your working directory.
Second, you have to clear the screen before each frame using window.fill([255, 255, 255])
Finally, you could try using pygame.display.flip() instead of update()
My code would look like:
import pygame
pygame.init()
window = pygame.display.set_mode([640, 480])
doQuit = False
board = pygame.image.load("empty_board.png")
while not doQuit:
window.fill([255, 255, 255])
window.blit(board, (0, 0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == pygame.QUIT:
doQuit = True
pygame.quit()
How do I convert an image to another image in pygame without using sprite class? Also how can I remove the previous image after I convert it to another one?
I wrote a small program today that shows how I switch an objects image(it may help/answer your question). It has notes for most of the code's use so it is easier to understand how and why it works(for all I know, anyone could have started programming yesterday).
Anyway, here is the code:
import pygame, sys
#initializes pygame
pygame.init()
#sets pygame display width and height
screen = pygame.display.set_mode((600, 600))
#loads images
background = pygame.image.load("background.png").convert_alpha()
firstImage = pygame.image.load("firstImage.png").convert_alpha()
secondImage = pygame.image.load("secondImage.png").convert_alpha()
#object
class Player:
def __init__(self):
#add images to the object
self.image1 = firstImage
self.image2 = secondImage
#instance of Player
p = Player()
#variable for the image switch
image = 1
#x and y coords for the images
x = 150
y = 150
#main program loop
while True:
#places background
screen.blit(background, (0, 0))
#places the image selected
if image == 1:
screen.blit(p.image1, (x, y))
elif image == 2:
screen.blit(p.image2, (x, y))
#checks if you do something
for event in pygame.event.get():
#checks if that something you do is press a button
if event.type == pygame.KEYDOWN:
#quits program when escape key pressed
if event.key == pygame.K_ESCAPE:
sys.exit()
#checks if down arrow pressed
if event.key == pygame.K_DOWN:
#checks which image is active
if image == 1:
#switches to image not active
image = 2
elif image == 2:
image = 1
#updates the screen
pygame.display.update()
I am not sure how your code is set up or if this is what you need (I don't entirely understand classes either so it might be a sprite class), but I hope this helps!
Converting one image to another is as simple as reassigning the variable
firstImage = pygame.image.load("firstImage.png")
secondImage = pygame.image.load("secondImage.png")
firstImage = secondImage
del secondImage
I'm not sure what exactly you mean by removing the image. You could use "del secondImage" to delete the reference in your code and send it to garbage collection. Once you clear the screen and blit the updated image there should no longer be any sign of the outdated image.
I'm making a basic game where I have a surface and everytime I click on the surface it moves 5 pixels to the right. The program is working just fine without the checkCollide(event) function, but when I put the that condition it doesn't move. What is wrong?
My code until now is this
import pygame, sys
from pygame.locals import *
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300,300))
def checkCollide(event):
k = 0
a,b = event.pos
x = P1[0].get_rect()
if x.collidepoint(a,b):
return True
return False
CP1 = [(150, 150)
,(155, 150)
,(160, 150)
,(165, 150)
,(170, 150)
,(175, 150)
,(180, 150)
,(185, 150)
,(190, 150)]
statp1_1 = 0
WHITE = (255,255,255)
DISPLAYSURF.fill(WHITE)
while True: # the main game loop
P1 = [pygame.image.load('PAzul.png'),CP1[statp1_1],statp1_1]
DISPLAYSURF.blit(P1[0], P1[1])
e = pygame.event.get()
for event in e:
if event.type == MOUSEBUTTONUP:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
statp1_1 +=1
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Thank you
Check your logic in these lines of your function:
x = P1[0][0].get_rect()
if x.collidepoint(a,b):
return True
return False
Your code hinges on this bit:
a = checkCollide(event)
if a:
DISPLAYSURF.fill(WHITE)
So you're never evaluating this piece to be true.
I just realized what was wrong. When I do x = P1[0].get_rect() it creates a surface with topleft at (0,0).
What I needed to do was change the position of the rectangle using x.topleft = P1[1]
I've got some tips for you. First store the rect in the P1 list (it contains only the image and the rect in the following example, but maybe you could also add the statp1_1 index to it). Now we can just move this rect, if the user clicks on it (in the example I set the topleft attribute to the next point). Read the comments for some more tips. One thing you need to fix is to prevent the game from crashing when the statp1_1 index gets too big.
import sys
import pygame
pygame.init()
DISPLAYSURF = pygame.display.set_mode((300, 300))
WHITE = (255, 255, 255)
# Don't load images in your while loop, otherwise they have to
# be loaded again and again from your hard drive.
# Also, convert loaded images to improve the performance.
P1_IMAGE = pygame.image.load('PAzul.png').convert() # or .convert_alpha()
# Look up `list comprehension` if you don't know what this is.
CP1 = [(150+x, 150) for x in range(0, 41, 5)]
statp1_1 = 0
# Now P1 just contains the image and the rect which stores the position.
P1 = [P1_IMAGE, P1_IMAGE.get_rect(topleft=CP1[statp1_1])]
clock = pygame.time.Clock() # Use this clock to limit the frame rate.
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONUP:
if P1[1].collidepoint(event.pos):
print('clicked')
statp1_1 += 1
# Set the rect.topleft attribute to CP1[statp1_1].
P1[1].topleft = CP1[statp1_1]
DISPLAYSURF.fill(WHITE)
DISPLAYSURF.blit(P1[0], P1[1]) # Blit image at rect.topleft.
pygame.display.update()
clock.tick(30) # Limit frame rate to 30 fps.
I have created some sort of menu navigation system in my game. All the screens are blitted in. The "Play" and "Quit" and "Controls" button works just fine but when I try to press menu from the controls screen, nothing happens. On the controls screen, you can faintly see the first menu screen from before. That might be the problem. I think that as the return to menu button is over the previous controls page button, it somehow is pressing the controls button from before. The button and menu segment of my code will be pasted here and the full thing will be pasted in a pastebin.
def text_to_button(msg,color,buttonx,buttony,buttonwidth,buttonheight,size = "small"):
textSurf, textRect = text_objects(msg,color,size)
textRect.center = ((buttonx + buttonwidth/2)), buttony+(buttonheight/2)
gameDisplay.blit(textSurf, textRect)
def button(text,x,y,width,height,inactive_color,active_color,size = "small",action = None):
cur = pygame.mouse.get_pos()
click = pygame.mouse.get_pressed()
#print(click)
if x + width > cur[0] > x and y + height > cur[1] > y:
pygame.draw.rect(gameDisplay, active_color,(x,y,width,height))
if click[0] == 1 and action != None:
if action == "quit":
pygame.quit()
quit()
if action == "controls":
game_controls()
if action == "play":
gameLoop()
if action == "main":
game_intro()
else:
pygame.draw.rect(gameDisplay, inactive_color,(x,y,width,height))
text_to_button(text,black,x,y,width,height,size)
def game_controls():
gcont = True
while gcont:
gameDisplay.blit(cont,(0,0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("Main Menu",320,500,150,50,white,gray,"tiny", action = "main")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
def game_intro():
intro = True
while intro:
gameDisplay.blit(imggg,(0,0))
button("Play",150,500,100,50,white,gray,"small",action = "play")
button("ControLs",320,500,150,50,white,gray,"tiny", action = "controls")
button("Quit",550,500,100,50,white,gray,"small", action = "quit")
pygame.display.update()
clock.tick(15)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_p:
intro = False
Full Code: https://pastebin.com/jrd82gkJ
You will have very hard time to debug your code in order to achieve the behavior you want for one simple reason:
The logic you use to switch between different screens providing different functionality is causing much trouble you can't directly see if you only run the game.
So you think: "oh ... how come the button doesn't work, there must be an issue with the button".
You are probably not aware of the fact that using functions having own while loops you go deeper and deeper into recursive calls with increasing recursion depth with each switch from one view to another - it is not how pygame is thought to be programmed.
I suggest you add some print() commands into your code to see in the console output that the code doesn't really do what you expect even if it appears to be OK at the first glance because it works.
Then I suggest you REWRITE your entire code so that you have one main while notGameExit: loop, and don't use any other looping in the helper functions. If you want use looping in your helper functions at least don't call from the helper functions another functions with own loops (and so on), but RETURN from them with an explicit return to avoid recursion.
If you leave the in the main loop called function with return your main loop will continue running and depending on some switches you can display in it different things on the screen and react differently to user actions.
Maybe looking at a minimal working pygame script showing "action" without usage of a loop you will gain better understanding and some deep "enlightenment" about how pygame works and then start a total rewrite of your game using another approach as this one you have used in the current code? Then come back with what you have achieved if you have further questions, but you won't probably have any, because it would be much easier to debug it yourself if the code will become more straightforward.
import pygame
pygame.init() # start PyGame (necessary because 'import pygame' doesn't start PyGame)
winDisplay = pygame.display.set_mode((1024, 768)) # set PyGame window size to 1024x768 pixel
pygame.display.set_caption("Minimal PyGame Test Script")
# Time in pygame is measured in milliseconds (1/1000 seconds) (defined by TIMER_RESOLUTION constant):
pygame.TIMER_RESOLUTION = 1000 # assure 1000 explicit, don't relay on default value
colorWhite = (255, 255, 255) # RGB color in Pygame format (valueRed=255, valueGreen=255, valueBlue=255)
colorRed = (255, 0, 0)
colorGreen = ( 0, 255, 0)
colorBlue = ( 0, 0, 255)
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorRed)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorGreen)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorBlue)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
winDisplay.fill(colorWhite)
pygame.display.update()
pygame.time.wait(3000) # show the Pygame window for 3 seconds
I am new into Python and pyGame and i have a problem with scaling an image.
I want to zoom an image in pygame.
The pygame documentation claims that
pygame.transform.scale()
should scale to a new resolution.
But in my example below it does not work - it crops the image instead of resizing it!?
What am i doing wrong?
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = pic.get_rect()
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, pic_position_and_size)
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.scale(pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()
pygame.transform.scale() does not work very well for your case. If you shrink a Surface by such a small amount, the algorithm just crops the last column and row of pixels. If you now repeat this process over and over again with the same Surface, you get the strange behaviour you see.
A better approach would be to keep a copy of your original Surface around, and use that for creating the scaled image. Also, using smoothscale instead of scale may also lead to a better effect; it's up to you if you want to use it.
Here's a "fixed" version of your code:
#!/usr/bin/env python3
# coding: utf-8
import pygame
from pygame.locals import *
# Define some colors
BLACK = (0, 0, 0)
pygame.init()
# Set the width and height of the screen [width, height]
screen = pygame.display.set_mode((1920, 1080))
org_pic = pygame.image.load('test.jpg').convert()
pic_position_and_size = org_pic.get_rect()
pic = pygame.transform.scale(org_pic, pic_position_and_size.size)
# Loop until the user clicks the close button.
done = False
# Clear event queue
pygame.event.clear()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == QUIT:
done = True
elif event.type == KEYDOWN:
if event.key == K_ESCAPE:
done = True
# background in black
screen.fill(BLACK)
# Copy image to screen:
screen.blit(pic, (0,0))
# Update the screen with what we've drawn.
pygame.display.flip()
pygame.display.update()
pygame.time.delay(10) # stop the program for 1/100 second
# decreases size by 1 pixel in x and y axis
pic_position_and_size = pic_position_and_size.inflate(-1, -1)
# scales the image
pic = pygame.transform.smoothscale(org_pic, pic_position_and_size.size)
# Close the window and quit.
pygame.quit()