Minggu, 05 Oktober 2025

PYTHON - PYGAME - CLOCK

 





# Examples of the math.sin() and math.cos() trig functions in making a clock

# Al Sweigart al@inventwithpython.com


# You can learn more about Pygame with the

# free book "Making Games with Python & Pygame"

#

# http://inventwithpython.com/pygame

#


import sys, pygame, time, math

from pygame.locals import *


# set up a bunch of constants

BRIGHTBLUE = (  0,  50, 255)

WHITE      = (255, 255, 255)

DARKRED    = (128,   0,   0)

RED        = (255,   0,   0)

YELLOW     = (255, 255,   0)

BLACK      = (  0,   0,   0)


HOURHANDCOLOR = DARKRED

MINUTEHANDCOLOR = RED

SECONDHANDCOLOR = YELLOW

NUMBERBOXCOLOR = BRIGHTBLUE

BGCOLOR = WHITE


WINDOWWIDTH = 640 # width of the program's window, in pixels

WINDOWHEIGHT = 480 # height in pixels

WIN_CENTERX = int(WINDOWWIDTH / 2)

WIN_CENTERY = int(WINDOWHEIGHT / 2)



CLOCKNUMSIZE = 40 # size of the clock number's boxes

CLOCKSIZE = 200 # general size of the clock



# This function retrieves the x, y coordinates based on a "tick" mark, which ranges between 0 and 60

# A "tick" of 0 is at the top of the circle, 30 is at the bottom, 45 is at the "9 o'clock" position, etc.

# The "stretch" is how far from the origin the x, y return values will be

# "originx" and "originy" will be where the center of the circle is (almost always the center of the window)

def getTickPosition(tick, stretch=1.0, originx=WIN_CENTERX, originy=WIN_CENTERY):

    # uncomment to have a "rotating clock" feature.

    # This works by pushing the "tick" amount forward

    #tick += (time.time() % 15) * 4


    # The cos() and sin()

    tick -= 15


    # ensure that tick is between 0 and 60

    tick = tick % 60


    tick = 60 - tick


    # the argument to sin() or cos() needs to range between 0 and 2 * math.pi

    # Since tick is always between 0 and 60, (tick / 60.0) will always be between 0.0 and 1.0

    # The (tick / 60.0) lets us break up the range between 0 and 2 * math.pi into 60 increments.

    x =      math.cos(2 * math.pi * (tick / 60.0))

    y = -1 * math.sin(2 * math.pi * (tick / 60.0)) # "-1 *" because in Pygame, the y coordinates increase going down (the opposite of how they normally go in mathematics)


    # sin() and cos() return a number between -1.0 and 1.0, so multiply to stretch it out.

    x *= stretch

    y *= stretch


    # Then do the translation (i.e. sliding) of the x and y points.

    # NOTE: Always do the translation addition AFTER doing the stretch.

    x += originx

    y += originy


    return x, y



# these next 2 lines are used by the "pulsing clock" feature (see below)

originalClockSize = CLOCKSIZE

PULSESIZE = 20


# standard pygame setup code

pygame.init()

DISPLAYSURF = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))

pygame.display.set_caption('Trig Clock')

fontObj = pygame.font.Font('freesansbold.ttf', 26)


# render the Surface objects that have the clock numbers written on them

clockNumSurfs = [fontObj.render('%s' % (i), True, BGCOLOR, NUMBERBOXCOLOR)

                 for i in [12] + list(range(1, 12))] # Put 12 at the front of the list since clocks start at 12, not 1.



while True: # main application loop

    # event handling loop for quit events

    for event in pygame.event.get():

        if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):

            pygame.quit()

            sys.exit()


    # fill the screen to draw from a blank state

    DISPLAYSURF.fill(BGCOLOR)


    # draw the numbers and number boxes of the clock

    for i in range(12):

        # set up the Rect objects for the numbers and the number boxes

        clockNumRect = clockNumSurfs[i].get_rect()

        clockNumRect.center = getTickPosition(i * 5, CLOCKSIZE)


        clockNumBoxRect = clockNumSurfs[i].get_rect()

        clockNumBoxRect.size = (CLOCKNUMSIZE, CLOCKNUMSIZE)

        clockNumBoxRect.center = getTickPosition(i * 5, CLOCKSIZE)


        # draw the numbers and the number boxes

        pygame.draw.rect(DISPLAYSURF, NUMBERBOXCOLOR, clockNumBoxRect)

        DISPLAYSURF.blit(clockNumSurfs[i], clockNumRect)


    # get the current time

    now = time.localtime()

    now_hour = now[3] % 12 # now[3] ranges from 0 to 23, so we mod 12.

    now_minute = now[4]

    now_second = now[5] + (time.time() % 1) # add the fraction of a second we get from time.time() to make a smooth-moving seconds hand


    # Uncomment this if you don't want the second hand to move smoothly:

    #now_second = now[5]


    # draw the hour hand

    x, y = getTickPosition(now_hour * 5 + (now_minute * 5 / 60.0), CLOCKSIZE * 0.6)

    pygame.draw.line(DISPLAYSURF, HOURHANDCOLOR, (WIN_CENTERX, WIN_CENTERY), (x, y), 8)


    # draw the minute hand

    x, y = getTickPosition(now_minute + (now_second / 60.0), CLOCKSIZE * 0.8)

    pygame.draw.line(DISPLAYSURF, MINUTEHANDCOLOR, (WIN_CENTERX, WIN_CENTERY), (x, y), 6)


    # draw the second hand

    x, y = getTickPosition(now_second, CLOCKSIZE * 0.8)

    pygame.draw.line(DISPLAYSURF, SECONDHANDCOLOR, (WIN_CENTERX, WIN_CENTERY), (x, y), 2)


    # draw the second hand's part that sticks out behind

    x, y = getTickPosition(now_second, CLOCKSIZE * -0.2) # negative stretch makes it go in the opposite direction

    pygame.draw.line(DISPLAYSURF, SECONDHANDCOLOR, (WIN_CENTERX, WIN_CENTERY), (x, y), 2)


    # draw border

    pygame.draw.rect(DISPLAYSURF, BLACK, (0, 0, WINDOWWIDTH, WINDOWHEIGHT), 1)


    pygame.display.update()


    # Uncomment this if you want the "pulsing clock" feature:

    #CLOCKSIZE = originalClockSize + math.sin(2 * math.pi * (time.time() % 1)) * PULSESIZE


Tidak ada komentar: