So right now I am learning pygame and I'm using sentdex's tutorials. On I believe his 6th pygame tutorial he showed us how to generate more than just one block. I added the code, but it didin't work. I don't understand why it didn't work? Could you please tell me what I'm doing wrong and how to fix it?
Here's the code:
import pygame
import random
pygame.init()
white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
window_width = 800
window_height = 600
gameDisplay = pygame.display.set_mode((window_width,window_height))
pygame.display.set_caption('MyFirstGame')
carImg = pygame.image.load("racecar.png")
clock = pygame.time.Clock()
def blocks(block_x, block_y, block_width, block_height, color):
pygame.draw.rect(gameDisplay, color, [block_x, block_y, block_width, block_height])
def crash():
print("YOUR GARBAGE! Press C to play again or Q to quit.")
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
pygame.quit
quit()
gameExit = True
if event.key == pygame.K_c:
gameLoop()
print("User has decided to play again")
def gameLoop():
# Defining variables to draw and move car
car_x = 350
car_y = 400
car_x_change = 0
car_w = 100
car_h = 100
# Defining variables to draw blocks
block_x = random.randrange(0, window_width)
block_y = -600
block_speed = 7
block_width = 100
block_height = 100
gameExit = False
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
car_x_change += -5
if event.key == pygame.K_RIGHT:
car_x_change += 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
x_change = 0
if event.key == pygame.K_RIGHT:
x_change = 0
car_x += car_x_change
gameDisplay.fill(white)
# blocks((block_x,block_y,[block_width,block_height,black))
blocks(block_x, block_y, block_width, block_height, black)
block_y += block_speed
gameDisplay.blit(carImg, (car_x,car_y))
if car_x >= window_width:
gameExit = True
crash()
if car_x <= 0:
gameExit = True
crash()
if car_y > window_height:
block_y = 0 - block_height
block_x = random.randrange(0,window_width-block_width)
pygame.display.update()
clock.tick(30)
gameLoop()
pygame.quit
quit()
One pair block_x, block_y can't be use to draw many blocks.
You have to create list with pairs (x,y) for all blocks which you want to draw. You have to use for loops to create blocks (pairs (x,y)), to move them, and to draw them.
BTW: running gameloop() inside crash() create recursion which is not prefered method.
My version with more information in comments # changed
import pygame
import random
# changed: better organized code
# --- constants --- (UPPERCASE_NAMES)
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,0,0)
WINDOW_WIDTH = 800
WINDOW_HEIGHT = 600
# --- functions --- (lowercase_names)
def blocks(points, width, height, color):
# changed: use `for` to draw all blocks
for x, y in points:
pygame.draw.rect(display, color, [x, y, width, height])
def crash():
print("YOUR GARBAGE! Press C to play again or Q to quit.")
# changed: return `True/False` insted of executing gameloop()
# because it was not good idea
while True:
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_q:
return True # True = quit
if event.key == pygame.K_c:
print("User has decided to play again")
return False # false = continue
def gameloop():
# --- objects ---
car_image = pygame.image.load("racecar.png")
# Defining variables to draw and move car
car_x = 350
car_y = 400
car_x_change = 0
car_w = 100
car_h = 100
# BTW: you could use `pygame.Rect` to keep position and size
# car_rect = car_image.get_rect(x=350, y=450)
# Defining variables to draw blocks
block_speed = 7
block_width = 100
block_height = 100
# changed: create list with points x,y
pairs = []
for _ in range(10):
x = random.randrange(0, WINDOW_WIDTH)
y = -block_height
pairs.append( (x, y) )
# --- mainloop ---
clock = pygame.time.Clock()
gameExit = False
while not gameExit:
# --- events ---
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
car_x_change -= 5
elif event.key == pygame.K_RIGHT:
car_x_change += 5
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
car_x_change += 5 # changed: wrong variable, use +=
elif event.key == pygame.K_RIGHT:
car_x_change -= 5 # changed: wrong variable, use -=
# --- updates ---
# changed: all moves before draws
# move car
car_x += car_x_change
# changed: one `if` for both crashes (`car_x`)
if car_x < 0 or car_x >= WINDOW_WIDTH:
# changed: use value from crash to set gameExit
# and to move car to start position
gameExit = crash()
if not gameExit:
car_x = 350
car_y = 400
# changed: use `for` to move all points
# and to check if they need new random place
# move blocks
moved_pairs = []
for x, y in pairs:
y += block_speed
if y > WINDOW_HEIGHT:
y = -block_height
x = random.randrange(0, WINDOW_WIDTH - block_width)
moved_pairs.append( (x, y) )
pairs = moved_pairs
# --- draws ---
# changed: all draws after moves
display.fill(WHITE)
blocks(pairs, block_width, block_height, BLACK)
display.blit(car_image, (car_x, car_y))
pygame.display.update()
# --- FPS ---
clock.tick(30)
# --- main ---
pygame.init()
display = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption('MyFirstGame')
gameloop()
pygame.quit() # changed: forgot ()
Related
I'm attempting to detect a collision between two objects (both images).
I have rect's for both the objects, but cannot get the collision to be detected.
I've attempted to use rect's, comparing x and y positions.
import sys
import pygame
from pygame.locals import *
#init pygame
pygame.init()
window_width = 840
window_height = 650
size = (window_width, window_height)
screen = pygame.display.set_mode(size)
bg_img = pygame.image.load("img.png").convert_alpha()
crash = False
bot1x = 150
bot1y = 100
x = (window_width * 0.45)
y = (450)
clock = pygame.time.Clock()
fr = clock.tick(30)
x_speed = 0
car_img = pygame.image.load("car.png").convert_alpha()
car_img = pygame.transform.scale(car_img, (125, 175))
bot_img = pygame.image.load("bot.png").convert_alpha()
bot_img = pygame.transform.scale(bot_img, (175, 200))
def car(x, y):
screen.blit(car_img, (x,y))
def bot(x, y):
screen.blit(bot_img, (x,y))
car_rect = pygame.Rect(x, y, 125, 175)
bot_rect = pygame.Rect(bot1x, bot1y, 175, 200)
#game loop
while(crash==False):
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == K_LEFT:
x_speed = -.9
print("Moving Left")
if event.key == K_RIGHT:
x_speed = .9
print("Moving Right")
if event.type == pygame.KEYUP:
if event.key == K_LEFT:
x_speed = 0
if event.key == K_RIGHT:
x_speed= 0
if event.type == pygame.QUIT:
crash = True
bot1y += .5
# Move car
x += x_speed
if car_rect.colliderect(bot_rect):
print("collision deceted")
#blit images to screen
screen.blit(bg_img, [0, 0])
#spawn car
car(x,y)
bot(bot1x, bot1y)
#flip game display
pygame.display.flip()
#end game
pygame.quit()
quit()
I expect the game to output "Collision detected" when the two objects touch eachother.
Thanks,
Lachlan
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 trying to make the character face the way the player presses the key on pygame in python I had been researching for a while and couldn't find what I can do. Basically I want the face or the direction of the character to face what the player press and for this game I only need left and right. Can someone give me so help? (This is what I have so far.)
import pygame
from pygame_functions import *
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("The Adventure of the Excorist's Meter")
black = (0,0,0)
white = (255,255,255)
clock = pygame.time.Clock()
# Set positions of graphics
background_position = [0, 0]
# Load and set up graphics.
background_image = pygame.image.load("skyline_background.jpg").convert()
crashed = False
character_img = pygame.image.load('character_left.png')
def player(x,y):
gameDisplay.blit(character_img, (x,y))
x = (display_width * 0.45)
y = (display_height * 0.65)
x_change = 0
player_speed = 0
while not crashed:
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
x_change = -5
elif event.key == pygame.K_RIGHT:
x_change = 5
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x_change = 0
x += x_change
# Copy image to screen:
gameDisplay.blit(background_image, background_position)
player(x,y)
pygame.display.update()
clock.tick(60)
pygame.quit()
quit()
Use two images in two variables character_left and character_right and assing correct image - ie. character_img = character_left - when you change direction.
You can load two different images or use pygame.transform.flip to create second (flipped) image.
Code could look like this (I didn't test it).
import pygame
# --- constants --- (UPPER_CASE_NAMES)
DISPLAY_WIDTH = 800
DISPLAY_HEIGHT = 600
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
FPS = 30
# --- classes --- (CamelCaseNames)
# empty
# --- functions --- (lower_case_names)
# empty
# --- main --- (lower_case_names)
# - init -
pygame.init()
gameDisplay = pygame.display.set_mode((DISPLAY_WIDTH, DISPLAY_HEIGHT))
pygame.display.set_caption("The Adventure of the Excorist's Meter")
# - objects -
background_image = pygame.image.load("skyline_background.jpg").convert()
background_position = [0, 0]
player_image_left = pygame.image.load('character_left.png').convert()
player_image_right = pygame.image.load('character_right.png').convert()
player_image = player_image_left
player_speed = 0
player_x = DISPLAY_WIDTH * 0.45
player_y = DISPLAY_HEIGHT * 0.65
player_x_change = 0
# - mainloop -
clock = pygame.time.Clock()
crashed = False
while not crashed:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
crashed = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player_x_change = -5
player_image = player_image_left
elif event.key == pygame.K_RIGHT:
player_x_change = 5
player_image = player_image_right
if event.type == pygame.KEYUP:
if event.key in (pygame.K_LEFT, pygame.K_RIGHT):
player_x_change = 0
# - updates -
player_x += player_x_change
# - draws -
gameDisplay.blit(background_image, background_position)
gameDisplay.blit(player_image, (player_x, player_y))
pygame.display.update()
clock.tick(FPS)
# - end -
pygame.quit()
I'm working on the basics of a game right now, but for some reason I cannot get my sprite to move. I know that it's registering when I'm pressing the key down, but the sprite for some reason just stays still.
import pygame
import sys
from pygame.locals import *
import time
pygame.init()
black = (0, 0, 0)
white = (255, 255, 255)
screen = pygame.display.set_mode((800, 600))
pygame.display.set_caption("RADICAL")
screen.fill(black)
imga = pygame.image.load('coina.png')
imgb = pygame.image.load('coinb.png')
sound = pygame.mixer.Sound('coin.mp3')
FPS = 80
imgx = 10
imgy = 10
pixMove = 10
steps = 0
x1 = 0
y1 = 0
keystate = pygame.key.get_pressed()
GameOver = False
while not GameOver:
screen.fill(white)
points = (steps)
font = pygame.font.SysFont(None, 30)
text = font.render('Score: '+str(points), True, black)
screen.blit(text, (0,0))
if steps % 2 == 0:
screen.blit(imga, (imgx, imgy))
else:
screen.blit(imgb, (imgx, imgy))
for event in pygame.event.get():
print event
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if keystate[pygame.K_UP]:
y1 -= pixMove
elif keystate[pygame.K_DOWN]:
y1 += pixMove
elif keystate[pygame.K_LEFT]:
x1 -= pixMove
elif keystate[pygame.K_RIGHT]:
x1 += pixMove
elif event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
x1 = 0
if event.key == pygame.K_UP or event.key == pygame.K_DOWN:
y1 = 0
steps +=1
if event.type == K_SPACE:
sound.play()
time.sleep(1)
sound.stop()
pygame.display.update()
fpsTime.tick(FPS)
Generally you blit() images on to the screen (pygame.display.set_mode()), for the changes to to reflect on the screen we call pygame.display.update(), In your case the game never comes the statement, which is out of while loop.
I have been coding a program, a survival game, on Python. I seem to have an issue with adding Images/Sprites. I am noticing the images blink. Any way to fix this?
import os
import pygame
import time
import random
from pygame.locals import *
launchLog = pygame.init()
print(launchLog)
white = (255,255,255)
black = (0,0,0)
red=(255,0,0)
blue=(0,0,255)
green=(0,255,0)
skin = (236,227,100)
size = 10
dependant = (green)
rate = 0.0018
weight = 100
bound_x = 600
bound_x2 = bound_x-size
bound_y = 600
bound_y2 = bound_y-size
screen = pygame.display.set_mode((bound_x,bound_y))
pygame.display.set_caption("Survival: EfEs Edition")
clock = pygame.time.Clock()
font = pygame.font.SysFont(None,25)
x = 300
y = 300
roundX = x
roundY = y
img=pygame.image.load("pewds.png")
def hmn(x,y,size):
clothes = pygame.draw.rect(screen,skin,[x,y,size,size-size*2])
snake = pygame.draw.rect(screen, red, [x,y,size,size])
def mesg(msg,color):
txt = font.render(msg, True, color)
screen.blit(txt, [x,y-30])
display.flip(img)
def gameLoop():
global x
global y
jump = 1
quitted = False
starved = 100
eaten = False
restart = False
lead_change = 0
lead_y = 0
randF_x = random.randrange(0,bound_x)
randF_y = random.randrange(0,bound_y)
didX2=round(randF_x/10.0)*10.0
didY2=round(randF_y/10.0)*10.0
while not quitted:
screen.blit(img,(x,y -15))
screen.blit(img,(x,y -15))
pygame.display.update()
hmn(x,y,size)
starved=starved-rate
#print(starved)
if starved<0:
screen.fill(white)
mesg("You died of hunger! Press R to restart.",red)
pygame.display.flip()
time.sleep(0.3)
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
starved = 100
pygame.display.update()
rate = 0.0018
x=300
y=300
for event in pygame.event.get():
#print(event)
if event.type == pygame.QUIT:
pygame.display.update()
quitted = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_a:
lead_change = -.2
elif event.key == pygame.K_d:
lead_change = .2
elif event.key == pygame.K_w:
lead_y = .2
elif event.key == pygame.K_s:
lead_y = -0.2
if event.type == pygame.KEYUP:
if event.key == pygame.K_d or event.key == pygame.K_a:
lead_change = 0
#print(x)
#print(y)
elif event.key == pygame.K_ESCAPE:
#print("Quitting")
quitted = True
elif event.key == pygame.K_w or event.key == pygame.K_s:
#print(y)
lead_y=0
x += lead_change
y -= lead_y
roundX = x
roundY = y
global roundX
global roundY
didX=round(roundX/10)*10
didY=round(roundY/10)*10
screen.fill(white)
s = pygame.draw.rect(screen, red, [bound_x2/15,bound_y2/20, starved * 2, 50])
pygame.draw.rect(screen, dependant, [didX2,didY2,10,10])
pygame.display.update()
#boundary script
if x>bound_x2:
x=bound_x2
elif x<-1:
x=-1
elif y<2:
y=2
elif y>590:
y=590
hmn(x,y,size)
pygame.display.flip()
if didX == didX2 and didY==didY2:
didX2 = round(random.randrange(0,bound_x)/10)*10
didY2 = round(random.randrange(0,bound_y)/10)*10
global dependant
dependant = green
global starved
starved = starved +0.01
global weight
weight = weight + 3
elif weight>150:
mesg("Weight increased! You now get hungry faster.",black)
pygame.display.update()
global rate
rate = rate+0.0008
pygame.display.update()
clock.tick(55)
mesg("Leaving game", black)
screen.blit(img,(x,y-15))
pygame.display.update()
time.sleep(2)
pygame.quit()
quit()
gameLoop()`
Please excuse the bad coding, the game is only in it's earliest state.
The correct sequence is to:
draw everything you want to show on a frame (all the blit()s, draw()s), etc.
do only one of display.update() with a list of all the changed regions OR display.flip() to update the whole screen once you've drawn everything
tl;dr - don't mix draw()s with update()s.