Trying to make random image blitting at random time in PYGAME - python

I have an interesting problem. I need to make such that image must appear every random time in a random place and if it collides with my GAMER it must affect GAMER(some function) with GAMER for exactly 3 sec and disappear and appear after a random time again.
. I have an idea but it does not work.(note: this is a part of code i already initialized everythiing)
clock = pygame.time.Clock()
FPS = 30
playtime = 0
newtime=random.randint(3,10)
while mainloop:
milliseconds = clock.tick(FPS)
seconds = milliseconds / 1000.0
playtime += seconds
if playtime>=newtime:
image.draw()
newtime=random.randint(2,6) #because next appear time must change
if collision(GAMER,image):
GAMER.do_something() #how to do it exactly for 3 sec?
image.far_away() #just dissapear for some time

When you talk about an image, then you talk about a pygame.Surface. A pygame.Surface can be blit() to the display (respectively the Surface which is associated to the window). For instance
screen.blit(image, image_rect)
You cannot move a surface far away. You have to draw the entire scene in every frame and you have to draw (blit) the image on the display surface in every frame.
You can change the position of the image. Create a random position when the time span exceeds:
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
When the player collides with the image, then set compute the time point 3 seconds in the future. Effect the player as long the 3 seconds are not exceeded:
if image_rect.colliderect(GAMER.rect):
affecttime = playtime + 3
if playtime < affecttime:
GAMER.do_something()
General process:
clock = pygame.time.Clock()
FPS = 30
newtime=random.randint(3,10)
playtime = 0
affecttime = 0
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
while mainloop:
milliseconds = clock.tick(FPS)
seconds = milliseconds / 1000.0
playtime += seconds
# handle events (event loop)
for event in pygame.event.get():
if event.type == pygame.QUIT:
mainloop = False
if playtime >= newtime:
newtime = playtime + random.randint(2,6)
position = random.randint(0, window_height), random.randint(0, window_width)
image_rect = image.get_rect(center = position)
if image_rect.colliderect(GAMER.rect):
affecttime = playtime + 3
position = .... # set position far away
image_rect = image.get_rect(center = position)
if playtime < affecttime:
GAMER.do_something()
# clear dispaly
scree.fill(0)
#draw image at the current position
screen.blit(image, image_rect)
# update disaply
pygame.display.update()

Related

Make stars blink in Pygame

The following code generates random x,y coordinates, appending the coordinates to a list, then runs a for-loop through the list to blit star images to the screen. The same stars are constantly being redrawn while the code is running, but they're in the same location, so the screen looks static. Here is the code.
import time
import pygame
from random import randint
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("My God, it's full of stars!")
med_star_img = pygame.image.load('images/medium_star.png')
tiny_star_img = pygame.image.load('images/tiny_star.png')
black = (0,0,0)
white = (255,255,255)
gray = (50,50,50)
tiny_stars_width = tiny_star_img.get_width()
tiny_stars_height = tiny_star_img.get_height()
med_stars_width = med_star_img.get_width()
med_stars_height = med_star_img.get_height()
tiny_stars_location = []
med_stars_location = []
clock = pygame.time.Clock()
running = True
gameDisplay.fill(gray)
# create random coordinates for stars
for i in range(25):
tiny_stars_location.append(pygame.Rect(randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height))
for i in range(10):
med_stars_location.append(pygame.Rect(randint(1,800),randint(1,600),med_stars_width,med_stars_height))
def make_med_star(x,y):
gameDisplay.blit(med_star_img, (x,y))
def make_tiny_star(x,y):
gameDisplay.blit(tiny_star_img, (x,y))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for star in med_stars_location:
make_med_star(star.x,star.y)
for star in tiny_stars_location:
make_tiny_star(star.x,star.y)
pygame.display.flip()
time.sleep(1)
clock.tick(60)
pygame.quit()
quit()
I'd like the stars to occasionally blink, which I think would be done by randomly removing one or two stars from the stars_location list during the main loop before adding them back when the loop comes back around. The loop probably executes very fast, but I think I can add a delay. Any help here would be greatly appreciated.
You can save a boolean for each star. If the value is True the star is visible.
Example for saving star data: (I wouldn't use the pygame.Rect and instead a simple list)
for i in range(25):
tiny_stars_location.append([randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height, True])
Also you should not use time.sleep in a pygame program. It does not delay a task. I delays the program. So you have to wait a whole second to close the program or interact with it in any way.
A lazy but working approach would be just to use randomness. You could just get a random number with random.randint(0, n), if it is 0 you set the boolean value of the star to True or False, depending on what state it currently is. You can set the variable n to some number like
n = maximum fps * average seconds before the star is hidden/shown
An other thing you probably just forgot is to clear the window in the loop with gameDisplay.fill(gray).
Your finished code could look like this:
import time
import pygame
from random import randint
pygame.init()
display_width = 800
display_height = 600
gameDisplay = pygame.display.set_mode((display_width,display_height))
pygame.display.set_caption("My God, it's full of stars!")
med_star_img = pygame.image.load('images/medium_star.png')
tiny_star_img = pygame.image.load('images/tiny_star.png')
black = (0,0,0)
white = (255,255,255)
gray = (50,50,50)
tiny_stars_width = tiny_star_img.get_width()
tiny_stars_height = tiny_star_img.get_height()
med_stars_width = med_star_img.get_width()
med_stars_height = med_star_img.get_height()
tiny_stars_location = []
med_stars_location = []
clock = pygame.time.Clock()
running = True
gameDisplay.fill(gray)
# create random coordinates for stars
for i in range(25):
tiny_stars_location.append([randint(1,800),randint(1,600),tiny_stars_width,tiny_stars_height, True])
for i in range(10):
med_stars_location.append([randint(1,800),randint(1,600),med_stars_width,med_stars_height, True])
def make_med_star(x,y):
gameDisplay.blit(med_star_img, (x,y))
def make_tiny_star(x,y):
gameDisplay.blit(tiny_star_img, (x,y))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
for star in med_stars_location:
if star[2]:
make_med_star(star[0], star[1])
if not randint(0, 300): # 300 / 60(fps) = 5 -> every 5 seconds on average
star[2] = not star[2] # inverse
for star in tiny_stars_location:
if star[2]:
make_tiny_star(star[0], star[1])
if not randint(0, 300): # 300 / 60(fps) = 5 -> every 5 seconds on average
star[2] = not star[2] # inverse
pygame.display.flip()
#time.sleep(1) <- never do this in pygame
clock.tick(60)
gameDisplay.fill(gray) # reset display
pygame.quit()

Generate tiles in piano tiles consecutively in pygame

I have created a simple piano tiles game clone in pygame.
Everything working fine except the way i am generating tiles after every certain interval, but as the game speed increases this leaves a gap between two tiles.
In the original version of the game, there's no lag (0 distance ) between two incoming tiles.
Here's a preview of the game:
Currently I am generating tiles like this:
ADDBLOCK = pygame.USEREVENT + 1
ADDTIME = 650
pygame.time.set_timer(ADDBLOCK, ADDTIME)
if event.type == ADDBLOCK:
x_col = random.randint(0,3)
block = Block(win, (67.5 * x_col, -120))
block_group.add(block)
But with time, these tiles speed increase so there's remain a gap between generation of two tiles as shown by red line in the preview. Is there any way to generate tiles consecutively?
Source Code
Use a variable number to know how many tiles have been generated since the start. This variable will start with 0, then you will add 1 to this variable every time a tile is generated.
Then, you can use a variable like scrolling which increases continuously. You will add this scrolling to every tile y pos to render them.
Now you just have to add a tile which y position is like -tile_height - tile_height * number.
If that doesn't make sense to you, look at this MRE:
import pygame
from pygame.locals import *
from random import randint
pygame.init()
screen = pygame.display.set_mode((240, 480))
clock = pygame.time.Clock()
number_of_tiles = 0
tile_height = 150
tile_surf = pygame.Surface((60, tile_height))
tiles = [] # [column, y pos]
scrolling = 0
score = 0
speed = lambda: 200 + 5*score # increase with the score
time_passed = 0
while True:
click = None # used to click on a tile
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
exit()
if event.type == MOUSEBUTTONDOWN:
click = event.pos
screen.fill((150, 200, 255))
if scrolling > number_of_tiles * tile_height:
# new tile
# use "while" instead of "if" if you want to go at really high speed
tiles.append([randint(0, 3), -tile_height - number_of_tiles * tile_height])
number_of_tiles += 1
for x, y in tiles:
screen.blit(tile_surf, (60 * x, y + scrolling))
if y + scrolling > 480: # delete any tile that is no longer visible
tiles.remove([x, y])
if click is not None and Rect((60 * x, y + scrolling), tile_surf.get_size())
.collidepoint(click):
tiles.remove([x, y]) # delete any tile that has been clicked
score += 1 # used to calculate speed
scrolling += speed() * time_passed
pygame.display.flip()
time_passed = clock.tick() / 1000

Having an image appear multiple times Pygame

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()

Rendering Large Image in PyGame Causing Low Framerate

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.

How do I make pygame display the time and change it when the time changes using fonts?

I have got a working digital clock in python but I am stuck trying to make it a visual in pygame.
The code for the clock works but it just doesn't display anything, even though I have used .blit to do so.
The idea is to have the timer show every minute (Second), Hour(every 60 seconds) and Days (Every 12 in game hours). This is then to appear on the top left.
Here is my code:
import sys, pygame, random, time
pygame.init()
#Screen
size = width, height = 1280, 720 #Make sure background image is same size
screen = pygame.display.set_mode(size)
done = False
#Animation
A1=0
A2=0
#Time Info
Time = 0
Minute = 0
Hour = 0
Day = 0
counter=0
#Colour
Black = (0,0,0)
White = (255, 255, 255)
#Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)
#Day
DayFont = Font.render("Day:"+str(Day),1, Black)
DayFontR=DayFont.get_rect()
DayFontR.center=(985,20)
#Hour
HourFont = Font.render("Hour:"+str(Hour),1, Black)
HourFontR=HourFont.get_rect()
HourFontR.center=(1085,20)
#Minute
MinuteFont = Font.render("Minute:"+str(Minute),1, Black)
MinuteFontR=MinuteFont.get_rect()
MinuteFontR.center=(1200,20)
#Images
Timer=pygame.time.get_ticks
Clock = pygame.time.Clock()
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(White)
#Timer
if Time<60:
time.sleep(1)
Minute=Minute+1
if Minute == 60:
Hour=Hour+1
Minute=0
if Hour==12:
Day=Day+1
Hour=0
if A1==0:
A1=A1+1
A2=A2+1
time.sleep(1)
if A1==1 or A2==1:
A2=A2-1
A1=A1-1
if A1==1:
screen.blit(MinuteFont, MinuteFontR)
screen.blit(HourFont, HourFontR)
screen.blit(DayFont, DayFontR)
if A2==0:
screen.fill(pygame.Color("White"), (1240, 0, 40, 40))
pygame.display.flip()
Clock.tick(60)
pygame.quit()
Sorry if this is nooby, but any help is appreciated
Barring all other problems, I'm not sure what your A1 and A2 are supposed to be, but
if A1==0: #true for the first run through
A1=A1+1 #A1 = 1
A2=A2+1
time.sleep(1)
if A1==1 or A2==1: #always true, since A1==1
A2=A2-1
A1=A1-1 #A1 = 0
this will always increase A1 and set it back to zero in the same step, essentially doing nothing, so you never get to the part if A1==1 where you might blit the time.
Apart from that, Font.render() "creates a new Surface with the specified text rendered on it." (cf. the documentation) This means you have to re-render the font every time you want to update the text, otherwise you keep blitting the same (unchanged) surface again and again. You will also need to adjust the rect to account for the text being wider then the time goes up from one digit to two.
The easiest way to keep track of time might be to use a custom user event that's fired every second in the event queue like so:
import pygame
pygame.init()
#Screen
size = width, height = 1280, 720 #Make sure background image is same size
screen = pygame.display.set_mode(size)
done = False
#Time Info
Time = 0
Minute = 0
Hour = 0
Day = 0
counter=0
#Colour
Black = (0,0,0)
White = (255, 255, 255)
#Fonts
Font = pygame.font.SysFont("Trebuchet MS", 25)
#Day
DayFont = Font.render("Day:{0:03}".format(Day),1, Black) #zero-pad day to 3 digits
DayFontR=DayFont.get_rect()
DayFontR.center=(985,20)
#Hour
HourFont = Font.render("Hour:{0:02}".format(Hour),1, Black) #zero-pad hours to 2 digits
HourFontR=HourFont.get_rect()
HourFontR.center=(1085,20)
#Minute
MinuteFont = Font.render("Minute:{0:02}".format(Minute),1, Black) #zero-pad minutes to 2 digits
MinuteFontR=MinuteFont.get_rect()
MinuteFontR.center=(1200,20)
Clock = pygame.time.Clock()
CLOCKTICK = pygame.USEREVENT+1
pygame.time.set_timer(CLOCKTICK, 1000) # fired once every second
screen.fill(White)
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == CLOCKTICK: # count up the clock
#Timer
Minute=Minute+1
if Minute == 60:
Hour=Hour+1
Minute=0
if Hour==12:
Day=Day+1
Hour=0
# redraw time
screen.fill(White)
MinuteFont = Font.render("Minute:{0:02}".format(Minute),1, Black)
screen.blit(MinuteFont, MinuteFontR)
HourFont = Font.render("Hour:{0:02}".format(Hour),1, Black)
screen.blit(HourFont, HourFontR)
DayFont = Font.render("Day:{0:03}".format(Day),1, Black)
screen.blit(DayFont, DayFontR)
pygame.display.flip()
Clock.tick(60) # ensures a maximum of 60 frames per second
pygame.quit()
I've zero-padded the minutes, hours and days so you don't have to recalculate the rectangle every time. You could also optimize the draw code by only drawing hours and days if they have changed (in the respective if statements).
To see other methods of how to handle timed events, check out Do something every x (milli)seconds in pygame.

Categories

Resources