I'm displaying two random images in my pygame project that need to change when pressing one "z" or "x" in my keyboard. So I've created a function to do so and the images are correctly showing and changing. My problem is with the if statement in the run function: when the condition are met the sound start playing, but the images don't change their transparency. This is my code:
class Main():
def __init__(self):
pygame.init()
self.window = pygame.display.set_mode((0,0), pygame.FULLSCREEN)
self.clock = pygame.time.Clock()
self.sound_one = pygame.mixer.Sound(os.path.join("soundone.mp3"))
self.sound_two = pygame.mixer.Sound(os.path.join("soundtwo.mp3"))
self.image_list = [] # a list with all the images
def show_image(self, image_one, image_two):
rect_one = image_one.get_rect(midleft=(50, 240))
rect_two = image_two.get_rect(midright=(640- 50, 240))
image_one.set_alpha(0)
image_two.set_alpha(0)
self.window.blit(image_one, rect_one)
self.window.blit(image_two, rect_two)
pygame.display.update()
return image_one, image_two
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == pygame.K_z:
self.one, self.two = self.show_image(random.choice(self.image_list), random.choice(self.image_list))
if event.key == pygame.K_x:
self.one, self.two = self.show_image(random.choice(self.image_list), random.choice(self.image_list))
self.window.fill((0,0,0))
if self.value <= 42:
self.one.set_alpha(50)
self.two.set_alpha(0)
self.sound_two.play(loops=0)
elif self.value > 53:
self.sound_one.play(loops=0)
self.one.set_alpha(0)
self.two.set_alpha(50)
elif 42 > self.value > 53:
self.one.set_alpha(0)
self.two.set_alpha(0)
self.clock.tick(30)
if __name__ == "__main__":
main = Main()
main.run()
How can I access the image created with a function to edit it? My code is not giving me back any error. It just doesn't work
You have to redraw the scene in every frame You must draw the images in the application loop and update the display in every frame:
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
run = True
if event.key == pygame.K_z:
self.one, self.two = random.choice(self.image_list), random.choice(self.image_list)
if event.key == pygame.K_x:
self.one, self.two = random.choice(self.image_list), random.choice(self.image_list)
self.window.fill((0,0,0))
rect_one = image_one.get_rect(midleft=(50, 240))
rect_two = image_two.get_rect(midright=(640- 50, 240))
self.window.blit(self.one, rect_one)
self.window.blit(self.two, rect_two)
pygame.display.update()
# [...]
pygame.quit()
sys.exit()
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()
Related
I am making a snake game, and I want to make sure that if you want to turn twice (for example a 180 degree turn), if both keys are pressed in the same frame, the next key press will be processed in the next frame, so that the snake actually turns twice over two frames instead of changing direction twice in the same frame, which could cause it to turn into itself and die. So basically, one turn per frame.
import pygame, sys
from pygame.locals import *
from sys import exit
import keyboard
import random
import time
class body:
def __init__(self,properties=[0,0,20,20],colour=-1):
self.properties=properties
self.colour=colour
self.next=None
class fruit:
def __init__(self,centre=[0,0],size=10):
self.centre=centre
self.size=size
def drawSnake(window,snake):
pygame.draw.rect(window,(0,0,0),snake.properties)
snake.colour=snake.colour*-1
temp=snake.next
while temp:
# Alternate snake colour
if temp.colour==-1:
colour=(0,150,0)
else:
colour=(0,100,0)
temp.colour=temp.colour*-1
pygame.draw.rect(window,colour,temp.properties)
temp=temp.next
return snake
def drawApple(window,snake,size):
numApples=500/(size*2)
bound=numApples-1
apple=fruit([(random.randint(0,bound)*(500/numApples))+size,(random.randint(0,bound)*(500/numApples))+size],size)
#apple=fruit([290,250],10)
pygame.draw.circle(window,"red",apple.centre,apple.size)
return apple
def newGame():
# Draw initial snake and apple
window.fill((255, 255, 255))
snake=body([240,240,20,20],-1)
snake=drawSnake(window,snake)
apple=drawApple(window,snake,10)
return snake,apple
def die(snake):
pygame.draw.rect(window,(180,0,0),[snake.properties[0],snake.properties[1],snake.properties[2],snake.properties[3]])
pygame.display.update()
time.sleep(1)
def getDirection(key,direction):
print(key)
if key == pygame.K_w:
if direction!=[0,20]:
direction=[0,-20]
if key == pygame.K_a:
if direction!=[20,0]:
direction=[-20,0]
if key == pygame.K_s:
if direction!=[0,-20]:
direction=[0,20]
if key == pygame.K_d:
if direction!=[-20,0]:
direction=[20,0]
return direction
def move(snake,apple,direction,length):
# New body piece location
x=snake.properties[0]+direction[0]
y=snake.properties[1]+direction[1]
# If snake crashed, restart
if x<0 or y<0 or x>480 or y>480:
die(snake)
snake,apple=newGame()
return snake,apple,0,False
# Check if collision with body
temp=snake
# Create new body piece with other colour and add to front of list
newBody=body([x,y,20,20],snake.colour*-1)
newBody.next=snake
snake=newBody
# If apple is eaten
if [x,y]==[apple.centre[0]-10,apple.centre[1]-10]:
# Add 1 to length, spawn new apple, do not remove end body piece
length+=1
apple=drawApple(window,snake,10)
while temp:
# Check if apple spawned in body
if temp.properties[0]==apple.centre[0]-10 and temp.properties[1]==apple.centre[1]-10:
apple=drawApple(window,snake,10)
temp=snake.next
temp=temp.next
else:
# Remove end body piece
temp=snake
while temp.next:
# Check if collision with body
if temp.next.properties[0]==x and temp.next.properties[1]==y:
die(snake)
snake,apple=newGame()
return snake,apple,0,False
previous=temp
temp=temp.next
pygame.draw.rect(window,"white",temp.properties)
previous.next=None
return snake,apple,length,True
# Make window
pygame.init()
window=pygame.display.set_mode((500, 500))
snake,apple=newGame()
length=0
delay=0.1
clock=pygame.time.Clock()
pygame.display.update()
prevEvents=[]
while True:
# Wait until a key is pressed to start the game
pressed_keys=pygame.key.get_pressed()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
# Key is pressed, get direction and start main game loop
direction=getDirection(event.key,[])
game=True
## MAIN GAME LOOP
while game:
# Set FPS
clock.tick(1)
# Get current event queue
events=pygame.event.get()
print("events1: ",events)
print()
# Add current event queue to previous events which were not processed as a key was pressed in the last frame
prevEvents.extend(events)
events=prevEvents
prevEvents=[]
print("events2: ",events)
print()
if events!=None:
i=1
for event in events:
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
# Key was pressed, get new direction of snake
direction=getDirection(event.key,direction)
# Save rest of event queue for next frame to process
prevEvents=events[i:len(events)+1]
print("prevEvents: ",prevEvents)
print()
# Make events nothing to exit this loop, move the snake and get to the next frame
events=[]
i+=1
# Move and draw snake
snake,apple,length,game=move(snake,apple,direction,length)
snake=drawSnake(window,snake)
pygame.display.update()
I am new to pygame, so any help is appreciated.
Store the keys pressed in a queue:
direction_queue = []
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
direction_queue.append('L')
if event.key == pygame.K_d:
direction_queue.append('R')
if event.key == pygame.K_w:
direction_queue.append('U')
if event.key == pygame.K_s:
direction_queue.append('D')
Process the keys one after the other in the application loop:
if direction_queue:
direction = direction_queue[0]
direction_queue.pop(0)
Minimal example:
import pygame
pygame.init()
COLUMNS, ROWS, TIESIZE = 20, 20, 20
window = pygame.display.set_mode((COLUMNS*TIESIZE, ROWS*TIESIZE))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 50)
snake_x, snake_y = 9, 9
key_map = {pygame.K_a: 'L', pygame.K_d: 'R', pygame.K_w: 'U', pygame.K_s: 'D'}
direction_map = {'L': (-1, 0), 'R': (1, 0), 'U': (0, -1), 'D': (0, 1)}
direction_queue = []
direction = 'R'
run = True
while run:
clock.tick(5)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key in key_map:
direction_queue.append(key_map[event.key])
text_surf = font.render(str(direction_queue), True, 'black')
if direction_queue:
direction = direction_queue[0]
direction_queue.pop(0)
snake_x = (snake_x + direction_map[direction][0]) % COLUMNS
snake_y = (snake_y + direction_map[direction][1]) % ROWS
window.fill("white")
for c in range (1, COLUMNS):
pygame.draw.line(window, "gray", (c*TIESIZE, 0), (c*TIESIZE, window.get_height()))
for r in range (1, ROWS):
pygame.draw.line(window, "gray", (0, r*TIESIZE), (window.get_width(), r*TIESIZE))
rect = pygame.Rect(snake_x*TIESIZE, snake_y*TIESIZE, TIESIZE, TIESIZE)
pygame.draw.rect(window, "red", rect)
window.blit(text_surf, (10, 340))
pygame.display.flip()
pygame.quit()
exit()
So i was messing around in computer science and starting actually getting some decent progress (for me) on a project that managed to last longer than 2 days.
I just want some help on what im doing wrong.
heres my code its like some fnaf spin off that im planning to add some watermelon enemy to. Im just confused on how to do this click detection
import pygame, random, time
import pygame_textinput
import prompts
pygame.init()
textinput = pygame_textinput.TextInputVisualizer()
font = pygame.font.SysFont("Comicsansms", 55)
display = pygame.display.set_mode((575, 375))
pygame.display.set_caption("Game")
clock = pygame.time.Clock()
pygame.key.set_repeat(200, 25)
room = pygame.image.load("assets/images/room.png")
dark = pygame.image.load("assets/images/dark.png")
light = pygame.image.load("assets/images/light.png")
mel = pygame.image.load("assets/images/waterelo.png")
tablet = pygame.image.load("assets/images/3.png")
cam1 = pygame.image.load("assets/images/winner1.png")
def wait(x):
time.sleep(x)
def insideimage(pos, rsurf):
refrect = rsurf.get_rect().move((100, 100))
pickedcol = display.get_at(pos)
return refrect.collidepoint(pos)
q = False
flash = False
while True:
display.fill((225, 225, 225))
display.blit(room, (0, 0))
events = pygame.event.get()
textinput.update(events)
for event in events:
if event.type == pygame.QUIT:
exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
flash = not flash
if event.key == pygame.K_SPACE:
q = not q
elif event.type == pygame.MOUSEBUTTONDOWN and q == True:
if cam1.rect.collidepoint(event.pos):
print("hi")
if q == True:
display.blit(tablet, (-75, -75))
display.blit(cam1, (450, 240))
elif flash == True:
display.blit(light, (70, 60))
else:
display.blit(dark, (80, 55))
pygame.display.update()
clock.tick(30)
##if event.type == pygame.KEYDOWN and event.key == pygame.K_RETURN:
See How do I detect collision in pygame?. A pygame.Surface has no rect attribute. Use get_rect() to get a rectangle with the size of the image and set the position with keyword arguments:
elif event.type == pygame.MOUSEBUTTONDOWN and q == True:
cam1_rect = cam1.get_rect(topleft = (450, 240))
if cam1_rect .collidepoint(event.pos):
print("hi")
I am using PyGame to create a game, and can't figure a clean way to switch between scenes and menus. I don't know if I need to create a scene class for each thing with its own update and render loop or just use while statements and functions (which I don't like that much as it is a little messy for me) It doesn't matter about my code, just the way to switch between a menu and the main game.
There are different strategies and it depends on what functionality you want. One simple way is to have each scene in a function that returns what the next scene should be. Then create a simple if-statement that switches between them in the main game loop.
import pygame
pygame.init()
SCENE_MENU = 0
SCENE_GAME = 1
SCENE_SHOP = 2
def menu(screen):
# Initialize game variables as the player, enemies and such.
fps_cap = 30
options = ['continue', 'save', 'quit']
clock = pygame.time.Clock()
# Game loop.
while True:
# Time management.
clock.tick(fps_cap)
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a: # Go to game if you press A.
return SCENE_GAME
elif event.key == pygame.K_b: # Go to shop if you press B.
return SCENE_SHOP
# Update the menu (like buttons, settings, ...).
print('Updating buttons:', *options)
# Draw the shop.
screen.fill((0, 0, 255)) # A green menu.
pygame.display.update()
def game(screen):
# Initialize game variables as the player, enemies and such.
fps_cap = 60
player = 'Ted'
clock = pygame.time.Clock()
# Game loop.
while True:
# Time management.
clock.tick(fps_cap)
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a: # Go to menu if you press A.
return SCENE_MENU
elif event.key == pygame.K_b: # Go to shop if you press B.
return SCENE_SHOP
# Update the game.
print(f'Player {player} is playing!')
# Draw your game.
screen.fill((0, 255, 0)) # A blue game.
pygame.display.update()
def shop(screen):
# Initialize game variables as the player, enemies and such.
fps_cap = 30
items = ['sword', 'armor', 'potion']
clock = pygame.time.Clock()
# Game loop.
while True:
# Time management.
clock.tick(fps_cap)
# Handle events.
for event in pygame.event.get():
if event.type == pygame.QUIT:
quit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_a: # Go to game if you press A.
return SCENE_GAME
elif event.key == pygame.K_b: # Go to shop if you press B.
return SCENE_SHOP
# Update the shop (like buttons, money transfers, ...).
print('Looking at items:', *items)
# Draw the shop.
screen.fill((255, 0, 0)) # A red shop.
pygame.display.update()
def main():
screen = pygame.display.set_mode((100, 100))
scene = SCENE_MENU
while True:
if scene == SCENE_MENU:
scene = menu(screen)
elif scene == SCENE_SHOP:
scene = shop(screen)
elif scene == SCENE_GAME:
scene = game(screen)
main()
This is just a simple example, but should show the principle.
I'm trying to animate a sprite using a loop such that each time the loop runs through the position number for an image in an array increases by one. I keep getting "UnboundLocalError: local variable 'Antic' referenced before assignment". There is
Antic = 0
Antic = int(Antic)
# Global constants
StAnmtn = ["Images/PlayerVampireStanding1.png", "
Images/PlayerVampireStanding2.png",
"Images/PlayerVampireStanding3.png","Images/PlayerVampireStanding4.png",
"Images/PlayerVampireStanding5.png", "Images/PlayerVampireStanding6.png",
"Images/PlayerVampireStanding7.png", "Images/PlayerVampireStanding8.png"]
`
at the start and
def main():
""" Main Program """
pygame.init()
clock = pygame.time.Clock() # creates clock to limit frames per
second
FPS = 60 # sets max speed of min loop
SCREENSIZE = SCREENWIDTH, SCREENHEIGHT = 1300, 700 # sets size of
screen/window
screen = pygame.display.set_mode(SCREENSIZE) # creates window and game
screen
pygame.display.set_caption("Count Acheron")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append( Level_01(player) )
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# 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 not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
if Antic > 6:
Antic = 0
else:
Antic += 1
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# 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()
if __name__ == "__main__":
main()
as the loop. What it doesn't seem to like is the snippet of code
if Antic > 6:
Antic = 0
else:
Antic += 1
How do I fix this?
Personally I've never used pygame's sprite module.
import pygame
class character:
def __init__(self, x, y):
self.x = x
self.y = y
self.sprites = [pygame.image.load("img1.png"), pygame.image.load("img2.png")]
self.frame = 0
def draw(self, surface):
surface.blit(self.sprites[self.frame], (self.x, self.y))
self.frame += 1
if self.frame > len(self.sprites) - 1: self.frame = 0
pygame.init()
DS = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
c = character(640, 360)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
c.draw(DS)
pygame.display.update()
clock.tick(30)
DS.fill((0, 0, 0))
Needed to globalise the function ("global Antic" in the main loop)
So my game was working fine but the sprite would not handle repeated key presses. I thought i fixed it but now i can't do anything once i get passed the start screen. The code where i think the problem is is under playgame(). If anyone knows that would be great!
import pygame
from Classes import PlaneClass
pygame.init()
import sys,random,os
from pygame.locals import*
#import pdb
menuscreen=pygame.display.set_mode((640, 480))#FULLSCREEN
def highscores():
WHITE=(255,255,255)
global menuscreen
highscoresFile= open('data/highscores.txt','r')
filecontentstoread=''
for line in highscoresFile:
filecontentstoread+=str(line)+'\n'
menuscreen.fill(WHITE)
my_font = pygame.font.SysFont('Courier', 20)
the_text = my_font.render(filecontentstoread, True, (0,0,0))
menuscreen.blit(the_text, (20, 40))
pygame.display.update()
def playgame():
BLACK=(0,0,0)#Define the color black, later used as backgound
plane_x=0 #Define the planes x and y coordinates
plane_y=0
gamescreen=pygame.display.set_mode((640, 480))#FULLSCREEN
gamescreen.fill(BLACK) #Fill screen with black, as background
plane_img=pygame.image.load('data/plane.png')
plane=PlaneClass(plane_x,plane_y,plane_img)
plane.move(plane_x,plane_y)
gamerunning=True
while gamerunning==True:
#Move plane according to keyboard input
keys=pygame.key.get_pressed()
if keys[K_LEFT]:
plane_x -=1
plane.move(plane_x,plane_y)
if keys[K_RIGHT]:
plane_x +=1
plane.move(plane_x,plane_y)
if keys[K_UP]:
plane_y -=1
plane.move(plane_x,plane_y)
if keys[K_DOWN]:
plane_y+=1
plane.move(plane_x,plane_y)
#gamescreen.fill(BLACK)
clock=pygame.time.Clock()
clock.tick(30)
def menu_screen_options():
menuvalue=main_menu()
laserstartup=pygame.mixer.Sound('data/laserstartup.wav')
laserstartup.play()
if menuvalue==0:
playgame()
if menuvalue==1:
highscores()
if menuvalue==2:
credits()
if menuvalue==3:
pygame.quit()
sys.exit()
def main_menu():
menuclock=pygame.time.Clock()
clock.tick(30)
pygame.display.set_caption('Dog Fight')
#pygame.mouse.set_visible(False)
WHITE=(255,255,255)
GREEN=(0,255,0)
BLUE=(0,0,255)
background=pygame.image.load('data/background.png')
lasersound=pygame.mixer.Sound('data/lasershot.wav')
arrow=pygame.image.load('data/arrow.png')
arrowpos = { 0 : (140,147) , 1:(140,210) , 2:(140,270) , 3 :(140,330) }
menu=True
counter = 0
menuscreen.blit(arrow,arrowpos[counter])
menuscreen.blit(background,(0,0))
pygame.display.update()
while menu == True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
menu = False
if event.key == K_UP:
if counter > 0:
counter -= 1
if event.key == K_DOWN:
if counter < 3:
counter += 1
if event.key == K_RETURN:
return counter
menuscreen.fill(WHITE)
menuscreen.blit(background,(0,0))
menuscreen.blit(arrow,arrowpos[counter])
pygame.display.update()
menu_screen_options()
Also, i dont know if this will help or not but the code for the sprite class is.
import pygame
class PlaneClass(pygame.sprite.Sprite):
# -- Methods
# Constructor function
def __init__(self,x,y,sprite_image):
self.image=sprite_image
self.x=x
self.y=y
pygame.sprite.Sprite.__init__(self)
def move(self,new_x,new_y):
screen=pygame.display.get_surface()
self.new_x=new_x
self.new_y=new_y
screen.blit(self.image,(new_x,new_y))
pygame.display.update()
You have that get_pressed call within a while True loop, so you never get back to the main event loop (the bit with for event in pygame.event.get():). This prevents your program from handling more events, which means that your program locks up.
Instead, you need to wait for a key event in your main event loop and only call get_pressed when you know there's a keypress to handle.
Note, you are using keydown polling. You might want keypress events instead. See: https://stackoverflow.com/a/11918084/341744