I'm pretty new to coding. I was thrown straight into it by my (terrible) programming teacher. This is what I've got:
import pygame, sys, time
from pygame.locals import *
pygame.init()
clock = pygame.time.Clock()
screen = pygame.display.set_mode((800,600))
pygame.display.set_caption("Caldun")
bg = pygame.image.load("Background.png")
bg2 = pygame.image.load("BG2 clone.png")
bg3 = pygame.image.load("BG2 clone clone.png")
white = (255, 255, 255)
black = (0, 0, 0)
myfont = pygame.font.SysFont("Press Start 2P", 23)
label = myfont.render("Welcome to the land of Caldun.", 1, (255,255,255))
label2 = myfont.render("Click to continue", 1, (255,255,255))
running = 1
while running:
screen.fill((black))
screen.blit(bg,(0,0))
screen.blit(bg3,(37,30))
screen.blit(label, (65,420))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT or \
(event.type == pygame.KEYDOWN and
(event.key == K_ESCAPE)):
pygame.quit()
sys.exit()
if(event.type == pygame.KEYDOWN and
(event.key == K_SPACE)):
screen.blit(bg2,(37,30))
pygame.display.update()
What I'm trying to do is make it so that when you press spacebar, it will blit bg2 over bg3, and basically remove bg3 from the screen. For some reason, this isn't working out for me. What happens is that the screen kind of just flashes and shows bg2 for only a split second. I do realize that I have two pygame.display.update()s, and this is probably causing it, but I'm pretty lost. I'd appreciate it if I could get some pointers on what to do, or even how to clean up my code and where to go with it.
OK I've rewritten your main loop as follows to resolve the issue:
running = True
stage = 1
while running:
screen.fill(black)
screen.blit(bg, (0, 0))
screen.blit(label, (65, 420))
if stage == 1:
screen.blit(bg2, (37, 30))
else:
screen.blit(bg3, (37, 30))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT or \
(event.type == pygame.KEYDOWN and event.key == K_ESCAPE):
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN and event.key == K_SPACE:
stage += 1
The problem with your existing code is that it assumes the KEYDOWN event is sticky, that is it is reported each loop iterations while the key is held down, but this is not the case. To resolve this we use the stage variable to track the current state you want to display and update it whenever the space key is pressed.
As per you comment I've updated the code so you could use it to present a simple sequence. To add additional stages in the sequence just update the stage if test to support additional values, e.g:
if state == 1:
...render graphics for stage 1
elif state == 2:
...render graphics for stage 2
elif state == n:
...render graphics for stage `n`
else:
...render the final stage graphics
Related
I am building a small game in pygame and I wanted a function to exit out. However it takes multiple clicks to exit and it is not consistent either. Also the windows exit function is restarting the program, too Here is the part of the code that deals with exiting
if isKill:
pygame.mixer.music.stop()
gameover = myfont.render("Press R to Respawn", False, (255, 255, 255))
rect = gameover.get_rect()
rect.center = screen.get_rect().center
screen.blit(gameover, rect)
if event.type == KEYDOWN:
if event.key == K_r:
gameloop()
and
for event in pygame.event.get():
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
running = False
*gameloop() is the whole script
Instead of event.type, you can use the pygame builtin event QUIT
Refer the following code
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#Can use pygame.quit() in place of running=False if the above line doesn't work.
This while loop is the starting of gameloop. The contents of the gameloop should be inside it.
Don't call the gameloop() function inside the while loop
Perhaps use sys.exit to stop the program.
Try:
import sys
import pygame
while 1:
#code
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
In your game loop, you should always keep the loop running at one level. In your code, the respawn actually freezes the current level and reruns the game at a lower level. This is why several quit commands are required to exit the game.
When the player respawns, reset the game variables, then continue the game loop.
Update your code similar to this:
if isKill: # game is over
pygame.mixer.music.stop()
gameover = myfont.render("Press R to Respawn", False, (255, 255, 255))
rect = gameover.get_rect()
rect.center = screen.get_rect().center
screen.blit(gameover, rect)
if event.type == KEYDOWN:
if event.key == K_r:
#gameloop() # remove this
dospawn() # initialize\reset game variables here (can use same function at game start)
isKill = False # start new game
continue # skip rest of game process
Whenever I try to run my program it freezes up and crashes. I'm not a master pygame coder, but I'm almost sure its something to do with my main loop. It's supposed to allow the user to move left and right using arrow keys. I've tried adding a clock and changing the size of the screen but that didn't work. Here is the code:
import pygame
import sys
import random
import time
pygame.init()
screen = pygame.display.set_mode((500,500))
events = pygame.event.get()
clock = pygame.time.Clock()
x = 50
y = 50
game_over = False
while not game_over:
for event in events:
if event.type != pygame.QUIT:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
x += 5
elif event.key == pygame.K_LEFT:
x -= 5
else:
sys.exit()
screen.fill((0,0,0))
pygame.draw.rect(screen, (255,255,255), (x,y,50,50))
clock.tick(30)
pygame.display.update()
The code needs to process the event queue continuously, otherwise your operating environment will consider your window to be non-responsive (locked up). Your code is almost there, except it only fetches the new events once, but this needs to be done every iteration of the main loop.
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((500,500))
clock = pygame.time.Clock()
x = 50
y = 50
game_over = False
while not game_over:
events = pygame.event.get() # <<-- HERE handle every time
for event in events:
if event.type != pygame.QUIT:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
x += 5
elif event.key == pygame.K_LEFT:
x -= 5
else:
sys.exit()
screen.fill((0,0,0))
pygame.draw.rect(screen, (255,255,255), (x,y,50,50))
clock.tick(30)
pygame.display.update()
You cant do foe event in events, as when you call pygame.events.get(), you are updating them, you are updating them once and looping over them every frame, you need to use for event in pygame.event.get(): so you are calling the function every frame and updating the events every frame
unless you were trying to do this?
events = pygame.event.get
...
for event in events():
which does the same as above
Just to clarify, I have absolutely no idea what I'm doing, in fact I'm really not sure how I got this far. I wrote a bit of code to act as an auto clicker for a Minecraft farm (yes, I'm aware you can use much simpler methods). I've taken bits and pieces from various tutorials and have done some by myself. It is a bit of a mess. However, once the code runs and does the first click the pygame window shows not responding. I have no idea why. I would appreciate any advice and tips and it would be great if I could bet this problem fixed, thanks!
I think some of the code was messed up from me not knowing how to use this very well :(
import pygame
import keyboard
import time
import pyautogui
pygame.init()
def Click():
pyautogui.doubleClick(None, None, 1)
print('Click')
time.sleep(3)
def Img(x, y):
display_surface.blit(Piglin_Img, (x, y))
white = (255, 255, 255)
black = (0, 0, 0)
x = 280
y = 10
X = 400
Y = 100
Piglin_Img = pygame.image.load('Piglin.png')
pygame.display.set_icon(pygame.image.load("Icon.png"))
display_surface = pygame.display.set_mode((X, Y ))
pygame.display.set_caption('Gold Farm Auto Clicker')
font = pygame.font.Font('freesansbold.ttf', 20)
Start_Text = font.render('Press p to start...', True, black, white)
Run_Text = font.render('Running...', True, black, white)
Pause_Text = font.render('Paused', True, black, white)
Start_Text_pos = (10, 10)
Run_Text_pos = (10, 10)
Pause_Text_pos = (10, 10)
Continue_pos = (10, 40)
display_surface.fill(white)
display_surface.blit(Start_Text, Start_Text_pos)
Clicker = False
running = True
while running:
for event in pygame.event.get():
Img(x, y)
pygame.event.set_blocked(pygame.MOUSEMOTION)
pygame.event.set_blocked(pygame.MOUSEBUTTONDOWN)
pygame.event.set_blocked(pygame.MOUSEBUTTONUP)
if event.type == pygame.QUIT or \
event.type == pygame.KEYDOWN and \
event.key == pygame.K_z:
running = False
if event.type == pygame.KEYDOWN and \
event.key == pygame.K_p:
print('started')
display_surface.fill(white)
display_surface.blit(Run_Text, Run_Text_pos)
Img(x, y)
pygame.display.update()
Clicker = True
while Clicker:
if event.type == pygame.KEYDOWN and \
event.key == pygame.K_x:
Clicker = False
display_surface.fill(white)
display_surface.blit(Start_Text, Continue_pos)
display_surface.blit(Pause_Text, Pause_Text_pos)
Img(x, y)
pygame.display.update()
Click()
if event.type == pygame.KEYDOWN and \
event.key == pygame.K_x:
Clicker = False
display_surface.fill(white)
display_surface.blit(Start_Text, Continue_pos)
display_surface.blit(Pause_Text, Pause_Text_pos)
Img(x, y)
pygame.display.update()
pygame.display.update()
pygame.quit()
It's blocking the event queue processing when Clicker becomes True. So once clicker starts looping, no user-input is handled as this loop never re-examines the queue for new events, and just continues to re-process the same (old) event result.
You probably need to merge the event handling in the while Clicker cause into the main event loop. Maybe with an if Clicker on those events:
pygame.event.set_blocked(pygame.MOUSEMOTION)
pygame.event.set_blocked(pygame.MOUSEBUTTONDOWN)
pygame.event.set_blocked(pygame.MOUSEBUTTONUP)
while running:
# handle events and user interaction
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN : # some key was pushed
if event.key == pygame.K_p:
print('started')
Clicker = True # start the clicker
elif event.key == pygame.K_x:
print('stopped')
Clicker = False # stop the clicker
elif event.key == pygame.K_z:
running = False # Allow exit here too
# Update the screen
if Clicker:
# Click mode
display_surface.fill(white)
display_surface.blit(Run_Text, Run_Text_pos)
else:
# NOT in Click Mode
display_surface.fill(white)
display_surface.blit(Start_Text, Continue_pos)
display_surface.blit(Pause_Text, Pause_Text_pos)
Img(x, y)
pygame.display.update()
Something close to that anyway. Without comments, it's not immediately clear what the intention of the code is, so it's hard to create an exacting solution.
Using pygame and python 3.7, I have created a game in which an image at the center (250, 250) can be dragged around the screen and collide with a radius, in which case a break happens and the next image in the next loop spawns at the exact center, where the first image was located, as well. Despite the game working the way I intended, in principle, it behaves weirdly for fast mouse speed. In my minimal example code, the colored circles are supposed to reappear at the exact center, for every while-loop, however, they somehow don't update properly and therefore reappear not at the center of the screen, most of the time (they only do when I release the mouse-button really early / well-timed). I tested the game on windows and mac and noticed that on my mac, the "lag" seems to be even worse. If anybody knows how I could work around that, I'd be really thankful. Also, the game starts lagging and jumping to the next loop right away for really fast mouse movement, with which I have dealt by changing the speed of my external mouse. Is there an inherent fix for too fast mouse-movement in pygame? Thanks for all suggestions and maybe also other improvements to the idea of my code.
import pygame
import time
from time import sleep
import math
pygame.init()
gameDisplay = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
background_surface = pygame.Surface((500, 500))
background_surface.fill((255, 255, 255))
colors = [(0,0,0), (253, 45, 0), (249, 253, 0), (32, 201, 5), (0, 210, 235)]
for color in colors:
done = False
a, b = 250, 250
u, v = 250, 250
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEMOTION:
if event.buttons[0]:
a += event.rel[0]
b += event.rel[1]
rect = pygame.Rect(u, v, 0.001, 0.001)
radius = 200
corners = [rect.bottomleft, rect.bottomright, rect.topleft, rect.topright]
dist = [math.sqrt((p[0] - a) ** 2 + (p[1] - b) ** 2) for p in corners]
p_out = [i for i, d in enumerate(dist) if d > radius]
if any(p_out):
break
gameDisplay.blit(background_surface, (0, 0))
pygame.draw.circle(gameDisplay, color, (a,b), 50, 0)
pygame.draw.circle(gameDisplay, (0,0,0), (250,250), 200, 2)
pygame.display.flip()
sleep(0.7)
pygame.quit()
quit()
[...] they somehow don't update properly and therefore reappear not at the center of the screen, most of the time (they only do when I release the mouse-button really early / well-timed) [...]
Of course, investigate your code. The 1st thing what happens in your code is, that a and b are modified:
while not done:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEMOTION:
if event.buttons[0]:
a += event.rel[0]
b += event.rel[1]
If the pygame.MOUSEMOTION event is in the queue, then it is handled before the circle is drawn. So the position of the circle is modified and it does not appear in the center.
Note, an event does not reflect the current state of the mouse. It is a notification, which is stored in a queue when it happens, but then event handling may done later. What you actually do is to handle an event, which possibly occurred in the past.
Use a state dragging, which is False at the start of each loop. Set the state when the button is pressed (pygame.MOUSEBUTTONDOWN event) and reset it when the button is released (pygame.MOUSEBUTTONUP event):
for color in colors:
# [...]
dragging = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
dragging = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
dragging = False
elif event.type == pygame.MOUSEMOTION:
if dragging:
a += event.rel[0]
b += event.rel[1]
# [...]
I am a beginner of pygame. Recently I code a Pong game.
However, I cannot make paddles move when I press the certain keys in keyboard. Can someone helps me check the code. I think maybe I have some problems in giving paddles' new position. But I cannot fix it. And hopefully give me some hints about that.
Thanks!
Code below:
import pygame, sys, time,math
from pygame.locals import *
# User-defined functions
def main():
# Initialize pygame
pygame.init()
# Set window size and title, and frame delay
surfaceSize = (500, 400) # window size
windowTitle = 'Pong' #window title
frameDelay = 0.005 # smaller is faster game
# Create the window
pygame.key.set_repeat(20, 20)
surface = pygame.display.set_mode(surfaceSize, 0, 0)
pygame.display.set_caption(windowTitle)
# create and initialize red dot and blue dot
gameOver = False
color1=pygame.Color('white')
center1 = [250, 200]
radius1=10
score=[0, 0]
speed1=[4,1]
location1=[50, 150]
location2=[450, 150]
size=(5, 100)
position1=(0,0)
position2=(350,0)
rect1=pygame.Rect(location1,size)
rect2=pygame.Rect(location2,size)
# Draw objects
pygame.draw.circle(surface, color1, center1, radius1, 0)
# Refresh the display
pygame.display.update()
# Loop forever
while True:
# Handle events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
# Handle additional events
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
location1[1] =+ 1
if event.key == pygame.K_p:
location2[1] =+ 1
if event.key == pygame.K_a:
location1[1] =- 1
if event.key == pygame.K_i:
location2[1] =- 1
if event.type == pygame.KEYUP:
if event.key == pygame.K_q:
location1[1] =+ 0
if event.key == pygame.K_p:
location2[1] =+ 0
if event.key == pygame.K_a:
location1[1] =- 0
if event.key == pygame.K_i:
location2[1] =- 0
# Handle additional events
# Update and draw objects for the next frame
gameOver = update(surface,color1,center1,radius1,speed1,rect1,rect2,score,position1,position2)
# Refresh the display
pygame.display.update()
# Set the frame speed by pausing between frames
time.sleep(frameDelay)
def update(surface,color1,center1,radius1,speed1,rect1,rect2,score,position1,position2):
# Check if the game is over. If so, end the game and
# returnTrue. Otherwise, erase the window, move the dots and
# draw the dots return False.
# - surface is the pygame.Surface object for the window
eraseColor=pygame.Color('Black')
surface.fill(eraseColor)
moveDot(surface,center1,radius1,speed1,score,position1,position2)
pygame.draw.circle(surface,color1,center1,radius1,0)
r1=pygame.draw.rect(surface, color1, rect1)
r2=pygame.draw.rect(surface, color1, rect2)
if r1.collidepoint(center1) and speed1[0]<0:
speed1[0]=-speed1[0]
if r2.collidepoint(center1) and speed1[0]>0:
speed1[0]=-speed1[0]
def moveDot(surface,center,radius,speed,score,position1,position2):
#Moves the ball by changing the center of the ball by its speed
#If dots hits left edge, top edge, right edge or bottom edge
#of the window, the then the ball bounces
size=surface.get_size()
for coord in range(0,2):
center[coord]=center[coord]+speed[coord]
if center[coord]<radius:
speed[coord]=-speed[coord]
if center[coord]+radius>size[coord]:
speed[coord]=-speed[coord]
if center[0]<radius:
score[0]=score[0]+1
drawScore(center,surface,score,position2,0)
if center[0]+radius>size[0]:
score[1]=score[1]+1
drawScore(center,surface,score,position1,1)
def drawScore(center1,surface,score,position,whichscore):
FontSize=30
FontColor=pygame.Color('White')
String='Score : '
font=pygame.font.SysFont(None, FontSize, True)
surface1=font.render(String+str(score[whichscore]), True, FontColor,0)
surface.blit(surface1,position)
main()
You always use the rects rect1 and rect2 to draw your paddles. But to update their position, you try to change values in the lists location1 and location2.
Stop it. Just alter the rects. The easiest way is to use move_ip to change the rects in place.
Also, if you want to keep your paddles moving while the players keep the movement keys pressed, use pygame.key.get_pressed to get a list of all pressed keys (since pressing a key only generates a single KEYDOWN event, unless you mess with pygame.key.set_repeat, which you shouldn't).
So your code should look like this:
...
while True:
# Handle events
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pressed = pygame.key.get_pressed()
if pressed[pygame.K_q]: rect1.move_ip(0, -1)
if pressed[pygame.K_a]: rect1.move_ip(0, 1)
if pressed[pygame.K_p]: rect2.move_ip(0, -1)
if pressed[pygame.K_i]: rect2.move_ip(0, 1)
gameOver = ...
...