pygame實現時鐘效果
用pygame做一個時鐘,供大傢參考,具體內容如下
剛剛學習pygame,由於基礎實在太差,每個例子都要反復寫逐句研究才能基本弄懂,這次做一個簡單的有時針、分針、秒針,能正確行走的表。。。例子不難,但是還是能掌握一些基本的知識點,比如xy坐標的計算,畫圓,文字處理等。小白如我可以借鑒下,我認為學習還是以邏輯為主,所以我盡量還原初學時候的邏輯步驟,不囉嗦瞭,開整!
前期準備
這次我們用到的主要是pygame,math,datetime幾個庫,datetime.today()可以獲取當前時間,math.sin()和math.cos()用於計算表針的坐標。用到的方法主要是pygame.draw.circle()畫圓,和pygame.draw.line()畫線
開始下手
先把pygame初始化,再弄個窗口出來,準備工作做好
import math, pygame from pygame.locals import * from datetime import datetime, date, time pygame.init() screen = pygame.display.set_mode((600, 600)) pygame.display.set_caption("Clock")
然後畫個圓當表盤,這樣就需要確定位置和半徑
pos_x = 300 pos_y = 300 radius = 250
考慮到區分三個表針的顏色,先設置好四種顏色
white = 255, 255, 255 red = 240, 0, 0 green = 0, 240, 0 blue = 0, 0, 240
計算表針的坐標,需要用到角度,所以先把角度設好
hour_angle = 0 minute_angle = 0 second_angle = 0
寫數字需要用到文字處理,把文字樣式設置一下
font = pygame.font.Font(None, 24)
最後還要寫兩個方法一個是輸出文字的,一個是規范角度的。這倆以後都經常用
# abs()是取絕對值,%運算符號很有意思,效果是360取餘數,保證瞭角度在360以內 def wrap_angle(angle): return abs(angle % 360) # 把打印文字的步驟封裝在一個方法裡,每次方便調用,簡化代碼 def print_text(font, x, y, text, color): imgText = font.render(text, True, color) screen.blit(imgText, (x, y))
好瞭,準備工作做完瞭,我們來寫循環
while True: for event in pygame.event.get(): if event.type == QUIT: exit() keys = pygame.key.get_pressed() if keys[K_ESCAPE]: exit()
這一段都是常規格式瞭,不解釋瞭,就是讓窗口能關掉。
然後把背景塗上一個顏色,不止一個人說我審美有問題瞭,所以我隨便選瞭個顏色,我都覺得有點醜
screen.fill((131, 139, 139))
我們先畫一個表盤
# 畫表盤 pygame.draw.circle(screen, white, (pos_x, pos_y), radius, 2)
在表盤上寫數字
# 寫表盤數字 for n in range(1, 13): # 一共12個數字,平均分到一個圓內 每兩個數字之間的角度為 360/12 x = math.cos(math.radians(angle)) * (radius - 10) - 5 y = math.sin(math.radians(angle)) * (radius - 10) - 7 print_text(font, pos_x + x, pos_y + y, str(n), white)
這裡說道說道幾個常用函數和概念,防止以後時間長瞭自己都忘
range(x,y)
作用是從x開始到y結束,但不包括y,所以range(1,13) 就是從1到12,如果x不填,則默認從0開始
math.randians(angle)、math.sin()、math.cos()
這裡比較繞瞭,要遍歷一個圓周,我們需要三個參數,圓心坐標(pos_x,pos_y),半徑(radius),和角度 (angle),然後通過三角函數裡的正弦和餘弦兩個函數乘以半徑,計算出每個點的坐標(x,y),而正弦和餘弦函數需要的參數是弧度,所以需要用 math.randians(angle)將角度轉化成弧度
問題來瞭,為啥正弦餘弦乘以半徑可以得出圓周上點的坐標呢?
給個圖自己看,很簡單
想象一下A點是圓心,B點是圓周上的點,AB是圓的半徑,那麼B點的x坐標就是 cosA乘以AB,y坐標就是sinA乘以AB
計算x,y坐標時候 -5 -7又是為啥呢?
因為pygame裡畫模型的時候,坐標是模型的左上角並不是模型的中心點,無論圖片還是文字還是其他什麼都是這樣,所以需要減掉幾個像素,使模型出現在正確的位置,不然會往右下偏,這點以後要經常用到
目前為止,表盤畫好瞭 ,是這個樣子的
開始畫表針
我們首先拿到當前的時間
# 獲取時間 time = datetime.today() hour = time.hour % 12 minute = time.minute second = time.second
畫秒針
# 畫秒針 second_angle = wrap_angle(second * (360 / 60) - 90) # 秒針是60進制,所以一秒的角度為 360/60 second_x = math.cos(math.radians(second_angle)) * (radius - 3) second_y = math.sin(math.radians(second_angle)) * (radius - 3) pygame.draw.line(screen, blue, (pos_x, pos_y), (pos_x + second_x, pos_y + second_y), 2)
問題又來瞭,為啥要 -90
因為畫圓的時候,0度是在3點鐘方向的,而實際情況下,我們希望0度在12點鐘方向,所以要減掉90度,達到需要
radius – 3 是為瞭讓秒針短一些,不至於戳到表盤上
解決瞭秒針,分針時針就簡單瞭
畫分針和時針
# 畫分針 minute_angle = wrap_angle(minute * (360 / 60) - 90) # 分針也是60進制,原理同秒針 minute_x = math.cos(math.radians(minute_angle)) * (radius - 40) minute_y = math.sin(math.radians(minute_angle)) * (radius - 40) pygame.draw.line(screen, green, (pos_x, pos_y), (pos_x + minute_x, pos_y + minute_y), 4) # 畫時針 # 時針算角度時增加瞭一部分,因為鐘表分針走的時候,時針也在走一個很小的角度 即30/60, # 加上這個角度,表才更加逼真,否則分針走的時候,時針一直保持指到整點,是錯誤的 hour_angle = wrap_angle(hour * (360 / 12) - 90) + minute * 30 / 60 hour_x = math.cos(math.radians(hour_angle)) * (radius - 80) hour_y = math.sin(math.radians(hour_angle)) * (radius - 80) pygame.draw.line(screen, red, (pos_x, pos_y), (pos_x + hour_x, pos_y + hour_y), 6)
這裡有點小技巧,我們看到計算hour_angle的時候,在後面加瞭 minute * 30 / 60,這裡實際上應該這麼寫minute / 60* (360/12) minute是當前的分鐘數,拿他除以60分鐘得到一個比例,然後12個小時,每兩個數字之間的角度是360/12即30度
加上這一塊,使分針每走一分鐘,時針也會相應的走一點,更逼真不是
然後寫上當前時間,比較表針位置是不是當前時間
# 寫時間 print_text(font, 10, 10, str(hour) + " : " + str(minute) + " : " + str(second), white)
最後在圓點位置畫一個點,蓋住三個表針交叉的位置,好看一點
# 畫表中心的圓點 之所以放在最後是想蓋住三個針的原點 pygame.draw.circle(screen, white, (pos_x, pos_y), 8, 0)
最最後,別忘瞭刷新
pygame.display.update()
完整代碼如下
import math, pygame from pygame.locals import * from datetime import datetime, date, time pygame.init() screen = pygame.display.set_mode((600, 600)) pygame.display.set_caption("Clock") pos_x = 300 pos_y = 300 radius = 250 white = 255, 255, 255 red = 240, 0, 0 green = 0, 240, 0 blue = 0, 0, 240 hour_angle = 0 minute_angle = 0 second_angle = 0 font = pygame.font.Font(None, 24) def wrap_angle(angle): return abs(angle % 360) def print_text(font, x, y, text, color): imgText = font.render(text, True, color) screen.blit(imgText, (x, y)) while True: for event in pygame.event.get(): if event.type == QUIT: exit() keys = pygame.key.get_pressed() if keys[K_ESCAPE]: exit() screen.fill((131, 139, 139)) # 畫表盤 pygame.draw.circle(screen, white, (pos_x, pos_y), radius, 2) # 寫表盤數字 for n in range(1, 13): # range(x,y)是從x開始到y結束 但不包括y,所以這裡是1-13 # 一共12個數字,平均分到一個圓內 每兩個數字之間的角度為 360/12 # 減90是因為默認開始點是3點鐘方向,而實際上是12點鐘方向,下面畫分針、時針、秒針時也是這個道理 angle = n * 360 / 12 - 90 # 這裡x,y減5減7,是因為寫文字的時候坐標不是文字的中心點而是文字的左上角 # ,所以文字會顯得往右下角偏,稍微的修正看起來更舒服 x = math.cos(math.radians(angle)) * (radius - 10) - 5 y = math.sin(math.radians(angle)) * (radius - 10) - 7 print_text(font, pos_x + x, pos_y + y, str(n), white) # 獲取時間 time = datetime.today() hour = time.hour % 12 minute = time.minute second = time.second # 畫秒針 second_angle = wrap_angle(second * (360 / 60) - 90) # 秒針是60進制,所以一秒的角度為 360/60 second_x = math.cos(math.radians(second_angle)) * (radius - 3) second_y = math.sin(math.radians(second_angle)) * (radius - 3) pygame.draw.line(screen, blue, (pos_x, pos_y), (pos_x + second_x, pos_y + second_y), 2) # 畫分針 minute_angle = wrap_angle(minute * (360 / 60) - 90) # 分針也是60進制,原理同秒針 minute_x = math.cos(math.radians(minute_angle)) * (radius - 40) minute_y = math.sin(math.radians(minute_angle)) * (radius - 40) pygame.draw.line(screen, green, (pos_x, pos_y), (pos_x + minute_x, pos_y + minute_y), 4) # 畫時針 # 時針算角度時增加瞭一部分,因為鐘表分針走的時候,時針也在走一個很小的角度 即30/60, # 加上這個角度,表才更加逼真,否則分針走的時候,時針一直保持指到整點,是錯誤的 hour_angle = wrap_angle(hour * (360 / 12) - 90) + minute * 30 / 60 hour_x = math.cos(math.radians(hour_angle)) * (radius - 80) hour_y = math.sin(math.radians(hour_angle)) * (radius - 80) pygame.draw.line(screen, red, (pos_x, pos_y), (pos_x + hour_x, pos_y + hour_y), 6) # 寫時間 print_text(font, 10, 10, str(hour) + " : " + str(minute) + " : " + str(second), white) # 畫表中心的圓點 之所以放在最後是想蓋住三個針的原點 pygame.draw.circle(screen, white, (pos_x, pos_y), 8, 0) pygame.display.update()
效果圖
還是很醜,但是基本功能都實現瞭。
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- Python使用Pygame實現時鐘效果
- 基於Python Pygame實現的畫餅圖遊戲
- python基於opencv 實現圖像時鐘
- pygame實現滑塊接小球遊戲
- pygame實現鍵盤和鼠標事件的處理