Slowly decrement variable with timer? - python

I've got a variable that increases when the user presses a button.
When the user presses another button, I'd like to set that variable to 0,
but not instantly-- I'd like it to tick down over the course of a few seconds.
During this time I'd like the user to be able to perform other actions-- hence why I'm not using sleep.
I've looked at using pygame's events, time.clock, etc., but I can't seem to get this to work. Here is what I've tried so far:
import pygame, sys, math
from pygame.locals import *
pygame.init()
pygame.font.init()
scrw = 640
scrh = 480
screen = pygame.display.set_mode((scrw, scrh))
ttwist = 0
recentering = False
fps = 15
clock = pygame.time.Clock()
my_font = pygame.font.SysFont("arial", 12)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pressed = pygame.key.get_pressed()
if not recentering:
if pressed[pygame.K_d]:
ttwist +=1
if pressed[pygame.K_a]:
ttwist -=1
RECENTERTORSOEVENT = USEREVENT
if event.type == pygame.KEYDOWN and event.key == pygame.K_BACKSLASH:
recentering = True
pygame.time.set_timer(RECENTERTORSOEVENT, 1000*abs(ttwist))
if ttwist == 0:
recentering = False
if event.type == USEREVENT:
if ttwist < 0:
ttwist += 1
elif ttwist > 0:
ttwist -= 1
drawtext = my_font.render("TTWIST:"+str(ttwist), True, (255,255,255),(0,0,0))
screen.blit(drawtext,(10,130))
pygame.display.update()
clock.tick(fps)
What am i doing wrong?

You are on the right track, but some parts of the code need to be changed:
All the if event.type == ... blocks should be inside of the event loop.
RECENTERTORSOEVENT = USEREVENT should be defined above the while loop (but that doesn't cause problems).
You're setting the time interval for the RECENTERTORSOEVENT way too high: 1000*abs(ttwist). That means, if the ttwist is 10, you're setting it to 10.000 ms (10 seconds). Just set it to a constant value like 100 ms.
When the ttwist is recentered, call pygame.time.set_timer(RECENTERTORSOEVENT, 0) to stop the timer.
Fill the screen each frame screen.fill((30, 30, 30)), otherwise you see artifacts because the font surface keeps changing its size.
import sys
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
my_font = pygame.font.SysFont('arial', 22)
clock = pygame.time.Clock()
ttwist = 0
RECENTERTORSOEVENT = pygame.USEREVENT
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
print('recentering')
# Start to add the USEREVENT every 100 ms.
pygame.time.set_timer(RECENTERTORSOEVENT, 100)
elif event.type == RECENTERTORSOEVENT:
ttwist += 1 if ttwist < 0 else -1
if ttwist == 0:
print('done')
# Stop to add the USEREVENT to the queue.
pygame.time.set_timer(RECENTERTORSOEVENT, 0)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_d]:
ttwist += 1
if pressed[pygame.K_a]:
ttwist -= 1
screen.fill((30, 30, 30))
drawtext = my_font.render(
'TTWIST: {}'.format(ttwist), True, (255, 255, 255))
screen.blit(drawtext, (10, 130))
pygame.display.update()
clock.tick(30)
ttwist += 1 if ttwist < 0 else -1 is a conditional expression and does basically the same as:
if ttwist < 0:
ttwist += 1
elif ttwist > 0:
ttwist -= 1

Related

How to start a countdown when pygame.QUIT is initialized

I have a ball animation and I want it so that it that runs until you CLOSE the program (A.K.A until pygame.QUIT is activated) And then after pygame.QUIT is activated it will count down from 10 seconds before it closes.
(PS. If you're an admin of this website the other post you send me doesn't help with my specific problem)
import pygame
import random
pygame.init()
window = pygame.display.set_mode([400,400])
c = pygame.time.Clock()
black = (0,0,0)
white = (255,255,255)
x = random.randint(10,390)
y = random.randint(10,390)
speed_x = random.randint(3,5)
speed_y = random.randint(3,5)
time = 10
#this is definitely wrong so this where I need help on
playing = True
while playing:
for event in pygame.event.get():
if event.type == pygame.QUIT:
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
time -= 1
print(time)
pygame.time.wait(1000)
if time == 0:
playing = False
x += speed_x
y += speed_y
window.fill((white))
pygame.draw.circle(window,black,(x,y),20)
if x > 390 or x < 10:
speed_x = speed_x * -1
if y > 390 or y < 10:
speed_y = speed_y * -1
c.tick(60)
pygame.display.flip()
Instead of exiting the application, start a countdown timer. Quit the application when the countdown is complete.
See Countdown timer in Pygame.
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((200, 200))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
counter = 0
text = font.render(str(10), True, (0, 128, 0))
timer_event = pygame.USEREVENT+1
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
counter = 10
pygame.time.set_timer(timer_event, 1000)
elif event.type == timer_event:
counter -= 1
text = font.render(str(counter), True, (0, 128, 0))
if counter == 0:
run = False
window.fill((255, 255, 255))
# draw game
# [...]
if counter > 0:
text_rect = text.get_rect(center = window.get_rect().center)
window.blit(text, text_rect)
pygame.display.flip()
pygame.quit()
exit()

Sprite disappears after holding SPACE or DOWN when using scrolling background

When SPACE or DOWN is held, then the sprite disappears because of the scrolling background. When the background is a still image, it works. Furthermore the animation is fast so I used a timer to make it slower, but when the DOWN button is let go of, the screen speeds up.
I have tried searching up syntax online and it works when the background image is still.
from time import sleep as s
import random
import pygame
pygame.init()
import time
window = pygame.display.set_mode((1000, 500))
pygame.display.set_caption("Practice Game")
image = pygame.image.load('pixel6.png')
image = pygame.transform.scale(image, (1000, 500))
jump1 = [pygame.image.load('adventurer-jump-00.png'),pygame.image.load('adventurer-jump-01.png'),pygame.image.load('adventurer-jump-02.png'),pygame.image.load('adventurer-jump-03.png'), pygame.image.load('adventurer-smrslt-00.png'),pygame.image.load('adventurer-smrslt-01.png'),pygame.image.load('adventurer-smrslt-02.png'),pygame.image.load('adventurer-smrslt-03.png')]
run2 = [pygame.image.load('adventurer-run-00.png'), pygame.image.load('adventurer-run-01.png'),pygame.image.load('adventurer-run-02.png'),pygame.image.load('adventurer-run-03.png')]
slide1 = [pygame.image.load('adventurer-slide-00.png'),pygame.image.load('adventurer-slide-01.png'),pygame.image.load('adventurer-stand-00.png'),pygame.image.load('adventurer-stand-01.png'),pygame.image.load('adventurer-stand-02.png')]
#attack = [pygame.image.load('
imagex = 0
imagex2 = image.get_width()
clock = pygame.time.Clock()
run = True
run1 = True
jump2 = True
slide2 = True
imagess = True
x = 40
y = 391
FPS = 60
speed = 0.6
jumpcount = 10
jumpcount1 = 0
runcount = 0
slide = 0
isJump = False
down = False
class obstacles(object):
img = [pygame.image.load('img.png')]
def __init__(self, x,y, width, height):
self.x = x
self.y =y
self.width = width
self.height = height
self.hitbox = (x,y,width,height)
self.count = 0
def draw(self, window):
self.hitbox = (self.x + 5, self.y + 5, self.width, self.height)
if self.count >= 8:
self.count = 0
self.count +=1
window.blit(pygame.transform.scale(self.img[self.count//1000], (150,100)), (self.x, self.y))
pygame.draw.rect(window, (255,0,0), self.hitbox, 2)
objects = []
def keepdrawing():
global runcount, slide, run1,jumpcount1
window.blit(image, (imagex,0))
window.blit(image, (imagex2,0))
for object1 in objects:
object1.draw(window)
if runcount >= 3:
runcount = 0
if run1 == True:
window.blit(run2[runcount],(int(x),int(y)))
runcount +=1
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN and y == 391:
run1 = False
if slide >= 4:
slide = 0
if slide2:
window.blit(slide1[slide],(int(x),int(y)))
slide +=1
if event.key == pygame.K_SPACE:
run1 = False
if jumpcount1 >= 7:
jumpcount1 = 0
if jump2 and y!=391:
window.blit(jump1[jumpcount1],(int(x),int(y)))
jumpcount1 +=1
if event.type == pygame.KEYUP:
if event.key == pygame.K_DOWN:
run1 = True
if event.key == pygame.K_SPACE:
run1=True
pygame.display.update()
pygame.time.set_timer(pygame.USEREVENT+1, 500)
pygame.time.set_timer(pygame.USEREVENT+2, random.randrange(1000,2000))
obstacles = obstacles(1050,300,64,64)
while run:
clock.tick(60)
imagex -= 2
imagex2 -= 2
if imagex < image.get_width() * -1:
imagex = image.get_width()
if imagex2 < image.get_width() * -1:
imagex2 = image.get_width()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.USEREVENT+1:
speed += 1
if event.type == pygame.USEREVENT+2:
objects.append(obstacles)
for object1 in objects:
object1.x -= 1
if object1.x < -100:
objects.pop(objects.index(object1))
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
keys = pygame.key.get_pressed()
if not(isJump):
if keys[pygame.K_SPACE]:
isJump =True
else:
if jumpcount >= -10:
neg=1
if jumpcount <0:
neg = -1
s(0.01)
y-= (jumpcount**2)*0.3*neg
s(0.01)
jumpcount -=1
else:
isJump = False
jumpcount = 10
keepdrawing()
I cannot test your game due to the lot of images I do not have, but I think you are misunderstanding how the event system works, or at least you have neglected a case.
When you press a key, the KEYDOWN is emitted, and when you lift the key, the KEYUP is emitted.
These event are instantaneous (well, not really, but they are very fast), and are catched by the event manager only when the status of the button changes (from pressed to unpressed and viceversa). You must not rely on them to check if a button is kept pressed. Have a look at this post for a better understanding.
With this in mind, let's see what happening to your keepdrawing function. Here the relevant parts:
def keepdrawing():
#...
if run1 == True:
#blitting
if event.type == pygame.KEYDOWN:
run1 = False
#stuff and blitting
if event.type == pygame.KEYUP:
run1 = True
As you can see, when you hold the button pressed (that is, between KEYDOWN and KEYUP events) the boolean run1 is False. So nothing is blit. That's why your image disappear.
You should still be able to see the beginning of the movement: the frame when you press the button the KEYDOWN event is catched and that part of the code is executed. But the frame later, nothing is blit because run1 is False and there is no event to be catched.
I do not have a working solution, as I said I cannot test the game, but I would suggest at least to be sure that keepdrawing always draw something. Try to figure what you should draw when run1 is False and add a couple of lines about it in keepdrawing.
As a more general advice, do not use the pygame event system in the keepdrawing function. Just check if a button is pressed like you do here:
keys = pygame.key.get_pressed()

Python 2D Sprite Animation

I'm trying to animate a sprite using a loop such that each time the loop runs through the position number for an image in an array increases by one. I keep getting "UnboundLocalError: local variable 'Antic' referenced before assignment". There is
Antic = 0
Antic = int(Antic)
# Global constants
StAnmtn = ["Images/PlayerVampireStanding1.png", "
Images/PlayerVampireStanding2.png",
"Images/PlayerVampireStanding3.png","Images/PlayerVampireStanding4.png",
"Images/PlayerVampireStanding5.png", "Images/PlayerVampireStanding6.png",
"Images/PlayerVampireStanding7.png", "Images/PlayerVampireStanding8.png"]
`
at the start and
def main():
""" Main Program """
pygame.init()
clock = pygame.time.Clock() # creates clock to limit frames per
second
FPS = 60 # sets max speed of min loop
SCREENSIZE = SCREENWIDTH, SCREENHEIGHT = 1300, 700 # sets size of
screen/window
screen = pygame.display.set_mode(SCREENSIZE) # creates window and game
screen
pygame.display.set_caption("Count Acheron")
# Create the player
player = Player()
# Create all the levels
level_list = []
level_list.append( Level_01(player) )
# Set the current level
current_level_no = 0
current_level = level_list[current_level_no]
active_sprite_list = pygame.sprite.Group()
player.level = current_level
player.rect.x = 340
player.rect.y = SCREEN_HEIGHT - player.rect.height
active_sprite_list.add(player)
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
# -------- Main Program Loop -----------
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
if Antic > 6:
Antic = 0
else:
Antic += 1
# Update the player.
active_sprite_list.update()
# Update items in the level
current_level.update()
# ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
current_level.draw(screen)
active_sprite_list.draw(screen)
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Be IDLE friendly. If you forget this line, the program will 'hang'
# on exit.
pygame.quit()
if __name__ == "__main__":
main()
as the loop. What it doesn't seem to like is the snippet of code
if Antic > 6:
Antic = 0
else:
Antic += 1
How do I fix this?
Personally I've never used pygame's sprite module.
import pygame
class character:
def __init__(self, x, y):
self.x = x
self.y = y
self.sprites = [pygame.image.load("img1.png"), pygame.image.load("img2.png")]
self.frame = 0
def draw(self, surface):
surface.blit(self.sprites[self.frame], (self.x, self.y))
self.frame += 1
if self.frame > len(self.sprites) - 1: self.frame = 0
pygame.init()
DS = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()
c = character(640, 360)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE):
pygame.quit()
c.draw(DS)
pygame.display.update()
clock.tick(30)
DS.fill((0, 0, 0))
Needed to globalise the function ("global Antic" in the main loop)

I want to hold down a button for constant movement, but KEYUP is reading true even if I don't lift the key

I want to be able to hold the key down and move my little black dot, and then release the key and have it stop. However even if I hold the key down my if statement for key up is being executed. Here is my code:
manmovemaster = 0
l = 1
f1 = 0
from random import randint
from math import sin, cos, tan, pi
import pygame
from pygame.locals import*
Fps = pygame.time.Clock()
#starting variables
sw = 1200
sh = 650
r = 250
g = 250
b = 250
framerate = 40
#beginning of a man
man1x = 650
man1y = 50
mancolor=(0,0,0)
manlocation = (man1x, man1y)
Diamaterofhead = (5)
man1ymovedown = 0
man1ymoveup = False
man1xmoveright = False
man1xmoveleft = False
#game logic
while l:
pygame.init()
screen = pygame.display.set_mode((sw,sh))
pygame.display.set_caption("WGD THE GAME")
background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((r,g,b))
man1 = pygame.draw.circle(background,mancolor,(man1x,man1y),Diamaterofhead)
if man1ymovedown== True:
man1y += 1
manmovemaster = 0
if man1ymoveup == True:
man1y -= 1
if man1xmoveright == True:
man1x +=1
if man1xmoveleft == True:
man1x -=1
#screen refresh
for event in pygame.event.get():
if event.type ==pygame.QUIT:
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
man1xmoveleft = True
if event.key == pygame.K_RIGHT:
man1xmoveright = True
if event.key == pygame.K_UP:
man1ymoveup = True
if event.key == pygame.K_DOWN:
man1ymovedown = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT:
man1xmoveleft = False
if event.key == pygame.K_RIGHT:
man1xmoveright = False
if event.key == pygame.K_UP:
man1ymoveup = False
if event.key == pygame.K_DOWN:
man1ymovedown = False
else:
screen.blit(background, (0,0))
pygame.display.flip()
pygame.time.get_ticks
Fps.tick(framerate)
Use this instead:
import pygame
import sys
pygame.init()
screen = pygame.display.set_mode((400,400))
pygame.display.set_caption("WGD THE GAME")
Fps = pygame.time.Clock()
man1x = 200
man1y = 200
while True:
screen.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
pygame.draw.circle(screen,(255, 255, 255),(man1x,man1y), 25)
pressed = pygame.key.get_pressed()
if pressed[pygame.K_LEFT]:
man1x -= 1
if pressed[pygame.K_RIGHT]:
man1x += 1
if pressed[pygame.K_UP]:
man1y -= 1
if pressed[pygame.K_DOWN]:
man1y += 1
pygame.display.flip()
Fps.tick(60)
using pygame.key.get_pressed() instead of pygame.event.get() returns the state of the keys at all times, not just when you press it. So you can hold a key down and it will, and when you release it, it will stop. This will also work for diagonal movement. because it checks the state of all keys, it will check up and left so both will be true (pressed) and the character will move diagonally.
https://www.pygame.org/docs/ref/key.html#pygame.key.get_pressed
and then you can take all the event checking and boolean movement flags out. Also, each time through the loop you are calling pygame.init(). This isn't necessary. you also don't need to set the mode each time through the game loop, as well as the caption, and background

Pygame collideRect precion issue [duplicate]

This question already has answers here:
How do I detect collision in pygame?
(5 answers)
How to detect collisions between two rectangular objects or images in pygame
(1 answer)
Closed 2 years ago.
I am trying to write a pygame program where the user dodges objects falling from the top of the screen. However, when I run, collideRect activates too early. Any suggestions?
import pygame
import sys
import time
import random
pygame.init()
size = width, height = 500, 500
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Avalanche!")
character = pygame.image.load("C:/Python27/Lib/site-packages/StickBasic.png")
boulder = pygame.image.load("C:/Python27/Lib/site-packages/Boulder1.png")
charRect = character.get_rect()
charRect.left = 246
charRect.bottom = 450
running = True
skyBlue = 0, 255, 255
groundBrown = 100, 0, 0
direction = 0
timer = 0
boulderFrequency = 20
boulders = []
def endgame():
global running
running = False
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
sys.exit()
def bg():
screen.fill(skyBlue)
pygame.draw.rect(screen, groundBrown, (0, 450, 500, 500))
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
if charRect.left > 0:
direction = -1
elif event.key == pygame.K_RIGHT:
if charRect.right < 500:
direction = 1
elif event.type == pygame.KEYUP:
direction = 0
if (direction < 0) and (charRect.left > 0):
charRect.left -= 1
if (direction > 0) and (charRect.right < 500):
charRect.left += 1
if timer >= boulderFrequency:
timer = 0
newBoulder = {
'rect': pygame.Rect(random.randint(0, 460), -40, 40, 40),
'surface': boulder}
boulders.append(newBoulder)
bg()
for b in boulders:
b['rect'].move_ip(0, 5)
if b['rect'].top > 500:
boulders.remove(b)
for b in boulders:
screen.blit(b['surface'], b['rect'])
screen.blit(character, charRect)
pygame.display.flip()
timer += 1
for b in boulders:
if charRect.colliderect(b['rect']):
endgame()
time.sleep(0.02)
PS: I know that the coding is not very clean, but I am relatively knew to coding.

Categories