I have a simple game and I want my mouse click (button doesnt matter) to only register once per click. Right now it works even if it is held down.
def drawer(x, y):
pygame.draw.circle(screen, (0, 0, 0), [int(x), int(y)],20)
def main():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
exit()
if event.type == pygame.MOUSEBUTTONDOWN:
playerY_change = -player.vy
if event.type == pygame.MOUSEBUTTONUP:
playerY_change = player.vy
player.y += PlayerY_change
drawer(player.x, player.y)
# Other game code
pygame.display.update()
Right now the players movement keeps changing as long as you hold down the button where I want it to change only per click. How do I go about this?
Once the playerY_change is set, the player moves continuously. Therefore do not set playerY_change, but change the player.y when you click with the mouse:
def main():
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
player.y -= player.vy
drawer(player.x, player.y)
# Other game code
pygame.display.update()
pygame.quit()
exit()
Related
I was building a simple rocket game and it required moving some sprites. In the code below cloud1 is supposed to move -30 pixels towards the bottom each time i press the K_DOWN key. I have been trying to figure out what is wrong with the code for 3 days but haven't progressed even a little bit. Help would be much appreciated.
import pygame
pygame.init()
DISPLAY_HEIGHT = 700
DISPLAY_WIDTH = 900
screen = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption('Rocket Game')
clock = pygame.time.Clock()
FPS = 60
#colors
WHITE = (255,255,255)
BLACK = (0,0,0)
SKY_BLUE = (102,178,255)
cloud1 = pygame.image.load('cloud.png')
cloud1_X, cloud1_Y = 100, 50
cloud1_Y_change = 30
def cloud1_display(x, y):
screen.blit(cloud1, (x, y))
running = True
while running:
screen.fill(SKY_BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
cloud1_Y += cloud1_Y_change
cloud1_display(cloud1_X, cloud1_X)
clock.tick(FPS)
pygame.display.update()
There are two problems. The first is that your code is not checking the event.key for the pygame.K_UP. But your code is also painting the cloud at (x, x), not (x, y).
Corrected code:
while running:
screen.fill(SKY_BLUE)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP: # <<-- HERE
cloud1_Y += cloud1_Y_change
cloud1_display(cloud1_X, cloud1_Y) # <<-- AND HERE
clock.tick(FPS)
pygame.display.update()
For you main game loop try to use event.key instead of event.type for the second time. Like so:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
cloud1_Y += cloud1_Y_change
Another issue that I have noticed is that your not converting your image to a rect object in pygame and then use .blit to show it onscreen. The .blit function requires a rect object argument, so that's why your having issues.
cloud1 = pygame.image.load('asteroid_pic.bmp')
rect = cloud1.get_rect()
screen.blit(cloud1, self.rect)
I also recommend creating separate classes for your sprites, so that its easier to keep track of them and if you want to create duplicates of the same one but still retain the same characteristics of the single class sprite you can do so by importing the function Group from pygame.sprite.
I am trying to make a ship on the surface move continuously on screen but it only accepts one key press at a time. I have tried all solutions online and they aren't working.
import pygame
#initialize the pygame module
pygame.init()
#set the window size
screen = pygame.display.set_mode((1280, 720))
#change the title of the window
pygame.display.set_caption("Space Invaders")
#change the icon of the window
icon = pygame.image.load("alien.png")
pygame.display.set_icon(icon)
#add the ship to the window
shipx = 608
shipy = 620
def ship(x, y):
ship = pygame.image.load("spaceship.png").convert()
screen.blit(ship, (x,y))
running = True
while running:
#background screen color
screen.fill((0, 0, 0))
#render the ship on the window
ship(shipx,shipy)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
shipx -= 30
if keys[pygame.K_RIGHT]:
shipx += 30
pygame.display.update()
I'm still new to Pygame. How can I fix this?
Its a matter of Indentation. pygame.key.get_pressed() has to be done in the application loop rather than the event loop. Note, the event loop is only executed when
event occurs, but the application loop is executed in every frame:
running = True
while running:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
#<--| INDENTATION
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
shipx -= 30
if keys[pygame.K_RIGHT]:
shipx += 30
# [...]
The problem that I found is that your application is replying only on one key pressed, not on a continuous movement. When you set the pygame.key.set_repeat function like in the example below, everything should be running smoothly.
import sys
import pygame
#initialize the pygame module
pygame.init()
#set the window size
screen = pygame.display.set_mode((1280, 720))
# Images
ship_img = pygame.image.load("spaceship.png")
ship_rect = ship_img.get_rect()
def draw():
screen.blit(ship_img, ship_rect)
pygame.key.set_repeat(10)
while True:
#background screen color
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
ship_rect = ship_rect.move((-30, 0))
if keys[pygame.K_RIGHT]:
ship_rect = ship_rect.move((30, 0))
#render the ship on the window
draw()
pygame.display.update()
For me, if I need to move an object in Pygame continuously, a velocity variable can be assigned to control the speed.
Here is part of the code for my robot movement program inside of the game_on loop:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# Detect keyboard input on your computer check if it is the direction keys
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("Left arrow is pressed")
robotX_speed = -60
if event.key == pygame.K_RIGHT:
print("Right arrow is pressed")
robotX_speed = 60
if event.key == pygame.K_UP:
print("Up arrow is pressed")
robotY_speed = -60
if event.key == pygame.K_DOWN:
print("Down arrow is pressed")
robotY_speed = 60
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
print("Keystoke L/R has been released")
robotX_speed = 0
if event.type == pygame.K_DOWN or event.key == pygame.K_UP:
print("Keystoke Up/Down has been released")
robotY_speed = 0
# update the coordinates in the while loop
robotX += robotX_speed
robotY += robotY_speed
Hope these codes can help you!
So I created a Python game Tetris based on Youtube tutorial:
https://www.youtube.com/watch?v=zfvxp7PgQ6c&t=2075s
But the pygame.error: display Surface quit occurs.
I have tried to add "break", "sys.exit()", "QUIT" after the pygame.quit but does not work.
Does anyone know how to solve it? Here is the code: (You can skip to the def main_menu)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run == False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
current_piece.x -= 1
if not (valid_space(current_piece, grid)):
current_piece.x += 1
if event.key == pygame.K_RIGHT:
current_piece.x += 1
if not (valid_space(current_piece, grid)):
current_piece.x -= 1
if event.key == pygame.K_DOWN:
current_piece.y += 1
if not (valid_space(current_piece, grid)):
current_piece.y -= 1
if event.key == pygame.K_UP:
current_piece.rotation += current_piece.rotation + 1 % len(current_piece.shape)
if not (valid_space(current_piece, grid)):
current_piece.rotation -= 1
shape_pos = convert_shape_format(current_piece)
for i in range(len(shape_pos)):
x, y = shape_pos[i]
if y > -1:
grid[y][x] = current_piece.color
if change_piece:
for pos in shape_pos:
p = (pos[0], pos[1])
locked_positions[p] = current_piece.color
current_piece = next_piece
next_piece = get_shape()
change_piece = False
score += clear_rows(grid, locked_positions) * 10
draw_window(win, grid, score, last_score)
draw_next_shape(next_piece, win)
pygame.display.update()
if check_lost(locked_positions):
draw_text_middle(win, "You Lost!", 80, (255,255,255))
pygame.display.update()
pygame.time.delay(1500)
run = False
update_score(score)
def main_menu(win):
run = True
while run:
win.fill((0,0,0))
draw_text_middle(win, 'Press any key to play', 60, (255,255,255))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.display.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
main(win)
pygame.display.QUIT()
win = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption('Tetris')
main_menu(win)
Updated code:
def main_menu(win):
run = True
while run:
win.fill((0,0,0))
draw_text_middle(win, 'Press any key to play', 60, (255,255,255))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
if event.type == pygame.KEYDOWN:
main(win)
pygame.quit()
win = pygame.display.set_mode((s_width, s_height))
pygame.display.set_caption('Tetris')
main_menu(win)
In your main_menu loop you are telling it to loop while local boolean run == True. This is okay, but you should as people mentioned in the comments do a pygame.quit() and optionally quit() (closes the window) instead of the pygame.display.quit() and sys.exit() that you have right now.
The second problem occurs if you start the game by going into the main loop. I assume that the main loop runs your events function shown at the top?
Depending on how you have written the code, the boolean run in the event function is
local. This means that it will not change the value of the run you are using in your
main loop (nor change it in the main_menu loop). I would suggest to transfer into OOP and create a self.run boolean instead,
or else you need to make the boolean run global.
And you should in the event function write this instead of what you have now at the
top:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
quit()
Hope this helps!
I'm trying to make it so when the game over screen shows the user can press space to get back into the game. Currently, when a game over happens, it displays the game over screen but accepts no input or at least doesn't do anything with the input. For some context, the game is basically about moving left and right to avoid obstacles. Currently, I only have one obstacle, but I just have not gotten to that yet. Thanks!
import pygame
import random
import math
pygame.init()
screenWidth = 700
screenHeight = 800
x = screenWidth / 2
y = (screenHeight / 4) * 3
width = 50
height = 50
win = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Test Game")
bg = pygame.image.load("background.png").convert()
gameover = pygame.image.load("gameover.png").convert()
bgx = (screenWidth / 6) * 2
bgy = 0
clock = pygame.time.Clock()
class enemy():
def __init__(self,c,y,width,height):
self.c = c
self.y = y
self.width = width
self.height = height
self.vel = 5
def draw(self, win):
if self.c == 1:
self.x = 250
#250
elif self.c == 2:
self.x = 350
#350
else:
self.x = 450
#450
self.y += self.vel
pygame.draw.rect(win, (0,0,255), (self.x,self.y,self.width,self.height))
evil = enemy(random.randint(1,3),0,50,50)
#def redrawGameWindow():
# evil.draw(win)
# pygame.display.update()
running = True
gameOver = False
while running:
clock.tick(60)
while gameOver:
win.blit(gameover, (0,0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if pygame.event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
gameOver = True
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.quit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
x+=100
if event.key == pygame.K_LEFT:
x-=100
win.fill((0,0,0))
win.blit(bg, (bgx, bgy))
evil.draw(win)
dist = math.hypot(evil.x - x, evil.y - y)
if dist <= 50:
print("Game Over!")
running = False
gameOver = True
pygame.draw.rect(win, (255,0,0), (x,y,width,height))
pygame.display.update()
#redrawGameWindow()
while gameOver:
win.blit(gameover, (0,0))
pygame.display.update()
keys = pygame.key.get_pressed()
if keys[pygame.K_SPACE]:
gameOver = False
pygame.quit()
The main problem is that your game over scene is the loop behind the main while running: loop and there's no way to go back to the first loop when you reach it. When you touch the evil object, you set running = False, leave the main and enter the while gameOver: loop.
In this loop you also need to call pygame.event.pump(), otherwise the pygame.key.get_pressed() function doesn't work correctly and the window freezes after a while because the events are not handled. If you want to restart the game, you should rather use only the nested while gameOver loop. Actually, I would recommend that you restructure the scenes even more and use a finite state machine instead (here's an answer in which I use functions as scenes but check out the link in the comment below as well).
Here's a working version of your code. I've changed a few things and added comments to explain the changes.
while running:
# -----The game over scene.-----
while gameOver:
for event in pygame.event.get():
if event.type == pygame.QUIT:
# pygame.quit only uninitializes the pygame modules and
# doesn't quit the program.
pygame.quit()
# This will quit the whole program. You need to import sys.
sys.exit()
elif event.type == pygame.KEYUP: # event.type not pygame.event.type
if event.key == pygame.K_SPACE:
# Change it to False to break out of the loop.
gameOver = False
# Reset the game. You could reset the position of the
# `evil` object or instantiate a new one.
evil.x = 350
evil.y = 0
win.blit(gameover, (0,0))
pygame.display.update()
clock.tick(60) # You need to call tick in this loop as well.
# ------------------------------
# -----The main scene.-----
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYUP:
if event.key == pygame.K_RIGHT:
x += 100
elif event.key == pygame.K_LEFT:
x -= 100
win.fill((0,0,0))
win.blit(bg, (bgx, bgy))
evil.draw(win)
dist = math.hypot(evil.x - x, evil.y - y)
if dist <= 50:
print("Game Over!")
# running = False # This would stop the main loop.
gameOver = True
pygame.draw.rect(win, (255,0,0), (x,y,width,height))
pygame.display.update()
clock.tick(60)
# The other while loop was removed.
pygame.quit()
I am making a Pong game in Python. To do this, I am using pygame. I am trying to make an image move continuously on a keypress. I have tried multiple methods, but none have worked. here is my code for the movement:
import pygame, sys
from pygame.locals import *
import time
try: #try this code
pygame.init()
FPS = 120 #fps setting
fpsClock = pygame.time.Clock()
#window
DISPLAYSURF = pygame.display.set_mode((1000, 900), 0, 32)
pygame.display.set_caption('Movement with Keys')
WHITE = (255, 255, 255)
wheatImg = pygame.image.load('gem4.png')
wheatx = 10
wheaty = 10
direction = 'right'
pygame.mixer.music.load('overworld 8-bit.WAV')
pygame.mixer.music.play(-1, 0.0)
#time.sleep(5)
#soundObj.stop()
while True: #main game loop
DISPLAYSURF.fill(WHITE)
bign = pygame.event.get()
for event in bign:
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_d:
pygame.mixer.music.stop()
keys_pressed = key.get_pressed()
if keys_pressed[K_d]:
wheatx += 20
#events = pygame.event.get()
#for event in events:
# if event.type == pygame.KEYDOWN:
# if event.key == pygame.K_p:
# pygame.mixer.music.stop()
# time.sleep(1)
# pygame.mixer.music.load('secondscreen.wav')
# pygame.mixer.music.play()
DISPLAYSURF.blit(wheatImg, (wheatx, wheaty))
pygame.display.update()
fpsClock.tick(FPS)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
Indentation is normal, I am new to stackoverflow! I have an except, which is why the try is there. Thanks for the help!
This code will move the image down upon the down arrow key being pressed and up if the up arrow key is pressed (should you not be changing the Y-axis and wheaty if the user presses the down key rather than altering wheatx ?). Do similar for the other arrow keys.
while True:
DISPLAYSURF.fill(WHITE)
bign = pygame.event.get()
for event in bign:
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
pygame.mixer.music.stop()
if event.key == pygame.K_DOWN:
wheaty +=20
elif event.key == pygame.K_UP:
wheaty -= 20
DISPLAYSURF.blit(wheatImg, (wheatx, wheaty))
pygame.display.update()
fpsClock.tick(FPS)