The code for loading a background image and making it transparent is:
# Load and set up graphics.
background_image = pygame.image.load("clock2.jpg").convert()
background_image.set_colorkey(WHITE) #make it transparent
You need to write commands for drawing the hands. In Pygame a line is defined by its endpoints. Naturally the center of the screen is width/2, height/2, but the other end of the hand is a math problem! What would be the best coordinate system to use? It wouldn't be easy to point to a specific point in Cartesian (x- and y-) coordinates but it's not hard to figure out how far to rotate the hand in polar coordinates. See my book Hacking Math Class for how to explore polar coordinates using Python. Here's how to find our point using the length of the hands and the angle of rotation:
The length of the hand is r. I made all the hands the same length for testing. They'd be different colors, though:
# Define some colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
#clock hands:
hour_length = 290
minute_length = 290
second_length = 290
Unlike the figure above, in a clock face the rotation is, well, clockwise from straight up. The easy solution to that is to switch sine and cosine. Now what's theta? All programming languages measure angles in radians, not degrees. No problem: import pi from the math or numpy module and 2*pi is a whole circle.
from math import pi, sin, cos
Each hour is a twelfth of the whole circle, or 2*pi/12. That means if it's 1 o'clock, the rotation is 1 * 2*pi divided by 12, 2 o'clock would be 2 * 2*pi /12 and so on. That makes the code for our hour hand this:
#draw hour hand
h_theta = hour*2*pi/12
and the Pygame syntax for drawing a line:
h_tip = [300+hour_length*sin(h_theta), 300-hour_length*cos(h_theta)]
pygame.draw.line(screen, BLACK, [300,300], h_tip, 2)
The "300" comes from the fact that the center of my clock is (300,300).
So that draws a perfect hour hand. Here's 1 and 2 o'clock:
hour = 1 or hour = 2
Let's add a minute hand. Now the circle (2*pi radians) is cut up into 60 slices, so we'll add that to our code:
#draw minute hand
m_theta = minute*2*pi/60
m_tip = [300+minute_length*sin(m_theta), 300- \ minute_length*cos(m_theta)]
pygame.draw.line(screen, BLUE, [300,300], m_tip, 2)
It'll be just as long as the hour hand, but blue instead of black. Now 1:00 looks like this:
That's correct, but when I put in 1:30 I get an incorrect clock:
hour = 1
minute = 30
The hour hand should be halfway between the 1 and the 2. Every hour the hour hand moves 2 * pi/12 radians but it should move 1/60th of that every minute. I'm changing the hour hand code to this:
h_theta = hour*2*pi/12 + minute*2*pi/(12*60)
That should fix the mistake:
h_theta = hour*2*pi/12 + minute*2*pi/(12*60)
...
m_theta = minute*2*pi/60 + second*2*pi/(60*60)
...
s_theta = second*2*pi/60
Of course, you need the usual Pygame code to get stuff on the screen. I highly recommend Professor Craven's tutorials, and that's where I got a template for Pygame programs.
Here's the whole code:
import pygame
from pygame.locals import *
from math import pi, sin, cos
from random import randint
# Define some colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
#clock hands:
hour_length = 290
minute_length = 290
second_length = 290
#Change these numbers to show the time:
hour = 1
minute = 45
second = 50
# Create an 600x600 sized screen
screen = pygame.display.set_mode([600, 600])
# This sets the name of the window
pygame.display.set_caption('Clocks!')
# Set positions of graphics
background_position = [0, 0]
# Load and set up graphics.
background_image = pygame.image.load("clock2.jpg").convert()
background_image.set_colorkey(WHITE)
# Call this function so the Pygame library can initialize itself
pygame.init()
clock = pygame.time.Clock()
done = False
#main loop:
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
screen.fill(WHITE)
# Copy image to screen:
screen.blit(background_image, background_position)
#draw hour hand
h_theta = hour*2*pi/12 +minute*2*pi/(12*60)
h_tip = [300+hour_length*sin(h_theta), 300-hour_length*cos(h_theta)]
pygame.draw.line(screen, BLACK, [300,300], h_tip, 2)
#draw minute hand
m_theta = minute*2*pi/60 + second*2*pi/(60*60)
m_tip = [300+minute_length*sin(m_theta), 300-minute_length*cos(m_theta)]
pygame.draw.line(screen, BLUE, [300,300], m_tip, 2)
#draw seconds hand
s_theta = second*2*pi/60
s_tip = [300+second_length*sin(s_theta), 300-second_length*cos(s_theta)]
pygame.draw.line(screen, RED, [300,300], s_tip, 2)
pygame.display.flip()
clock.tick(60)
pygame.quit()
You can use the time module in Python to make a clock read the current time:
>>> import time
>>> the_time = time.time()
>>> dt = time.localtime(the_time)
>>> print(dt.tm_hour,":",dt.tm_min,":",dt.tm_sec)
16 : 41 : 33
In our clocks program just set the 'hour' variable equal to 'dt.tm_hour" and so on. Yes, you have a clock on your computer and your phone already but you made this one!
great explanation thanks
ReplyDelete