python stop updating variables - python

I wrote this program which stops the time from the beginning of the program. But it want to display the time when I open the window and not when I start the code.
This is my function for the time right now:
def Time():
global myfont,minute
realtime = pygame.time.get_ticks() / 1000
time = int(pygame.time.get_ticks() / 1000 - minute*60 - realtime)
if time < 10:
label = myfont.render("Zeit: "+ str(minute) + ":0" + str(time) , 1, (255,255,255))
screen.blit(label, (x - 190, 20))
else:
label = myfont.render("Zeit: "+ str(minute) + ":" + str(time) , 1, (255,255,255))
screen.blit(label, (x - 190, 20))
if time / 60 == 1:
minute +=1
time = 0
label = myfont.render("Zeit: "+ str(minute) + ":" + str(time) , 1, (255,255,255))
screen.blit(label, (x - 190, 20))
I tried it by substracting the time that it ran until there with realtime. But the variable realtime keeps updating the same as time so it would display 0. Is there any way how I can take the value of realtime at the moment when I open the window?
Thanks for your help

Set a start_time variable when you open the window:
start_time = pygame.time.get_ticks()
Calculate the time difference in Time:
def Time():
global myfont,minute
current_time = pygame.time.get_ticks()
delta_time = current_time - start_time
realtime = delta_time / 1000
time = int(delta_time / 1000 - minute*60 - realtime)
# [...]

Related

How do I get an animation to happen at the location my enemy was last at when the enemy is removed Pygame [duplicate]

I don't know why explosion effect doesn't happen.
The other images were drawn well, but only explosion image didn't
explosion = pygame.image.load(os.path.join(image_path, "explosion.png"))
explosion_size = explosion.get_rect().size
explosion_width = explosion_size[0]
for missile_idx, missile_val in enumerate(missiles):
missile_pos_x = missile_val[0]
missile_pos_y = missile_val[1]
#weapon information upgrade
missile_rect = missile.get_rect()
missile_rect.left = missile_pos_x
missile_rect.top = missile_pos_y
if missile_rect.colliderect(rock_rect):
explosion_sound.play()
**explosion_pos_x = missile_pos_x
explosion_pos_y = missile_pos_y
screen.blit(explosion,(explosion_pos_x,explosion_pos_y))**
del(rock)
del(missiles)
missiles = []
# missile position coordination
missiles = [[m[0], m[1] - missile_speed] for m in missiles]
# top missile elimination
missiles = [[m[0], m[1]] for m in missiles if m[1]>0]
The explosion is just shown for a short moment. Use pygame.time.get_ticks() to return the number of milliseconds since pygame.init() was called. Calculate the point in time after that the explosion image has to be removed. Add the coordinates of the explosion and the end time point to the head of a list (explosionList ). Draw the explosion(s) in the main application loop. Remove the expired explosions from the tail of the list:
explosionList = []
while run:
current_time = pygame.time.get_ticks()
# [...]
for missile_idx, missile_val in enumerate(missiles)
# [...]
if missile_rect.colliderect(rock_rect):
explosion_sound.play()
explosion_pos_x = missile_pos_x
explosion_pos_y = missile_pos_y
end_time = current_time + 2000 # 2000 milliseconds = 2 seconds
explosionList.insert(0, (end_time, explosion_pos_x, explosion_pos_y))
# [...]
for i in range(len(explosionList)):
if current_time < explosionList[i][0]:
screen.blit(explosion, (explosionList[i][1], explosionList[i][2]))
else:
explosionList = explosionList[:i]
break
# [...]
With this algorithm it is possible to manage multiple explosions.
See Time, timer event and clock
Minimal example
import pygame
pygame.init()
window = pygame.display.set_mode((210, 210))
def create_rectangles():
global rectangles
w, h = window.get_size()
rectangles = []
for x in range(0, w - 60, 60):
for y in range(0, h - 60, 60):
rectangles.append(pygame.Rect(x + 30, y + 30, 30, 30))
create_rectangles()
hit_list = []
fade_out_time = 3000
run = True
while run:
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
point = pygame.mouse.get_pos()
collideindex = pygame.Rect(point, (1, 1)).collidelist(rectangles)
if collideindex >= 0:
end_time = current_time + fade_out_time
hit_list.insert(0, (end_time, rectangles[collideindex].center))
del rectangles[collideindex]
if not hit_list and not rectangles:
create_rectangles()
window.fill(0)
for r in rectangles:
pygame.draw.rect(window, (255, 0, 0), r)
for i in range(len(hit_list)):
delta_time = hit_list[i][0] - current_time
if delta_time > 0:
radius = round(30 * delta_time / fade_out_time)
pygame.draw.circle(window, (255, 255, 0), hit_list[i][1], radius)
else:
hit_list = hit_list[:i]
break
pygame.display.flip()
If you want to show explosion image for a while this method can be useful.
explosion_list = [] # list for explosion effect
running = True
while running:
start_time = pygame.time.get_ticks() # add time for explosion effect
for missile_idx, missile_val in enumerate(missiles):
missile_pos_x = missile_val[0]
missile_pos_y = missile_val[1]
#weapon information upgrade
missile_rect = missile.get_rect()
missile_rect.left = missile_pos_x
missile_rect.top = missile_pos_y
if missile_rect.colliderect(rock_rect):
explosion_sound.play()
explosion_pos_x = missile_pos_x
explosion_pos_y = missile_pos_y
explosion_time = start_time + 2000 # 1000 milliseconds = 2 seconds
**explosion_list.insert(0, (explosion_time, explosion_pos_x, explosion_pos_y))**
del(rock)
del(missiles)
missiles = []
# missile position coordination
missiles = [[m[0], m[1] - missile_speed] for m in missiles]
# top missile elimination
missiles = [[m[0], m[1]] for m in missiles if m[1]>0]
**for i in range(len(explosion_list)):
if start_time < explosion_time:
pygame.display.update()
screen.blit(explosion, (explosion_pos_x - 30, explosion_pos_y - 30))
pygame.time.delay(10)**
else:
explosion_list = explosion_list[:i]

How can I make Pygame wait a few milliseconds before every loop in a for loop without stopping other stuff?

I have a for loop in Pygame that is trying to slowly progress through a string, like how text scrolls in RPGs. I want it to wait around 7 milliseconds before displaying the next character in the string, but I don't know how to make the loop wait that long without stopping other stuff.
Please note that I am very new to pygame and python in general.
Here is my code:
mainText = pygame.font.Font(mainFont, 40)
finalMessage = ""
for letter in msg:
finalMessage = finalMessage + letter
renderMainText = mainText.render(finalMessage, True, white)
screen.blit(renderMainText, (100, 100))
renderMainText = mainText.render(finalMessage, True, white)
Do I need to do threading? Asyncrio?
You don't need the for loop at all. You have an application loop, so use it. The number of milliseconds since pygame.init() can be retrieved by pygame.time.get_ticks(). See pygame.time module.
next_letter_time = 0
next_letter = 0
run = True
while run:
current_time = pygame.time.get_ticks()
# [...]
if next_letter < len(msg):
if current_time > next_letter_time:
next_letter_time = current_time + 7000 # 7000 milliseconds = 7
finalMessage = finalMessage + msg[next_letter]
next_letter += 1
renderMainText = mainText.render(finalMessage, True, white)
Minimal example:
import pygame
pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
white = (255, 255, 255)
mainText = pygame.font.SysFont(None, 50)
renderMainText = None
finalMessage = ""
msg = "test text"
next_letter_time = 0
next_letter = 0
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
current_time = pygame.time.get_ticks()
if next_letter < len(msg):
if current_time > next_letter_time:
next_letter_time = current_time + 500
finalMessage = finalMessage + msg[next_letter]
next_letter += 1
renderMainText = mainText.render(finalMessage, True, white)
window.fill(0)
if renderMainText:
window.blit(renderMainText, (100, 100))
pygame.display.flip()
use this
#coroutine
def my_func():
from time import sleep
mainText = pygame.font.Font(mainFont, 40)
finalMessage = ""
for letter in msg:
finalMessage = finalMessage + letter
renderMainText = mainText.render(finalMessage, True, white)
screen.blit(renderMainText, (100, 100))
yield from sleep(0.007)
renderMainText = mainText.render(finalMessage, True, white)
async(my_func)
yield from is according to python 3.4
for more different versions check https://docs.python.org/3/
your function will run independently without interrupting other tasks after async(my_func)

Make images appear randomly and disappear after certain time

I am extremely confused as to how to approach this and I can't get it to work. So, if you have played snake before you will remember that at certain times an image would appear that if you ate that, you would get more points but if you missed it, it would disappear (i.e not stay there forever until you caught it.)
I have written code that works with time (allowing you to activate a shield) as below:
if (count % 35 == 0):
ang = random.choice(angles)
particles.append(Particle(red, 5, ang, user))
score += 10
score_graphic = font.render("Score " + str(score), 1, white)
total_shields += 1
if total_shields > 10:
total_shields = 10
count += 1
curr_time = time.time()
if space_press:
if (curr_time - new_time) > 0.3:
new_time = time.time()
total_shields -= 1
shield_on = total_shields > 0
How can I implement the disappearing image in pygame?
I know this is unconventional, but if you could help, I'd appreciate as I have not been able to do it for the past hour.
Best,
Seyed
use variables with time of start showing and end showing.
It is popular method to control different elements in game.
import pygame
import random
# - init -
pygame.init()
screen = pygame.display.set_mode((800, 600))
# - objects -
display_apple = False
start_showing = None
end_showing = None
current_time = pygame.time.get_ticks()
# show first time
start_showing = current_time + random.randint(1,5)*1000
# - mainloop -
clock = pygame.time.Clock()
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
# - updates -
current_time = pygame.time.get_ticks()
if display_apple:
# is it time to hide ?
if end_showing and current_time >= end_showing:
# hide it
display_apple = False
end_showinge = False
# set time when to show
start_showing = current_time + random.randint(1,5)*1000
else:
# is it time to show ?
if start_showing and current_time >= start_showing:
# show it
display_apple = True
start_showing = False
# set time when to hide
end_showing = current_time + random.randint(1,5)*1000
# - draws -
screen.fill((0,0,0))
if display_apple:
pygame.draw.rect(screen, (255,0,0), (0,0,100,100))
pygame.display.flip()
# - FPS -
clock.tick(30)
# - end -
pygame.quit()

How to make a mouse click do something at a specific point?

how can I make the mouse do something once it's clicking at a certain point in Zelle's graphics? What I am trying to do is make my stopwatch start when I click the "startbutton" image. However, I am obviously doing something wrong because my program either crashes or doesn't do anything.
from graphics import *
import time
#from tkinter import *
win = GraphWin('Stopwatch', 600, 600)
win.yUp()
#Assigning images
stopWatchImage = Image(Point (300, 300), "stopwatch.png")
startImage = Image(Point (210, 170), "startbutton.png")
stopImage = Image(Point (390, 170), "stopbutton.png")
lapImage = Image(Point (300, 110), "lapbutton.png")
stopWatchImage.draw(win)
startImage.draw(win)
stopImage.draw(win)
lapImage.draw(win)
sec = 0
minute = 0
hour = 0
def isBetween(x, end1, end2):
'''Return True if x is between the ends or equal to either.
The ends do not need to be in increasing order.'''
return end1 <= x <= end2 or end2 <= x <= end1
def isInside(point, startImage):
'''Return True if the point is inside the Rectangle rect.'''
pt1 = startImage.getP1()
pt2 = startImage.getP2()
return isBetween(point.getX(), pt1.getX(), pt2.getX()) and \
isBetween(point.getY(), pt1.getY(), pt2.getY())
def getChoice(win): #NEW
'''Given a list choicePairs of tuples with each tuple in the form
(rectangle, choice), return the choice that goes with the rectangle
in win where the mouse gets clicked, or return default if the click
is in none of the rectangles.'''
point = win.getMouse()
if isInside(point, startImage):
time.sleep(1)
sec += 1
timeText.setText(sec)
timeText.setText('')
while sec >= 0 and sec < 61:
#Displaying Time
timeText = Text(Point (300,260), str(hour) + ":" + str(minute) + ":" + str(sec))
timeText.setSize(30)
timeText.draw(win)
time.sleep(1)
sec += 1
timeText.setText(sec)
timeText.setText('')
#Incrementing minutes,hours
if sec == 60:
sec = 0
minute += 1
if minute == 60:
sec = 0
minute = 0
hour += 1
return default
def layout()
getChoice(win)
layout()
I can't seem to get it to work.
Edit: added the rest of my code for clarification.
You can use setMouseHandler to assign function which will called when you click in window.
In example if you click in left part of window then it draws rectangle, if you click in right part of window then it draws circle.
You can open file graphics.py and see all code. It is the fastest method to can see what functions you can use.
from graphics import *
# --- functions ---
def on_click(point):
# inform function to use global variable
global win
if point.x > win.width//2:
c = Circle(point, 10)
c.draw(win)
else:
a = Point(point.x - 10, point.y - 10)
b = Point(point.x + 10, point.y + 10)
r = Rectangle(a, b)
r.draw(win)
def main():
# inform function to use global variable
global win
win = GraphWin("My Circle", 500, 500)
win.setMouseHandler(on_click)
win.getKey()
win.close()
# --- start ---
# create global variable
win = None
main()
BTW: graphics uses Tkinter which has widgets Button, Label, Text, etc. It can use canvas.create_window() to add widget to canvas.
Tkinter has also function after(miliseconds, function_name) which lets you execute function periodically - ie. to update time.
Example
from graphics import *
import datetime
# --- classes ---
class _Widget():
def __init__(self, x, y, w, h, **options):
self.x = x
self.y = y
self.w = w
self.h = h
self.options = options
def draw(self, canvas, **options):
return None
def set(self, **options):
self.widget.config(options)
def get(self, **options):
self.widget.cget(options)
class Button(_Widget):
def draw(self, canvas, **options):
x, y = canvas.toScreen(self.x, self.y) # ???
self.widget = tk.Button(canvas, self.options)
return canvas.create_window((x, y), options, width=self.w, height=self.h, window=self.widget, anchor='nw')
class Label(_Widget):
def draw(self, canvas, **options):
x, y = canvas.toScreen(self.x, self.y) # ???
self.widget = tk.Label(canvas, self.options)
return canvas.create_window((x, y), options, width=self.w, height=self.h, window=self.widget, anchor='nw')
# --- functions ---
def on_start():
#global b1, b2
global running
b1.set(state='disabled')
b2.set(state='normal')
running = True
# run first time
update_time()
print("START")
def on_stop():
#global b1, b2
global running
b1.set(state='normal')
b2.set(state='disabled')
l.set(text="Controls:")
running = False
print("STOP")
def update_time():
#global l
#global running
if running:
l.set(text=datetime.datetime.now().strftime("%H:%M:%S"))
# run again after 1000ms (1s)
win.after(1000, update_time)
# --- main ---
def main():
global win, l, b1, b2
win = GraphWin("My Buttons", 500, 500)
l = Label(0, 0, 100, 50, text="Controls:")
l.draw(win)
b1 = Button(100, 0, 100, 50, text="START", command=on_start)
b1.draw(win)
b2 = Button(200, 0, 100, 50, text="STOP", command=on_stop, state='disabled')
b2.draw(win)
win.getKey()
win.close()
# --- global variable to access in functions ---
win = None
l = None
b1 = None
b2 = None
running = False
# --- start ---
main()
Tkinter: Canvas, Button, other
EDIT: working example
from graphics import *
def isBetween(x, end1, end2):
return end1 <= x <= end2 or end2 <= x <= end1
def isInside(point, startImage):
x = startImage.getAnchor().getX()
y = startImage.getAnchor().getY()
w = startImage.getWidth()/2
h = startImage.getHeight()/2
pt1_x = x - w
pt1_y = y - h
pt2_x = x + w
pt2_y = y + h
return isBetween(point.getX(), pt1_x, pt2_x) and \
isBetween(point.getY(), pt1_y, pt2_y)
def getChoice(event):
global hour, minute, sec
global running
point = Point(round(event.x), round(event.y))
if isInside(point, startImage):
sec = 0
minute = 0
hour = 0
running = True
update_time()
if isInside(point, stopImage):
running = False
def update_time():
global hour, minute, sec
#global timeText
#global win
sec += 1
if sec == 60:
sec = 0
minute += 1
if minute == 60:
minute = 0
hour += 1
timeText.setText('{}:{}:{}'.format(hour, minute, sec))
if running:
win.after(1000, update_time)
else:
timeText.setText('')
def layout():
global win
global stopWatchImage
global startImage
global stopImage
global lapImage
global timeText
win = GraphWin('Stopwatch', 600, 600)
#win.yUp()
#Assigning images
stopWatchImage = Image(Point(300, 300), "stopwatch.png")
startImage = Image(Point(210, 170), "startbutton.png")
stopImage = Image(Point(390, 170), "stopbutton.png")
lapImage = Image(Point(300, 110), "lapbutton.png")
#Drawing images
stopWatchImage.draw(win)
startImage.draw(win)
stopImage.draw(win)
lapImage.draw(win)
timeText = Text(Point(300,260), '')
timeText.setSize(30)
timeText.draw(win)
win.setMouseHandler(getChoice)
win.getKey()
# --- global variable ---
win = None
stopWatchImage = None
startImage = None
stopImage = None
lapImage = None
timeText = None
running = False
# --- start ---
layout()

Having issues getting a Scene to redraw

I recently started learning Python and just finished my courses on it on CodeAcademy, so I've been trying to come up with small projects to do in order to practice and really learn this language. What I'm trying to do is create a clock that will change colors as the time changes, I have the scene drawn but the time doesn't change with it, how do I get the scene to redraw every second?
from time import strftime
from scene import *
current_time = strftime("%b %d %Y %H:%M:%S")
hour = int(strftime("%H"))
min = int(strftime("%M"))
sec = int(strftime("%S"))
class Clock (Scene):
def draw (self):
self.hour = hour
self.min = min
self.sec = sec
background(0, 0, 0)
fill(0, 0, 0)
w, h = self.size.w, self.size.h
rect(w * 0.5 - 100, h * 0.5 - 100, 200, 200)
s = 40 if self.size.w > 700 else 17
text(current_time,
'Futura', s, *self.bounds.center().as_tuple())
dead = set()
run(Clock())
print current_time
print hex(hour)
print hex(min)
print hex(sec)`
You are only calculating the hour, minute, and second once, at the beginning of the script. second doesn't know that it represents the second, it just knows that it's a dumb integer. That's why it doesn't update itself when the time changes.
Try moving the strftimes into the draw method, so they execute every time the screen is redrawn.
def draw (self):
current_time = strftime("%b %d %Y %H:%M:%S")
hour = int(strftime("%H"))
min = int(strftime("%M"))
sec = int(strftime("%S"))
self.hour = hour
self.min = min
self.sec = sec
#...etc

Categories