Sprites appearing too fast - python

I'm trying to create a program where balloons appear for the user to pop, however balloons are appearing so fast it becomes unmanageable. I took a screenshot about half a second into running the program:
Here is the code for time between balloons appearing:
timeTillNextBalloon = random.randint(100000, 200000)
while done == False:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if pygame.time.get_ticks() > timeTillNextBalloon:
timeTillNextBalloon = random.randint(30000, 250000)
yCoord = random.randint(50,350)
balloonType = random.randint(1,4)
balloon = Balloon(0, yCoord, "right", balloonType)
if balloonType >= 1 and balloonType <= 3:
otherBalloons.add(balloon)
else:
blueBalloons.add(balloon)
allBalloons.add(balloon)
I've tried to increase the timeTillNextBaloon variable, but it just shows a black screen if I try to make it any bigger than this.

Get_ticks gets the current time, timeTillNextBalloon should be the current to + the random value. Now every the loop repeats a balloon is added:
timeTillNextBalloon = pygame.time.get_ticks() + random.randint(30000, 250000)

Related

How to make a rectangular object to move slowly across the screen? [duplicate]

This question already has an answer here:
Pygame clock and event loops
(1 answer)
Closed 2 years ago.
i am new to python programming and now starting to write simple "Snake" game.
i am trying to make the head of the snake move around the screen in a way that
when an arrow key is pressed, the head should move in that direction non-stop, until a perpendicular
arrow is pressed.
i cant make the head of the snake ( a rectangle) to move non stop in single direction slowly.
i tried to use time.sleep() --> it made the whole code stuck.
i tried to use for loop --> it just made the rectangle to transport to the other direction fast.
this is my main function:
while not GameOver:
#create time delay of 10 milliseconds
pygame.time.delay(10)
# Get all of the events on the game's screen [all of the user's input]
# Loop on the user's activity and look for exit button pressing.
for event in pygame.event.get():
# If the user presses the X button:
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# Define a shortcut name to "get_pressed" method in pygame:
keys = pygame.key.get_pressed()
# defining x location
x = head_position[0]
y = head_position[1]
# if he pressed left key
if keys[pygame.K_LEFT]:
# reducing location by constant
head_position[0] -= head_speed
elif keys[pygame.K_RIGHT]:
# increacing location by constant
head_position[0] += head_speed
elif keys[pygame.K_UP]:
# increacing location by constant
head_position[1] -= head_speed
elif keys[pygame.K_DOWN]:
# increacing location by constant
head_position[1] += head_speed
#If the head passes the screen Boundaries, it would pop in the other side.
if head_position[0] >= WIDTH:
head_position[0] = 0
elif head_position[0] < 0:
head_position[0] = WIDTH-head_size
elif head_position[1] >= HEIGHT:
head_position[1] = 0
elif head_position[1] < 0:
head_position[1] = HEIGHT-head_size
Use the pygame.time module to control the frames per second. Generate a pygame.time.Clock object. If you pass the optional framerate argument to pygame.time.Clock.tick, the function will delay to keep the game running slower than the given ticks per second:
clock = pygame.time.Clock()
while not GameOver:
clock.tick(10) # 10: the game runs with 10 frames per second
# [...]
if you want to make it move at a constant speed in one direction after one key press then make a
right = False varible
then make a
key[pygame.K_YOURCHOICE]:
right = True
if right:
head_pos[1 or 0] -= head_speed

Interaction with AI in PyGame [duplicate]

I am currently developing a simple Tower of Hanoi animation in Pygame, that should show the correct solution of Tower of Hanoi, moving one piece per second.
However, in my hanoi solving algorithm, I'm trying to update the display and use pygame.time.wait() after each movement; and instead of updating one movement and waiting one second, the program waits the total number of movements amount of seconds and then displays the tower with all the movements done at once.
What I would like to know is if I am using the wait function wrongly or if there is any other useful function in this situation that I am missing.
Here's the code:
def hanoi(n, origin, destination, aux):
# solves the game with n pieces
if n == 1:
positions[0] = destination
# updates and waits
printBackground()
printPieces(positions)
pg.time.wait(1000)
else:
hanoi(n-1, origin, aux, destination)
positions[n-1] = destination
#updates and waits
printBackground()
printPieces(positions)
pg.time.wait(1000)
hanoi(n-1, aux, destination, origin)
and the loop:
while True:
for event in pg.event.get():
if event.type == pg.QUIT:
pg.quit()
sys.exit()
if running:
hanoi(numPieces, 0, 2, 1)
running = False
Thank you!
You need to seperate your algorithm from the drawing aspect of your code.
A simple way to update your code would be to use a coroutine that, at every step of your recursive hanoi function, gives the control back to the main loop, which in turn draws the screen, and gives control back to the hanoi coroutine every second.
Here's a simplified example that just counts down:
#-*- coding-utf8 -*-
import pygame
import pygame.freetype
pygame.init()
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
font = pygame.freetype.SysFont(None, 30)
def hanoi(num):
# We calculated something and want to print it
# So we give control back to the main loop
yield num
# We go to the next step of the recursive algorithm
yield from hanoi(num-1) #
steps = hanoi(1000)
ticks = None
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
exit()
# step every second only
if not ticks or pygame.time.get_ticks() - ticks >= 1000:
ticks = pygame.time.get_ticks()
screen.fill((200, 200, 200))
# the value from the next step of the coroutine
value = str(next(steps))
# render stuff onto the screen
font.render_to(screen, (100, 100), value)
pygame.display.flip()
clock.tick(60)
In your code, you should replace
# updates and waits
printBackground()
printPieces(positions)
pg.time.wait(1000)
with yield positions to give control back to the main loop and
hanoi(n-1, aux, destination, origin)
with
yield from hanoi(n-1, aux, destination, origin)
to keep the coroutine running and call
...
screen.fill((200, 200, 200))
positions = next(steps)
printBackground()
printPieces(positions)
...
inside the if in the main loop.
(If the algorithm finish, it will raise a StopIterationException which you probably want to catch).

How to increase a variable every second in Pygame?

I am creating a clicker game, very similar to cookie clicker. My question is, how do I increase a variable by an amount every second?
Here, prepare for a new game.
def new(self):
# set cookies/multipliers for a new game
self.cookie_count = 0
self.grandma = 10 # grandma bakes 10 cookies/second
Then, if a grandma is purchased, add 10 cookies/second to self.cookie_count for every grandma purchased. Example: If 2 grandmas are purchased, self.cookie_count += 20 cookies/second. Yet, as I have it now, everytime I purchase a grandma I just get 10 cookies.
if self.rect2.collidepoint(self.mouse_pos) and self.pressed1:
self.cookie_count += self.grandma
I know that it has something to do with time, but other than that I'm not quite sure where to start.
Instead of incrementing the cookies once per second, you can make the cookie count just how many seconds have passed since the start. This may cause problem in certain scenarios (this will complicate pausing, for example), but will work for simple games.
My Python is a tad rusty, so sorry if this isn't entirely idiomatic:
import time
self.start_time = time.time()
# When you need to know how many cookies you have, subtract the current time
# from the start time, which gives you how much time has passed
# If you get 1 cookie a second, the elapsed time will be your number of cookies
# "raw" because this is the number cookies before Grandma's boost
self.raw_cookies = time.time() - self.start_time
if self.grandma:
self.cookies += self.raw_cookies * self.grandma
else:
self.cookies += raw.cookies
self.raw_cookies = 0
This may look more complicated than just using time.sleep, but it has two advantages:
Using sleep in games is rarely a good idea. If you sleep on the animation thread, you'll freeze the entire program for the duration of the sleep, which is obviously not a good thing. Even if that's not an issue in simple games, the use of sleep should be limited for habit's sake. sleep should really only be used in tests and simple toys.
sleep isn't 100% accurate. Over time, the error of the sleep time will accumulate. Whether or not this is a problem though is entirely dependant on the application. By just subtracting the time, you know exactly (or at least with high precision) how much time has passed.
Note:
With the code above, cookies will be a floating point number, not an integer. This will be more accurate, but may not look nice when you display it. Convert it to an integer/round it before displaying it.
Having never player "Cookie Clicker" before, I may have confused the logic. Correct me if something doesn't make sense.
I'm assuming self.grandma is None/falsey if the player doesn't have the upgrade.
The way to do this in pygame is to use pygame.time.set_timer() and have an event generated every given number of milliseconds. This will allow the event to be handled in the script's main loop like any other.
Here's a somewhat boring, but runnable, example of doing something like that:
import pygame
pygame.init()
SIZE = WIDTH, HEIGHT = 720, 480
FPS = 60
BLACK = (0,0,0)
WHITE = (255,255,255)
GREEN = (0,255,0)
RED = (255,0,0)
BLUE = (0,0,255)
BACKGROUND_COLOR = pygame.Color('white')
screen = pygame.display.set_mode(SIZE)
clock = pygame.time.Clock()
font = pygame.font.SysFont('', 30)
COOKIE_EVENT = pygame.USEREVENT
pygame.time.set_timer(COOKIE_EVENT, 1000) # periodically create COOKIE_EVENT
class Player(pygame.sprite.Sprite):
def __init__(self, position):
super(Player, self).__init__()
self.cookie_count = 0
self.grandma = 10 # grandma bakes 10 cookies/second
text = font.render(str(self.cookie_count), True, RED, BLACK)
self.image = text
self.rect = self.image.get_rect(topleft=position)
self.position = pygame.math.Vector2(position)
self.velocity = pygame.math.Vector2(0, 0)
self.speed = 3
def update_cookies(self):
self.cookie_count += self.grandma # 10 cookies per grandma
if self.cookie_count > 499:
self.cookie_count = 0
text = font.render(str(self.cookie_count), True, RED, BLACK)
self.image = text
player = Player(position=(350, 220))
running = True
while running:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == COOKIE_EVENT:
player.update_cookies()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
player.velocity.x = -player.speed
elif keys[pygame.K_RIGHT]:
player.velocity.x = player.speed
else:
player.velocity.x = 0
if keys[pygame.K_UP]:
player.velocity.y = -player.speed
elif keys[pygame.K_DOWN]:
player.velocity.y = player.speed
else:
player.velocity.y = 0
player.position += player.velocity
player.rect.topleft = player.position
screen.fill(BACKGROUND_COLOR)
screen.blit(player.image, player.rect)
pygame.display.update()
You'll need to use time module. You can capture period of time with time.time().
import time
grandma = 3
cookie_count = 0
timeout = 1
while True:
cookie_count += grandma * 10
print 'cookie count: {}'.format(cookie_count)
time.sleep(timeout)
Another option is to validate the expression now - start > timeout. They will both do the same, but incase your timeout is larger than 1 this would be the solution. The first code above won't work.
import time
grandma = 3
cookie_count = 0
timeout = 1
start = time.time()
while True:
if time.time() - start > timeout:
cookie_count += grandma * 10
print 'cookie count: {}'.format(cookie_count)
time.sleep(timeout)

Referencing previous frames values Python Pygame

I have a really simple piece of code. What I would like to do as the program loops at 60 fps is I want to reference the previous mouse click state. i.e. I have 'one' as the variable for mouse click state, 0 for not clicked and 1 for clicked. What I want to happen is If the mouse is currently clicked i.e. one = 1 & the previous value of one was 0 i.e. unclicked then save the value of mx and my which are the mouse co-ordinates. Please see the code below:
PDimageFull = pygame.image.load('F:\Project files\coils\PDsinwaveResize.jpg')
PDresX = 300
PDresY = 720
gameDisplay = pygame.display.set_mode((Display_Width,Display_Height))
pygame.display.set_caption('PD diagnostic tool')
clock = pygame.time.Clock()
def PDimage(x, y):
gameDisplay.blit(PDimageFull, (x, y))
# Defining our main programing loop
def mainProgram_loop():
dx1 = (Display_Width-PDresX)
dy1 = (Display_Height-PDresY)
gameExit = False
# Event handling
while not gameExit:
mx, my = pygame.mouse.get_pos()
one, two, three = pygame.mouse.get_pressed()
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
# This expression controls the movement of the overall PD graph
# The section in the IF statement defines the boundary by which you can move the object
if one == 1 and mx > dx1 and mx < dx1 + PDresX and my > dy1 and my < dy1+PDresY:
dx1 = dx1 + (mx - PDresX)
dy1 = dy1 + (my - PDresY)
gameDisplay.fill(white)
PDimage(dx1, dy1)
pygame.display.update()
clock.tick(60)
mainProgram_loop()
Just use another variable:
prev_one = one
one, two, three = pygame.mouse.get_pressed()
if prev_one == 0 and one == 1:
print 'mouse was clicked this frame'
Be aware that you will have to initialise one with a default value at the start of your script.

Python - Pygame random obstacle height issues

I currently am working on a 'Flappy Bird' remake in Pygame using Python 3.2. I thought it would be good for practice, and relativly simple. However, it is proving to be hard. Currently, I am having a problem when drawing a rectangle at different heights but keeping the rectangle at the height it is set to.
Here is my Pipe class
class Pipe:
def __init__(self,x):
self.drawn = True
self.randh = random.randint(30,350)
self.rect = Rect((x,0),(30,self.randh))
def update(self):
self.rect.move_ip(-2,0)
def draw(self,screen):
self.drawn = True
pygame.draw.rect(screen,(0,130,30),self.rect)
My while Loop is as follows:
while True:
for event in pygame.event.get():
movey = +0.8
if event.type == QUIT:
pygame.quit()
sys.exit()
elif event.type == KEYDOWN:
if event.key == K_SPACE:
movey = -2
x += movex
y += movey
screen.blit(background,(0,0))
screen.blit(bird,(x,y))
Pipe1 = Pipe(scrollx)
if Pipe1.drawn == True:
Pipe1.update()
else:
Pipe1 = Pipe(scrollx)
Pipe1.draw(screen)
scrollx -= 0.3
pygame.display.update()
I have being wrestling with this code for over a week, and I really appreciate any help you can give.
I'm not following the logic of this part:
Pipe1 = Pipe(scrollx)
if Pipe1.drawn == True:
Pipe1.update()
else:
Pipe1 = Pipe(scrollx)
Pipe1.draw(screen)
The drawn attribute is set to True at the constructor, so when do you expect the else condition to be triggered? Remember you are recreating this pipe every frame.
Have you tried drawing the pipe the same you way you did with the bird?
Edit: suggestion for you for loop:
PIPE_TIME_INTERVAL = 2
pipes = [] # Keep the pipes in a list.
next_pipe_time = 0
while True:
[... existing code to handle events and draw the bird ...]
for pipe in pipes:
pipe.move(10) # You'll have to write this `move` function.
if pipe.x < 0: # If the pipe has moved out of the screen...
pipes.pop(0) # Remove it from the list.
if current_time >= next_pipe_time: # Find a way to get the current time/frame.
pipes.append(Pipe()) # Create new pipe.
next_pipe_time += PIPE_TIME_INTERVAL # Schedule next pipe creation.
You are creating a new Pipe on every loop, but never hang on to the old one(s), so you get a new random height each time. Move this line:
Pipe1 = Pipe(scrollx)
outside the while loop. Better yet, have a list of pipes you can add new ones to and easily update them all. You never set self.drawn = False within Pipe either.
Also, you are resetting movey for every event, try:
movey = 0.8 # no need for plus
for event in pygame.event.get():

Categories

Resources