This question already has answers here:
Why is my pygame application loop not working properly?
(1 answer)
Pygame window freezes when it opens
(1 answer)
How to detect when a rectangular object, image or sprite is clicked
(1 answer)
Closed 2 years ago.
For my coursework for computer science I have to make a program but I've ran into issues that I can't find answers to.
Firstly in the section of code highlighted with *** I am trying to make the sprite character1 move which doesn't do anything when I press the arrow keys and don't know why
Secondly is the picture I am using as a button doesn't do anything when i click on it - highlighted with ###
I know my code isn't the most efficient but I'm trying to do what makes sense to me
import pygame
import random
import time
WIDTH = 1080
HEIGHT =720
FPS = 30
x1 = WIDTH/2.25
y1 = HEIGHT/2.5
x2 = WIDTH/20
y2 = HEIGHT/2.5
xbut = 800
ybut = 275
gameTitle = 'Hungry Ghosts'
xChange1 = 0
yChange1 = 0
xChange2 = 0
yChange2 = 0
#define colours
WHITE = (255,255,255)
BLACK = (0,0,0)
MEGAN = (123,57,202)
MOLLIE = (244,11,12)
KATIE = (164,12,69)
#initialise pygame and window
pygame.init()
pygame.mixer.init()
pygame.font.init()
screen =pygame.display.set_mode((WIDTH,HEIGHT))
pygame.display.set_caption('Hungry Ghosts')
clock = pygame.time.Clock()
#load immages
background_image = pygame.image.load(('purplesky.jpg'))
player1_image = pygame.image.load(('player 1.png')).convert_alpha()
player2_image = pygame.image.load(('player 2.png')).convert_alpha()
position = (0,0)
screen.blit(background_image, position)
startBut = pygame.image.load('button.jpg').convert()
#define functions
def textObjects(gameTitle, font):
textSurface = font.render(gameTitle,True, WHITE)
pygame.display.update()
return textSurface, textSurface.get_rect()
def titleText(gameTitle):
textForTitle = pygame.font.Font('VCR_OSD_MONO_1.001.ttf',115)
TextSurf, TextRect = textObjects(gameTitle, textForTitle)
TextRect.center = ((WIDTH/2),(HEIGHT/6))
screen.blit(TextSurf,TextRect)
pygame.display.update()
########################################
def titleButton(xbut,ybut):
screen.blit(startBut,(xbut,ybut))
pygame.display.update()
########################################
***************************************
def character1(x1,y1):
screen.blit(player1_image,(x1,y1))
pygame.display.update()
***************************************
def character2(x,y):
screen.blit(player2_image,(x,y))
pygame.display.update()
def homeScreen():
running = True
gameplay = False
instructions = False
home = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
################################################################
if event.type == pygame.MOUSEBUTTONDOWN:
xbut,ybut = event.pos
if startBut.get_rect().collidepoint(xbut,ybut):
print('clicked on button')
################################################################
def gameLoop():
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
pygame.display.flip()
*************************************************************************
#movement
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xChange1 = -5
elif event.key == pygame.K_RIGHT:
xChange1 = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
xChange1 = 0
x1 += xChange1
*************************************************************************
#calling functions
titleText(gameTitle)
character1(x1,y1)
character2(x2,y2)
titleButton(xbut,ybut)
homeScreen()
pygame.quit()
You have to do the movement and the drawing of the scene in the game loop.
an 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()
running = True
def homeScreen():
global running
start = False
home = True
while running and not start:
clock.tick(FPS)
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.MOUSEBUTTONDOWN:
if startBut.get_rect(topleft = (xbut, ybut)).collidepoint(event.pos):
print('clicked on button')
start = True
# draw background
screen.blit(background_image, (0, 0))
# draw scene
titleText(gameTitle)
titleButton(xbut,ybut)
# update display
pygame.display.flip()
homeScreen()
def gameLoop():
global running
global x1, y2, x2, y2, xChange1, yChange1, xChange2, yChange2
while running:
clock.tick(FPS)
# handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xChange1 = -5
elif event.key == pygame.K_RIGHT:
xChange1 = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
xChange1 = 0
# update position of objects
x1 += xChange1
# draw background
screen.blit(background_image, (0, 0))
# draw scene
character1(x1,y1)
character2(x2,y2)
# update display
pygame.display.flip()
gameLoop()
pygame.quit()
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!
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)
I am attempting to make a game where the 'player' (who spawns as the moon furthest to the right) can move around using the 'WASD' keys and enemies fall from the top of the screen in order to hit the player and end the game. I am currently doing this for an assignment and i have set up a test to see whether it is possible for me to do this and so far i have been able to create a 'player' object that is controllable by the 'WASD' keys and make a screen which requires players to press 'SPACE' to play the game. I am having trouble though with being able to have the enemies fall on the 'Y' axis down the screen smoothly. The picture moves down the screen only when the user presses or releases a key, this creates a jagged movement or when the user moves the mouse over the pygame screen, creating a very smooth movement.
#import necessary modules and pygame.
import pygame, sys, random
from pygame.locals import *
#set global variables
pygame.init()
WINDOWWIDTH = 800
WINDOWHEIGHT = 800
BACKGROUNDCOLOUR = (255,255,255)
TEXTCOLOUR = (0,0,0)
FPS = 30
ENEMYMINSIZE = 10
BOMBSAWAY = -1
ENEMYMAXSIZE = 40
ENEMYMINSPEED = 1
ENEMYMAXSPEED = 10
ADDNEWENEMYRATE = 5
PLAYERMOVERATE = 5
FSIZE = 48
BLUE = (0,0,255)
global PLAY
PLAY = False
global fpsClock
fpsClock = pygame.time.Clock()
# set up pygame and GUI
MainClock = pygame.time.Clock()
windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
windowSurface.fill(BACKGROUNDCOLOUR)
pygame.display.set_caption('Bubble Dash')
enemy = pygame.image.load('player.jpg')
char = pygame.image.load('player.jpg')
# set up fonts
basicFont = pygame.font.SysFont(None, 48)
# set up the text
text = basicFont.render('Press any key to play!', True, (255,255,0))
textRect = text.get_rect()
textRect.centerx = windowSurface.get_rect().centerx
textRect.centery = windowSurface.get_rect().centery
# draw the text onto the surface
# set up x and y coordinates
# music
windowSurface.blit(text, textRect)
def playgame(PLAY):
x,y = 0,0
movex,movey = 0,0
charx=300
chary=200
direction = 'down'
enemyx= 10
enemyy=10
while PLAY:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == ord('m'):
pygame.mixer.music.stop()
if event.key == ord('n'):
pygame.mixer.music.play()
if event.key == ord('a'):
movex = -0.5
if event.key == ord('d'):
movex = 0.5
if event.key == ord('w'):
movey = -0.5
if event.key == ord('s'):
movey = 0.5
if event.type ==KEYUP:
if event.key == ord('a'):
movex = 0
if event.key == ord('d'):
movex = 0
if event.key == ord('w'):
movey = 0
if event.key == ord('s'):
movey = 0
if direction == 'down':
enemyy += 7
windowSurface.fill(BLUE)
windowSurface.blit(char, (charx, chary))
windowSurface.blit(enemy, (enemyx, enemyy))
pygame.display.update()
charx+=movex
chary+=movey
def playertopresskey(PLAY):
while True: # main game loop
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_SPACE:
PLAY = True
if PLAY == True:
playgame(PLAY)
pygame.display.update()
playertopresskey(PLAY)
I would like for the 'enemy' object to be able to fall from the top without the user either needing to keypress or to key up or to have to move the mouse on the screen, rather the 'enemy' would just fall from the top as soon as the subroutine is called.
You may need to tweak it a bit because it is set up for me at the moment but i deleted a few things that would give you bother. Hopefully someone can help me. Thanks.
The below is link to a picture similar to mine which you can download and replace in the code for both the 'char' and the 'enemy' variables to view this yourself for i cannot access the courses at the present time.
http://www.roleplaygateway.com/roleplay/the-five-elements/characters/miss-joy/image
I found your error, you would have caught it yourself if you would have divided your code into some functions. Here is the problem:
for event in pygame.event.get():
if event.type == QUIT:
...
if event.type == KEYDOWN:
...
if event.type == KEYUP:
...
if direction == 'down':
enemyy += 7
your code moving the enemy is called only when an event is waiting in the queue. Move it out of the loop, and you will be good to go.
You have to change indention for:
if direction == 'down':
enemyy += 7
Now it is inside for event in pygame.event.get():