I want to show a text on the screen when a variable changes to True. The Text "Game Over" is show for a very short period of time with this code but I disappears after less than one second.
import pygame
import random
import time
import math
# Initialize pygame
pygame.init()
# Create window (width, height)
screen1 = pygame.display.set_mode(((800, 600)))
ScreenHeight = screen1.get_height()
ScreenWidth = screen1.get_width()
#Game Over text
go_font = pygame.font.Font('freesansbold.ttf', 128)
go_text = "GAME OVER"
go_textX = 300
go_textY = 300
def show_gameover(go_textX, go_textY):
gameover_text = font.render(go_text, True, (105, 105, 105))
screen1.blit(gameover_text, (go_textY,go_textY))
# Variable to track gameover
gameover = False
while running:
if gameover:
show_gameover(go_textX, go_textY)
# Insert Background
screen1.blit(background, (0, 0))
i = 0
for obs in obstacle_list:
obs.spawn_obstacle()
obs.update_y()
outOfBounds = obs.out_of_bounds(playerX, playerY)
if outOfBounds:
obstacle_list.pop(i)
collision = obs.collision_detection(playerX, playerY)
if collision:
gameover = True
show_gameover(go_textX, go_textY) #Show Gameover-text
i += 1
# Update after each iteration of the while-loop
pygame.display.update()
You have to draw the text after the background. If you draw the text before drawing the background, it will be hidden from the background. Draw it just before updating the display. So it is drawn over all other objects in the scene.
while running:
# Insert Background
screen1.blit(background, (0, 0))
# [...]
if gameover:
show_gameover(go_textX, go_textY)
# Update after each iteration of the while-loop
pygame.display.update()
Related
I wrote a small code to try working with pygame for the first time, but I'm having trouble getting the game window to respond to any input at all including the exit button. No matter if I run the code through Sublime, VScode, or Python the window loads fine but the sprite takes no input (so fare I have only coded left) nor will the window close. If I want to close the window I have to close whatever editor/terminal I'm running the program through
import pygame
import os
pygame.display.set_caption("CyberPunk 3077")
WIDTH, HEIGHT = 900, 500
PLAYER, SIZE = 34, 34
WIN = pygame.display.set_mode((WIDTH,HEIGHT))
'''We have now created the window and it's size
Now lets create the background display'''
FPS = 60
VELOCITY = 3
WHITE = ((255, 255, 255))
MID_BORDER = pygame.Rect((WIDTH/2)-2.5, 0,5, HEIGHT) #this will place a solid line in the middle of the screen
Player_1 = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'player.png')), (PLAYER,SIZE))
P1 = pygame.transform.rotate(Player_1, 270)
Player_2 = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'enemy.png')), (PLAYER,SIZE))
P2 = pygame.transform.rotate(Player_2, 270)
SKY = pygame.transform.scale(pygame.image.load(os.path.join('skins', 'bg.png')), (WIDTH,HEIGHT))
#this will search our folder 'skins' for the file 'bg' to make our background
def draw(yellow, blue):
WIN.blit(SKY, (0,0))
pygame.draw.rect(WIN, WHITE, MID_BORDER)
WIN.blit(P1, (yellow.y, yellow.y))
WIN.blit(P2, (blue.x, blue.y))
#pygame starts tracking at the top left with 0,0
pygame.display.update()
def P1_moves(keys_pressed, yellow):
if keys_pressed[pygame.K_a] and yellow.x - VELOCITY > 0: #LEFT
yellow.x -= VELOCITY
'''this is the only instance of movement I have coded so far. Didn't want to continue if I can't even get 'left' to work '''
def main():
yellow = pygame.Rect(200, 250, 32, 32)
blue = pygame.Rect(650, 250, 32, 32)
run = True
clock = pygame.time.Clock()
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run == False
keys_pressed = pygame.key.get_pressed()
P1_moves(keys_pressed, yellow)
draw(yellow, blue)
pygame.quit()
if __name__ == "__main__":
main()
The keys_pressed[pygame.K_a] should be keys_pressed[pygame.K_A] (capital 'A').
Rabbid76 answered this problem in a comment.
run = False instead of run == False
WIN.blit(P1, (yellow.x, yellow.y)) instead of WIN.blit(P1, (yellow.y, yellow.y))
Rabbid76 Sep 15 at 18:18
This question already has answers here:
Why is nothing drawn in PyGame at all?
(2 answers)
Closed 1 year ago.
I'm fairly new to pymunk and I wanted to make physics engine for my future games, there's just a small problem, My code won't draw the circle that pygame is trying to visualize. Here's my code.
import pygame
import pymunk
import sys
def create_item(space):
body = pymunk.Body(1, 100, body_type = pymunk.Body.DYNAMIC)
body.position = (450, 50)
shape = pymunk.Circle(body, 80)
space.add(body, shape)
return shape
def draw_items(items):
for item in items:
pygame.draw.circle(screen, item_color, item.body.position, 80)
def quit():
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
def display_update():
screen.fill(bg_color)
clock.tick(FPS)
space.step(1/60)
pygame.display.flip()
# Constructor
pygame.init()
# Constants and Variables
WIDTH = 900
HEIGHT = 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
FPS = 60
clock = pygame.time.Clock()
# Colors
bg_color = 30, 30, 40
item_color = 200, 200, 200
# Pymunk Variables
space = pymunk.Space()
space.gravity = (0, 500)
items = []
items.append(create_item(space))
# Loops
def main():
running = True
while running:
quit()
display_update()
draw_items(items)
main()
I don't really know what the problem is here, it doesn't give me an error or something like that and I only get a clean blank canvas with my bg color.(also sorry for the bad comments)
You have to draw the objects before updating the display
def main():
running = True
while running:
quit()
screen.fill(bg_color)
draw_items(items)
pygame.display.flip()
clock.tick(FPS)
space.step(1/60)
You are actually drawing on a Surface object. If you draw on the Surface associated to the PyGame display, this is not immediately visible in the display. The changes become visibel, when the display is updated with either pygame.display.update() or pygame.display.flip().
The typical PyGame 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()
limit frames per second to limit CPU usage
I have a single battery image appearing once here and it moves from right to left then goes away. I want batteries constantly coming and going until the player hits one of them.
My question is how do I get the batteries to keep on coming until a player hits it? I want them to appear maybe 100 units apart.
from pygame import *
import os
import random
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d, %d" %(0, 0)
init()
#set screen size
size = width, height = 800, 600
screen = display.set_mode(size)
#set fonts
fontGame=font.SysFont("Times New Roman", 30)
fontBack=font.SysFont("Ariel", 30)
fontTitle=font.SysFont("Ariel", 100)
fontResearch=font.SysFont ("Times New Roman", 18)
#set button and page to 0
button = 0
page=0
#setting colours
BLACK = (0, 0, 0)
RED = (255,0,0)
GREEN = (0, 255, 0)
BLUE = (106,186,232)
#loading image
backgroundPic=image.load("Background.jpg")
backgroundGame=image.load("gameBackground.jpg")
backgroundGame=transform.scale(backgroundGame,(800,600))
battery=image.load("Battery.png")
battery=transform.scale(battery,(100,100))
backgroundx=0
playerPic=image.load("player.png")
playerPic=transform.scale(playerPic,(70,70))
batteryx=[]
#defining what is going to be shown on the screen
def drawScene(screen, button,page,locationx,locationy):
global batteryx
mx, my = mouse.get_pos() #will get where the mouse is
#if the user does nothing
if page==0:
draw.rect(screen, BLACK, (0,0, width, height))
screen.fill(BLACK)
rel_backgroundx= backgroundx % backgroundGame.get_rect().width
screen.blit(backgroundGame, (rel_backgroundx - backgroundGame.get_rect().width,0))
if rel_backgroundx < width:
screen.blit (backgroundGame, (rel_backgroundx,0))
screen.blit(playerPic,(locationx,locationy))
screen.blit(battery,(batteryx,420))
batteryx-=1
display.flip()
return page
#def collision (battery, playerPic):
#if battery.colliderect(playerPic):
#return True
#return False
running = True
myClock = time.Clock()
KEY_LEFT= False
KEY_RIGHT= False
KEY_UP= False
KEY_DOWN= False
locationx=0
jumping=False
accel=20
onGround= height-150
locationy=onGround
batteryx=random.randrange(50,width,10)
# Game Loop
while running:
button=0
print (KEY_LEFT, KEY_RIGHT)
for evnt in event.get(): # checks all events that happen
if evnt.type == QUIT:
running=False
if evnt.type == MOUSEBUTTONDOWN:
mx,my=evnt.pos
button = evnt.button
if evnt.type== KEYDOWN:
if evnt.key==K_LEFT:
KEY_LEFT= True
KEY_RIGHT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= True
KEY_LEFT= False
if evnt.key==K_UP and jumping==False:
jumping=True
accel=20
if evnt.key== K_DOWN:
KEY_DOWN= True
KEY_UP= False
if evnt.type==KEYUP:
if evnt.key==K_LEFT:
KEY_LEFT= False
if evnt.key==K_RIGHT:
KEY_RIGHT= False
if evnt.key==K_DOWN:
KEY_DOWN=False
if KEY_LEFT== True:
locationx-=10
backgroundx+=10
if KEY_RIGHT== True:
locationx+=10
backgroundx-=10
if jumping==True:
locationy-=accel
accel-=1
if locationy>=onGround:
jumping=False
locationy=onGround
#player cannot move off screen
if locationx<0:
locationx=0
if locationx>400:
locationx=400
#if collision(battery, playerPic)==True:
#screen.fill(BLACK)
page=drawScene(screen,button,page,locationx,locationy)
myClock.tick(60) # waits long enough to have 60 fps
if page==6: #if last button is clicked program closes
running=False
quit()
Create a list of rects which serve as the positions of the batteries. Use for loops to update the rects and blit the battery image at the rects. Remove rects that have left the screen and append new rects to create new batteries
import pygame as pg
pg.init()
screen = pg.display.set_mode((640, 480))
clock = pg.time.Clock()
BG_COLOR = pg.Color('gray12')
battery_image = pg.Surface((30, 50))
battery_image.fill(pg.Color('sienna1'))
# Append pygame.Rect objects to this list.
batteries = []
batteries.append(battery_image.get_rect(topleft=(700, 100)))
battery_speed = -5
battery_timer = 40
done = False
while not done:
for event in pg.event.get():
if event.type == pg.QUIT:
done = True
# A simple frame based timer.
battery_timer -= 1
if battery_timer <= 0:
battery_timer = 40
# After 40 frames a new rect gets appended to the list.
batteries.append(battery_image.get_rect(topleft=(700, 100)))
temp_list = []
# Iterate over the rects to update them.
for battery_rect in batteries:
battery_rect.x += battery_speed
# Rects with x <= 50 won't be appended to the temp_list.
if battery_rect.x > 50:
temp_list.append(battery_rect)
# Assign the list with the remaining rects to the batteries variable.
batteries = temp_list
# Blit everything.
screen.fill(BG_COLOR)
for battery_rect in batteries:
screen.blit(battery_image, battery_rect)
pg.display.flip()
clock.tick(30)
pg.quit()
I am trying to make a 'Runner' style game in PyGame (like Geometry Dash) where the background is constantly moving. So far everything works fine, but the rendering of the background images restricts the frame rate from exceeding 35 frames per second. Before I added the infinite/repeating background element, it could easily run at 60 fps. These two lines of code are responsible (when removed, game can run at 60+fps):
screen.blit(bg, (bg_x, 0)) |
screen.blit(bg, (bg_x2, 0))
Is there anything I could do to make the game run faster? Thanks in advance!
Simplified Source Code:
import pygame
pygame.init()
screen = pygame.display.set_mode((1000,650), 0, 32)
clock = pygame.time.Clock()
def text(text, x, y, color=(0,0,0), size=30, font='Calibri'): # blits text to the screen
text = str(text)
font = pygame.font.SysFont(font, size)
text = font.render(text, True, color)
screen.blit(text, (x, y))
def game():
bg = pygame.image.load('background.png')
bg_x = 0 # stored positions for the background images
bg_x2 = 1000
pygame.time.set_timer(pygame.USEREVENT, 1000)
frames = 0 # counts number of frames for every second
fps = 0
while True:
frames += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
quit()
if event.type == pygame.USEREVENT: # updates fps every second
fps = frames
frames = 0 # reset frame count
bg_x -= 10 # move the background images
bg_x2 -= 10
if bg_x == -1000: # if the images go off the screen, move them to the other end to be 'reused'
bg_x = 1000
elif bg_x2 == -1000:
bg_x2 = 1000
screen.fill((0,0,0))
screen.blit(bg, (bg_x, 0))
screen.blit(bg, (bg_x2, 0))
text(fps, 0, 0)
pygame.display.update()
#clock.tick(60)
game()
Here is the background image:
Have you tried using convert()?
bg = pygame.image.load('background.png').convert()
From the documentation:
You will often want to call Surface.convert() with no arguments, to create a copy that will draw more quickly on the screen.
For alpha transparency, like in .png images use the convert_alpha() method after loading so that the image has per pixel transparency.
I'm trying to create "end credits" like the ones at the end of a movie, using pygame. I've googled for other ways to achieve this using python, but I haven't found any yet.
I've almost achieved this with the following code: http://pastebin.com/nyjxeDYQ
#!/usr/bin/python
import time
import threading
import pygame
from pygame.locals import *
# Initialise pygame + other settings
pygame.init()
pygame.fastevent.init()
event_get = pygame.fastevent.get
pygame.display.set_caption('End credits')
screen = pygame.display.set_mode((1920, 1080))
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((255, 255, 255))
fontsize = 40
font = pygame.font.SysFont("Arial", fontsize)
x = 0
def main():
global x
credit_list = ["CREDITS - The Departed"," ","Leonardo DiCaprio - Billy","Matt Damon - Colin Sullivan", "Jack Nicholson - Frank Costello", "Mark Wahlberg - Dignam", "Martin Sheen - Queenan"]
going = True
while going:
events = event_get()
for e in events:
if e.type in [QUIT]:
going = False
if e.type in [KEYDOWN] and e.key == pygame.K_ESCAPE:
going = False
# Loop that creates the end credits
ypos = screen.get_height()
while ypos > (0 - len(credit_list)*50) and x == 0: # Loop through pixel by pixel, screenheight + height of all the textlines combined
drawText(credit_list,ypos)
ypos = ypos - 1
x = 1
pygame.quit()
def drawText(text,y):
for line in text:
text = font.render(line, 1, (10, 10, 10))
textpos = text.get_rect()
textpos.centerx = background.get_rect().centerx
background.blit(text, (textpos.x,y))
y = y + 45
# Blit all the text
screen.blit(background, (0, 0))
pygame.display.flip()
time.sleep(0.0001) # Sleep function to adjust speed of the end credits
# Blit white background (else all the text will stay visible)
background.fill((255, 255, 255))
screen.blit(background, (0, 0))
pygame.display.flip()
if __name__ == '__main__': main()
The problem is that the scrolling text is flickering. This is because I use a time.sleep()-function to control the speed of the scrolling. When I use a value like 0.04 sec, it works pretty well, but the text moves too slow and there is still a bit of flickering. When I use a much lower value, like: 0.001 sec, the text is moving at a speed that I like, but there is a lot more flickering going on.
There is another value I can use to adjust the speed of the scrolling: the number of pixels to move. But when I set this to anything higher than 1, the scrolling isn't smooth anymore.
Does anyone know a solution to this problem? I don't necessarily have to use pygame, I do have to use python though.
Many thanks in advance!
Albrecht
Here are some simpe rule you should follow that will help you with your problem:
Don't call pygame.display.flip() more than once per frame
Don't use time.sleep() to control the speed of something in your application
Use a Clock to control the framerate
Here's a cleaned up, minimal working example:
#!/usr/bin/python
import pygame
from pygame.locals import *
pygame.init()
pygame.display.set_caption('End credits')
screen = pygame.display.set_mode((800, 600))
screen_r = screen.get_rect()
font = pygame.font.SysFont("Arial", 40)
clock = pygame.time.Clock()
def main():
credit_list = ["CREDITS - The Departed"," ","Leonardo DiCaprio - Billy","Matt Damon - Colin Sullivan", "Jack Nicholson - Frank Costello", "Mark Wahlberg - Dignam", "Martin Sheen - Queenan"]
texts = []
# we render the text once, since it's easier to work with surfaces
# also, font rendering is a performance killer
for i, line in enumerate(credit_list):
s = font.render(line, 1, (10, 10, 10))
# we also create a Rect for each Surface.
# whenever you use rects with surfaces, it may be a good idea to use sprites instead
# we give each rect the correct starting position
r = s.get_rect(centerx=screen_r.centerx, y=screen_r.bottom + i * 45)
texts.append((r, s))
while True:
for e in pygame.event.get():
if e.type == QUIT or e.type == KEYDOWN and e.key == pygame.K_ESCAPE:
return
screen.fill((255, 255, 255))
for r, s in texts:
# now we just move each rect by one pixel each frame
r.move_ip(0, -1)
# and drawing is as simple as this
screen.blit(s, r)
# if all rects have left the screen, we exit
if not screen_r.collidelistall([r for (r, _) in texts]):
return
# only call this once so the screen does not flicker
pygame.display.flip()
# cap framerate at 60 FPS
clock.tick(60)
if __name__ == '__main__':
main()