Sunday, October 18, 2020

Make an Analog Clock Using pygame and python

 

analog-clock-pygame
Analog Clock using Pygame

Contents

  1. Introduction
  2. Source Code
  3. Resources
  4. Explanation


The Pygame library is used to build simple games and to create simple animations using images. In this article, we will build a simple analog clock using this library. In the following sections, we have provided the source code and explained it in detail but before going further please download the required resources for this python project from the 'Resource Section' and make sure that pygame library is downloaded in your system.
You can install pygame by running the following command in the command prompt or terminal,  
pip install pygame
Click here if the PIP command is not working.

import pygame,sys
import datetime
pygame.init()

#section1 Font = pygame.font.Font('font.ttf',100) Font2 = pygame.font.Font('FONT2.ttf',30) display = pygame.display.set_mode((640,640)) pygame.display.set_caption('Clock') bg = pygame.image.load('bg.png') disc= pygame.image.load('disc_3.png').convert_alpha() disc= pygame.transform.scale(disc,(350,350)) disc_rect = disc.get_rect(center=(320,320))

#section2 s_hand=pygame.image.load('s_hand12.png').convert_alpha() s_rect=s_hand.get_rect(center=(325,325)) s_handc=s_hand.copy() m_hand = pygame.image.load('m_hand.png') m_rect = m_hand.get_rect(center=(320,320)) m_handc= m_hand.copy() h_hand = pygame.image.load('h_hand.png') h_rect = h_hand.get_rect(center=(320,320)) h_handc= h_hand.copy() fps = pygame.time.Clock()

#section3 def showDateTime(Time): week_day = Time.strftime('%A') LocalT = Time.strftime('%X') LocalT_surface = Font2.render(LocalT,True,(42,30,30)) LocalT_rect=LocalT_surface.get_rect(topright=(470,545)) week_surface = Font.render(week_day,True,(42,30,30)) week_rect = week_surface.get_rect(center=(470,515)) display.blit(week_surface,week_rect) display.blit(LocalT_surface,LocalT_rect) def rotate(image,angle): new_image = pygame.transform.rotozoom(image,-angle,1) return new_image

#section4 while True: time = datetime.datetime.now() s_angle=int(time.strftime('%S'))*6 m_angle=int(time.strftime('%M'))*6 h_angle=int(time.strftime('%I'))*30 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() display.blit(bg,(0,0)) display.blit(disc,disc_rect) h_handc=rotate(h_hand,h_angle) h_rect=h_handc.get_rect(center=(320,320)) display.blit(h_handc,h_rect) m_handc=rotate(m_hand,m_angle) m_rect=m_handc.get_rect(center=(320,320)) display.blit(m_handc,m_rect) s_handc = rotate(s_hand,s_angle) s_rect=s_handc.get_rect(center=(320,320)) display.blit(s_handc,s_rect) showDateTime(time) pygame.display.update() fps.tick(60)

The following zip file contains all of the image files and other resources required for this project.
Click here to download this file.



Section 1 :
 
In this section two pygame.font.Font objects are created and stored in variables named 'Font' and 'Font2'.
"display = pygame.display.set_mode((640,640))", this creates an object of type pygame.Surface having width and height of 640X640 pixels and named it as 'Clock' using the pygame function "pygame.display.set_caption(<string>)".
Using "pygame.image.load(<image path>)", we have loaded the background and the clock face image in the variables bg and disc respectively and transformed the clock face size for better alignment to the center using  "pygame.transform.scale()" method. In the next line we have creates a rect object for the clock face and aligned its center to the center of the display using "dics.get_rect(center=(320,320))".


Section 2  :

In section 2 we have loaded all of the required images in our program and created their rect objects using "pygame.image.load()" and "<image_surface>.get_rect(center=(x,y))" methods respectively and aligned their centers to the center of the main display screen.
  • s_hand: Holds image of the second hand.
  • s_rect: Holds the rect object of the s_hand.
  • s_handc: Holds a copy of the s_hand.
  • m_hand: Holds image of the minute's hand.
  • m_rect: Holds the rect object of the h_hand
  • m_handc: Holds a copy of the m_hand
  • h_hand: Holds the image of the hour hand.
  • h_rect: Holds the rect object of the h_hand
  • h_handc: Holds a copy of the h_hand

Section 3 :

In this section, we will go through all of the user-defined methods that are created to add more functionality to the code.
All of the following methods in this section deals with the movement of the clock hands and displaying the necessary information.
  • showDateTime(<datetime.datetime object>): This method takes a "datetime.datetime" object and displays the day-name and the local time on the main surface. "Time.strftime('%A')" and "Time.strftime('%X')" returns the day name and the local time respectively. And in this program, we have stored both of them in the variables named week_day and LocalT. In the next lines, we have rendered the day-name and the local time using the font objects that have created in section1 and stored them into the variables LocalT_surface and week_surface respectively. For each of the objects week_day and LocalT we have created the rect objects as well to align them properly on the screen. In the end, this function displays the week_day and LocalT according to their rects using blit() method.
  • rotate(image, angle): This function takes an image and an angle as arguments and rotate that image according to the given angle using the method "pygame.transform.rotozoom(image,-angle,1)", "1" represents the scale of the new image, in other words, the size of the new image will be same as the old image as the scale factor is 1. And returns the new image.

section 4 :

This is the final section of our code. This section contains the game-loop or the infinite while loop that breaks only if the user decides to close the program.
The very first line inside the game loop calls a method named "datetime.datetime.now()" of module datetime, this method returns an object of type "datetime.datetime" that contains all of the information regarding the current local time and date. Using this object we can retrieve necessary information of the time and date.

"time.strftime('%S')" returns a string the current second (0-59), So we have converted that string to an integer value and multiplied it with 6 as for each second the second's hand of the clock move 6 ° and stored the value in a variable named "s_angle". Similarly, we have converted the minutes and hours to angles and stored the values into the respective variables("m_angle, h_angle"). 

Next is the event loop "for event in pygame . event.get():", this loop iterate through all of the events taking place during the runtime, and using this loop we can detect certain events and make our program to act upon them. In this program, we want to detect the event of clicking the close button so that we can break our infinite while loop and close the program safely, and  "if event.type==pygame.QUIT" do the same for us, it checks whether the event that took place is of type pygame.QUIT ( clicking of the quit button ).
If the above condition turns true then we simply call the methods pygame.quit() and sys.exit() to close the program.

Next, we put the background and the clock-face on the main screen using the "display.blit()". We have passed "bg,(0,0)" and "disc,disc_rect" respectively for the background and the clock-face.
For the clock hands, we call the rotate function that we have created and pass the respective hand image and the calculated angle and store the new returned image.
Again we update the rect objects of the images using the new returned images and align them to the center of the screen. And in the end, the image of the hands are displayed on the screen according to their rects using the blit() method.
eg.
  • h_handc=rotate(h_hand,h_angle) : Rotating the image.
  • h_rect = h_handc.get_rect(enter=(320,320)): Updating the rect object.
  • display.blit(h_handc,h_rect): Displaying the image of the hand on the main surface named "display"
In the end, we call the showDateTime() method to display the local time and the day-name on the screen and update the main surface(screen/display) using pygame.display.update(). And we also have limited the fps using fps.tick(60), This method limits the number of the cycle of the game loop to 60 cycles per seconds.

And that's it, we have successfully created an analog clock using pygame. Now you can add extra features to it and modify it according to your wish and don't forget to check our other pygame projects.