Hide part after 5 seconds after mousedown action - python

I'm new to python. I programmed with vb2010, but it's time to try something new. I want to hide a action after 5 seconds after mouse down event(like in start()).
import pygame
import sys
from pygame.locals import *
from time import gmtime, strftime
import threading
import time
white = (255,255,255)
black = (0,0,0)
blue = (0,0,255)
width = 600
height = 400
channel = '0001'
name = 'Channel 3'
class screen(object):
def __init__(self):
pygame.init()
self.font = pygame.font.SysFont('Arial', 25)
pygame.display.set_caption('PyTV')
self.screen = pygame.display.set_mode((width,height), 0, 32)
self.screen.fill((black))
pygame.display.update()
def printData(self):
self.rect = pygame.draw.rect(self.screen, (blue), (0, 0, width, height - 350), 0)
self.screen.blit(self.font.render(channel, True, white), (width - 590, 0))
self.screen.blit(self.font.render(name, True, white), (height - 335, 0))
self.screen.blit(self.font.render(strftime("%H:%M %d/%m/%Y", gmtime()), True, white), (width - 590, height - 377))
pygame.display.update()
def clean(self):
self.screen.fill((black))
pygame.display.update()
if __name__ == '__main__':
def start():
Pan3.printData()
time.sleep(5)
Pan3.clean()
Pan3 = screen()
threading.Thread(target=start).start()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit(); sys.exit();
if event.type == pygame.MOUSEBUTTONDOWN:
print 'Event! Mouse Down! Code here....'

A timer may suit your needs, given that you also use threading.
EDIT: Addressing your needs for a more detailed explanation as to how to get it to work, here's some pseudo-code.
if event.type == pygame.MOUSEBUTTONDOWN:
if active_timer:
timer.cancel()
timer = Timer(5.0, show_info_things)
timer.start()
I hope this gets you going well enough.

When you click left mouse first time then it shows date, when you click second time then it hides date. If you don't click second time then it hides automatically after 5 seconds.
The same with key SPACE - first press shows, second hides. If you don't press second time then it hides automatically after 5 seconds.
Key ESC and right click hides too.
import pygame
import sys
import time
# --- constants --- (UPPER_CASE names)
WHITE = (255,255,255)
BLACK = ( 0, 0, 0)
BLUE = ( 0, 0,255)
WIDTH = 600
HEIGHT = 400
# --- classes --- (CamelCase names)
class Screen(object):
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT), 0, 32)
pygame.display.set_caption('PyTV')
self.font = pygame.font.SysFont('Arial', 25)
self.channel = '0001'
self.name = 'Channel 3'
self.show_data = None
self.current_time = pygame.time.get_ticks()
def draw_data(self):
self.rect = pygame.draw.rect(self.screen, BLUE, (0, 0, WIDTH, HEIGHT-350), 0)
self.screen.blit(self.font.render(self.channel, True, WHITE), (WIDTH-590, 0))
self.screen.blit(self.font.render(self.name, True, WHITE), (HEIGHT-335, 0))
self.screen.blit(self.font.render(time.strftime("%H:%M:%S %d/%m/%Y", time.gmtime()), True, WHITE), (WIDTH-590, HEIGHT-377))
def events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
return False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.show_data = None
elif event.key == pygame.K_SPACE:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
if self.show_data:
self.show_data = None
else:
self.show_data = self.current_time + 5000
elif event.button == 3:
# hide on right click
self.show_data = None
def update(self):
# if displayed
if self.show_data:
# check time
if self.current_time >= self.show_data:
# hide after time
self.show_data = None
def draw(self):
self.screen.fill(BLACK)
if self.show_data:
self.draw_data()
pygame.display.update()
def run(self): # mainloop
while True:
self.current_time = pygame.time.get_ticks()
if self.events() is False:
break
self.update()
self.draw()
#sys.exit()
# --- fucntions --- (lower_case names)
# empty
# --- main ---
if __name__ == '__main__':
Screen().run()

Related

Why does my button not work outside of the main loop

I have been following this tutorial about animated buttons in pygame. It worked perfectly until I created a button outside of the main loop in another function.
Here is my code:
import pygame
from pygame.locals import *
import sys
import random
# Constants
SCREEN = pygame.display.set_mode((1280, 720), 0, 32)
# Colours
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREY = (100, 100, 100)
LIGHT_BLUE = (66, 233, 245)
# Button Class
class Button:
def __init__(self, text, width, height, pos, elevation):
# Core attributes
self.pressed = False
self.elevation = elevation
self.dynamicElevation = elevation
self.originalYPos = pos[1]
# Top Rectangle
self.topRectangle = pygame.Rect(pos, (width, height))
self.topColor = '#457B9D'
# Bottom Rectangle
self.bottomRectangle = pygame.Rect(pos, (width, elevation))
self.bottomColor = '#1D3557'
# Text
self.textSurface = gui_font.render(text, True, '#FFFFFF')
self.textRectangle = self.textSurface.get_rect(center = self.topRectangle.center)
def draw(self):
# Elevation Logic
self.topRectangle.y = self.originalYPos - self.dynamicElevation
self.textRectangle.center = self.topRectangle.center
self.bottomRectangle.midtop = self.topRectangle.midtop
self.bottomRectangle.height = self.topRectangle.height + self.dynamicElevation
bottom =pygame.draw.rect(SCREEN, self.bottomColor, self.bottomRectangle, border_radius = 12)
top = pygame.draw.rect(SCREEN, self.topColor, self.topRectangle, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', top, 1, border_radius = 12)
pygame.draw.rect(SCREEN, '#000000', bottom, 1, border_radius = 12)
SCREEN.blit(self.textSurface, self.textRectangle)
self.check_click()
def check_click(self):
mousePosition = pygame.mouse.get_pos()
if self.topRectangle.collidepoint(mousePosition):
self.topColor = '#F1FAEE'
if pygame.mouse.get_pressed()[0]:
self.dynamicElevation = 0
self.pressed = True
else:
self.dynamicElevation = self.elevation
if self.pressed == True:
print("Click")
self.pressed = False
else:
self.topColor = '#457B9D'
class GameState():
def __init__(self):
self.state = "welcome"
def welcomeScreen(self):
SCREEN.fill(WHITE)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F1:
self.state = "mainGame"
pygame.display.update()
def mainGame(self):
SCREEN.fill(GREY)
buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
buttonBack.draw()
pygame.display.update()
def stateManager(self):
if self.state == "welcome":
self.welcomeScreen()
if self.state == "mainGame":
self.mainGame()
pygame.init()
clock = pygame.time.Clock()
gameState = GameState()
pygame.display.set_caption("Button Test")
gui_font = pygame.font.Font(None, 30)
while True:
gameState.stateManager()
clock.tick(60)
I have tried to play around with putting the button in a different screen or at different stages of the loop. Is there a logic error I cannot see or lies my mistake somewhere else?
You are actually creating the button inside the main loop since you create it each time mainGame is called. mainGame is called by stateManager if the state is "mainGame", and that's called at each frame in your while True loop. So as you are recreating your button at each frame I think your problems might come from there.
I suggest you create your button in the parent's class constructor instead:
class GameState():
def __init__(self):
self.state = "welcome"
# Create the button here to make the object persistent.
self.buttonBack = Button("Back to Main Screen", 250, 30, (1000, 650), 8)
# ...
def mainGame(self):
SCREEN.fill(GREY)
for event in pygame.event.get():
if event.type == QUIT:
exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
exit()
if event.key == K_F2:
self.state = "welcome"
self.buttonBack.draw() # <- use your button with self.buttonBack
pygame.display.update()
# ...

How to display an FPS counter in pygame?

I have recently started learning pygame, and I'd like to have an FPS counter displayed in the top left of the screen. I have that already done but when I start my game the FPS counter displays this, which is not what I'd like. I'd like the counter to display just two numbers, which would be 60 in that picture. This is my code so far:
class FPSCounter:
def __init__(self, surface, font, clock, color, pos):
self.surface = surface
self.font = font
self.clock = clock
self.pos = pos
self.color = color
self.fps_text = self.font.render(str(int(self.clock.get_fps())) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
def render(self):
self.surface.blit(self.fps_text, self.fps_text_rect)
def update(self):
self.fps_text = self.font.render(str(self.clock.get_fps()) + "FPS", False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))
And this is how I'd display it in my game:
import pygame, sys
from fps_counter import FPSCounter
pygame.init()
clock = pygame.time.Clock()
black = (0, 0, 0)
green = (0, 0, 255)
width = 640
height = 480
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("FPS Test")
font = pygame.font.Font(None, 36)
fps_counter = FPSCounter(screen, font, clock, green, (150, 10))
while True:
screen.fill(black)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
pygame.quit()
sys.exit()
fps_counter.render()
fps_counter.update()
pygame.display.update()
clock.tick(60)
Thank you in advance. :)
All you need to do is to format the text. See Format String Syntax:
class FPSCounter:
# [...]
def update(self):
text = f"{self.clock.get_fps():2.0f} FPS"
self.fps_text = self.font.render(text, False, self.color)
self.fps_text_rect = self.fps_text.get_rect(center=(self.pos[0], self.pos[1]))

Pygame display does not update

I am making a game in pygame, but the display doesn't update. I am using the update() function and am clearing the screen at the beginning of the loop with fill(). Pygame also does not load very quickly; I have to hit "quit" on the pygame application once it shows in the running applications on my mac for the screen to appear.
"Module Imports"
import pygame as pg
import shelve
"Import Classes"
from Settings import Settings
from Settings import Screen
from Settings import Save
from Random import Random
from Input import Input
from Input import Button
# Init Classes
Settings = Settings()
Screen = Screen()
Random = Random()
Save = Save()
on = True
pg.init()
event_const = pg.event.wait()
save_file = shelve.open("/Volumes/HISTORYGAME/Game_Saves/Save_File")
clock = pg.time.Clock()
MainDisplay = pg.display.set_mode((Screen.width, Screen.height))
pg.display.set_caption(Settings.title)
pg.display.init()
class Mouse:
def __init__(self):
self.left = False
self.right = False
Mouse = Mouse()
def begin_game():
players = []
num_players = input("How Many Players (enter int): ")
save_file["num_players_var"] = num_players
for pl in range(num_players):
players.append(raw_input("Enter Player Name: "))
save_file["players_var"] = players
print(players)
def intro():
intro = True
for event in pg.event.get():
if event.get == pg.QUIT:
intro = False
on = False
if event.get == pg.event.KEYDOWN:
pass
# begin_game()
test_button = Button(0, 0, 200, 200, "Enter Text Here", MainDisplay)
buttons = []
buttons.append(test_button)
loops = 0
test_x = 10
test_y = 10
while on:
MainDisplay.fill((0, 0, 0))
for event in pg.event.get():
if event.type == pg.QUIT:
On = False
pg.quit()
exit()
if event.type == pg.KEYDOWN:
if event.key == pg.K_ESCAPE:
On = False
pg.quit()
exit()
if event.key == pg.K_RIGHT:
test_x += 10
print("right")
if event.type == pg.MOUSEBUTTONDOWN:
if event.button == 1:
Mouse.left = True
else:
Mouse.left = False
if event.type == pg.MOUSEBUTTONUP:
if event.button == 1:
Mouse.left = False
for button in buttons:
button.draw(pg.mouse.get_pos(), event_const)
if button.clicked is True:
print("True \n" * 100)
pg.draw.line(MainDisplay, (255, 0, 0), (100, 100), (600, 600))
pg.draw.rect(MainDisplay, (255, 0, 0), (test_x, test_y, 20, 20))
pg.display.flip()
pg.display.update()
clock.tick(Settings.FPS)
loops += 1
print(str(loops))
I suspect the waiting for an event, or reading of the stdin with input() is causing a lockup issue. But in the presented code, the call to this is commented-out. It's not possible to really know.
This version of the code, with a re-created Button class works ok, but obviously it doesn't have any of the referenced classes.
"Module Imports"
import pygame
#import shelve
"Import Classes"
#from Settings import Settings
#from Settings import Screen
#from Settings import Save
#from Random import Random
#from Input import Input
#from Input import Button
# Init Classes
#Settings = Settings()
#Screen = Screen()
#Random = Random()
#Save = Save()
WINDOW_WIDTH = 600
WINDOW_HEIGHT = 600
class Mouse:
def __init__(self):
self.left = False
self.right = False
class Button:
def __init__( self, x, y, width, height, label, window ):
self.rect = pygame.Rect( x, y, width, height )
self.clicked = False
self.window = window
self.font = pygame.font.Font( None, 20 )
self.label = self.font.render( label, True, ( 255, 255, 255 ) ) # large white text
def draw( self, mouse_pos ):
if ( self.rect.collidepoint( mouse_pos ) ):
colour = ( 0, 200, 0 ) # green if mouse over
else:
colour = (0, 0, 200) # blue otherwise
pygame.draw.rect( self.window, colour, self.rect, 0 ) # filled rectangle
# centred text
label_rect = self.label.get_rect()
x_offset = ( self.rect.width - label_rect.width ) // 2
y_offset = ( self.rect.height - label_rect.height ) // 2
self.window.blit( self.label, ( x_offset, y_offset ) )
def checkClick( self, mouse_pos ):
if ( self.rect.collidepoint( mouse_pos ) ):
self.clicked = True
else:
self.clicked = False
def begin_game():
players = [ "Mork", "Mindy", "E.T." ] # test data
#players = []
#num_players = input("How Many Players (enter int): ")
#save_file["num_players_var"] = num_players
#for pl in range(num_players):
# players.append(raw_input("Enter Player Name: "))
#save_file["players_var"] = players
print(players)
# Initialisation
pygame.init()
pygame.font.init()
#event_const = pygame.event.wait()
#save_file = shelve.open("/Volumes/HISTORYGAME/Game_Saves/Save_File")
clock = pygame.time.Clock()
window = pygame.display.set_mode( ( WINDOW_WIDTH, WINDOW_HEIGHT ) )
pygame.display.set_caption( "Settings.title" )
pygame.display.init()
Mouse = Mouse()
begin_game()
test_button = Button(0, 0, 200, 200, "Enter Text Here", window)
buttons = []
buttons.append(test_button)
loops = 0
test_x = 10
test_y = 10
on = True
while on:
window.fill((0, 0, 0))
for event in pygame.event.get():
if event.type == pygame.QUIT:
on = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
on = False
elif event.key == pygame.K_RIGHT:
test_x += 10
print("right")
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
Mouse.left = True
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
Mouse.left = False
for button in buttons:
button.checkClick( event.pos ) # buttons actuate on mouse-up
for button in buttons:
button.draw( pygame.mouse.get_pos() ) #, event_const)
if button.clicked is True:
print("True \n" * 5) # 100
pygame.draw.line(window, (255, 0, 0), (100, 100), (600, 600))
pygame.draw.rect(window, (255, 0, 0), (test_x, test_y, 20, 20))
pygame.display.flip()
#pygame.display.update() # only need update() or flip()
clock.tick( 60 ) #Settings.FPS)
loops += 1
#print(str(loops)) # Too noisy
# exiting
pygame.quit()

Comparing keypressed to a char

I want to make some sort of typing game in python using pygame. So, if the key pressed character is the same as the character in the word, it should return true... Is there any way to do this in python?
For example:
the word is "cat", if the user presses the key 'c', then it returns true... and so on for the rest of the characters.
here's my main.py file
from time import sleep
import pygame
import random
import winsound
from words import Words
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
pygame.init()
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
done = False
clock = pygame.time.Clock()
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
w1 = Words(screen) #making a single word (for now) to see if typing works
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
w1.draw()
#attempting to write code here to compare word and user input
pygame.display.flip()
clock.tick(60)
pygame.init()
exit()
here's my words.py file
from random_words import RandomWords
import pygame
import random
from queue import *
rw = RandomWords()
class Words():
def __init__(self, screen):
self.screen = screen
self.x_point = 400
self.y_point = 400
self.word = rw.random_word() #generates a random word
self.queue = Queue() #was hoping to use the queue so that if the user types the char correctly in the right order, then the letter would change color or something (but that's further down the line)
for c in self.word: #iterate through randomized word..
self.queue.put(c) #add each char in randomized word to queue, for typing reasons
def getY(self):
return self.y_point
def draw(self):
#creates a new object
myfont = pygame.font.SysFont('Comic Sans MS' ,30)
#creates a new surface with text drawn on it
textsurface = myfont.render(self.word, False, (0,0,0))
self.screen.blit(textsurface,(self.x_point,self.y_point))
Event KEYDOWN has event.unicode, event.key, event.mod
You can compare
if event.type == pygame.KEYDOWN:
if event.unicode == "a":
or even
if event.type == pygame.KEYDOWN:
if event.unicode.lower() == "a":
to check "a" and "A"
To check char in word
if event.type == pygame.KEYDOWN:
if event.unicode.lower() in your_word.lower():
Example code use event.unicode to render text with pressed keys.
BTW: It is not some Entry widget so it doesn't delete char when you press backspace.
import pygame
# --- constants ---
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
BLUE = ( 0, 0, 255)
GREEN = ( 0, 255, 0)
RED = (255, 0, 0)
SCREEN_WIDTH = 300
SCREEN_HEIGHT = 200
FPS = 5 # `FPS = 25` is enough for human eye to see animation.
# If your program don't use animation
# then `FPS = 5` or even `FPS = 1` can be enough
# --- main ---
# - init -
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# - objects -
font = pygame.font.SysFont(None, 30)
text = ""
text_image = font.render(text, True, GREEN)
text_rect = text_image.get_rect() # get current size
text_rect.center = screen_rect.center # center on screen
# - mainloop -
clock = pygame.time.Clock()
done = False
while not done:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
text += event.unicode
text_image = font.render(text, True, GREEN)
text_rect = text_image.get_rect() # get current size
text_rect.center = screen_rect.center # center on screen
# - draws -
screen.fill(BLACK)
screen.blit(text_image, text_rect)
pygame.display.flip()
clock.tick(FPS)
# - end -
pygame.quit() # <-- quit(), not init()

Python sin and cosine giving incorrect values

I have code that draws a line from 2 points; One on the middle bottom of the screen, and the other to the mouse pointer. I am trying to constrain the point by not exceeding a length parameter that I set. Heres the code:
import pygame
import Resources as r
import math as m
pygame.init()
class Segment():
def __init__(self, _screen, _id, _start_pos, _length):
self.screen = _screen
self.id = _id
self.start_pos = _start_pos
self.length = _length
def update(self):
if self.id == 1:
mouse_pos = pygame.mouse.get_pos()
self.angle = m.atan2(mouse_pos[1]-self.start_pos[1],mouse_pos[0]-self.start_pos[0])
self.a = self.start_pos
self.b = (m.cos(self.angle)*self.length, m.sin(self.angle)*self.length)
self.draw_line(self.a, self.b, r.black, 4)
def draw_line(self, start, end, color, width):
if self.id == 1:
pygame.draw.line(self.screen, color, start, end, width)
def get_data(self):
return (self.start_pos, self.end_)
I am seeing very different results when I run this that I would expect, it doesnt line up with my mouse and often just oscillates back and forth when the mouse is moved.
self.b is calculated based on origin 0, 0, not self.start_pos.
Add coordinates in self.a to self.b.
EDIT: as skrx pointed out in comment: mouse position doesn't have to be converted to Vector2 because tuple-Vector2 gives Vector2.
You can do the same with python.math.Vector2
Your start point on the middle bottom of the screen
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
start = pygame.math.Vector2(screen_rect.centerx, screen_rect.bottom)
And end point using mouse positon and length
#mouse = pygame.math.Vector2(pygame.mouse.get_pos()) # edited
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
And now you can draw
pygame.draw.line(screen, (255,0,0), start, end)
Working example
import pygame
# === CONSTANS === (UPPER_CASE names)
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 400
# === MAIN === (lower_case names)
# --- init ---
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
screen_rect = screen.get_rect()
# --- objects ---
start = pygame.math.Vector2(screen_rect.centerx, screen_rect.bottom)
end = start
length = 150
# --- mainloop ---
clock = pygame.time.Clock()
is_running = True
while is_running:
# --- events ---
for event in pygame.event.get():
# --- global events ---
if event.type == pygame.QUIT:
is_running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
is_running = False
elif event.type == pygame.MOUSEMOTION:
#mouse = pygame.math.Vector2(pygame.mouse.get_pos()) # edited
mouse = pygame.mouse.get_pos()
end = start + (mouse - start).normalize() * length
# --- objects events ---
# empty
# --- updates ---
# empty
# --- draws ---
screen.fill(BLACK)
pygame.draw.line(screen, RED, start, end)
pygame.display.update()
# --- FPS ---
clock.tick(25)
# --- the end ---
pygame.quit()
Red line has always the same length and it shows direction to cursor.

Categories