用pygame做一個(gè)時(shí)鐘,供大家參考,具體內(nèi)容如下
剛剛學(xué)習(xí)pygame,由于基礎(chǔ)實(shí)在太差,每個(gè)例子都要反復(fù)寫逐句研究才能基本弄懂,這次做一個(gè)簡單的有時(shí)針、分針、秒針,能正確行走的表。。。例子不難,但是還是能掌握一些基本的知識點(diǎn),比如xy坐標(biāo)的計(jì)算,畫圓,文字處理等。小白如我可以借鑒下,我認(rèn)為學(xué)習(xí)還是以邏輯為主,所以我盡量還原初學(xué)時(shí)候的邏輯步驟,不啰嗦了,開整!
前期準(zhǔn)備
這次我們用到的主要是pygame,math,datetime幾個(gè)庫,datetime.today()可以獲取當(dāng)前時(shí)間,math.sin()和math.cos()用于計(jì)算表針的坐標(biāo)。用到的方法主要是pygame.draw.circle()畫圓,和pygame.draw.line()畫線
開始下手
先把pygame初始化,再弄個(gè)窗口出來,準(zhǔn)備工作做好
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")
然后畫個(gè)圓當(dāng)表盤,這樣就需要確定位置和半徑
pos_x = 300
pos_y = 300
radius = 250
考慮到區(qū)分三個(gè)表針的顏色,先設(shè)置好四種顏色
white = 255, 255, 255
red = 240, 0, 0
green = 0, 240, 0
blue = 0, 0, 240
計(jì)算表針的坐標(biāo),需要用到角度,所以先把角度設(shè)好
hour_angle = 0
minute_angle = 0
second_angle = 0
寫數(shù)字需要用到文字處理,把文字樣式設(shè)置一下
font = pygame.font.Font(None, 24)
最后還要寫兩個(gè)方法一個(gè)是輸出文字的,一個(gè)是規(guī)范角度的。這倆以后都經(jīng)常用
# abs()是取絕對值,%運(yùn)算符號很有意思,效果是360取余數(shù),保證了角度在360以內(nèi)
def wrap_angle(angle):
return abs(angle % 360)
# 把打印文字的步驟封裝在一個(gè)方法里,每次方便調(diào)用,簡化代碼
def print_text(font, x, y, text, color):
imgText = font.render(text, True, color)
screen.blit(imgText, (x, y))
好了,準(zhǔn)備工作做完了,我們來寫循環(huán)
while True:
for event in pygame.event.get():
if event.type == QUIT:
exit()
keys = pygame.key.get_pressed()
if keys[K_ESCAPE]:
exit()
這一段都是常規(guī)格式了,不解釋了,就是讓窗口能關(guān)掉。
然后把背景涂上一個(gè)顏色,不止一個(gè)人說我審美有問題了,所以我隨便選了個(gè)顏色,我都覺得有點(diǎn)丑
screen.fill((131, 139, 139))
我們先畫一個(gè)表盤
# 畫表盤
pygame.draw.circle(screen, white, (pos_x, pos_y), radius, 2)
在表盤上寫數(shù)字
# 寫表盤數(shù)字
for n in range(1, 13):
# 一共12個(gè)數(shù)字,平均分到一個(gè)圓內(nèi) 每兩個(gè)數(shù)字之間的角度為 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)
這里說道說道幾個(gè)常用函數(shù)和概念,防止以后時(shí)間長了自己都忘
range(x,y)
作用是從x開始到y(tǒng)結(jié)束,但不包括y,所以range(1,13) 就是從1到12,如果x不填,則默認(rèn)從0開始
math.randians(angle)、math.sin()、math.cos()
這里比較繞了,要遍歷一個(gè)圓周,我們需要三個(gè)參數(shù),圓心坐標(biāo)(pos_x,pos_y),半徑(radius),和角度 (angle),然后通過三角函數(shù)里的正弦和余弦兩個(gè)函數(shù)乘以半徑,計(jì)算出每個(gè)點(diǎn)的坐標(biāo)(x,y),而正弦和余弦函數(shù)需要的參數(shù)是弧度,所以需要用 math.randians(angle)將角度轉(zhuǎn)化成弧度
問題來了,為啥正弦余弦乘以半徑可以得出圓周上點(diǎn)的坐標(biāo)呢?
給個(gè)圖自己看,很簡單
想象一下A點(diǎn)是圓心,B點(diǎn)是圓周上的點(diǎn),AB是圓的半徑,那么B點(diǎn)的x坐標(biāo)就是 cosA乘以AB,y坐標(biāo)就是sinA乘以AB
計(jì)算x,y坐標(biāo)時(shí)候 -5 -7又是為啥呢?
因?yàn)閜ygame里畫模型的時(shí)候,坐標(biāo)是模型的左上角并不是模型的中心點(diǎn),無論圖片還是文字還是其他什么都是這樣,所以需要減掉幾個(gè)像素,使模型出現(xiàn)在正確的位置,不然會(huì)往右下偏,這點(diǎn)以后要經(jīng)常用到
目前為止,表盤畫好了 ,是這個(gè)樣子的
開始畫表針
我們首先拿到當(dāng)前的時(shí)間
# 獲取時(shí)間
time = datetime.today()
hour = time.hour % 12
minute = time.minute
second = time.second
畫秒針
# 畫秒針
second_angle = wrap_angle(second * (360 / 60) - 90) # 秒針是60進(jìn)制,所以一秒的角度為 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
因?yàn)楫媹A的時(shí)候,0度是在3點(diǎn)鐘方向的,而實(shí)際情況下,我們希望0度在12點(diǎn)鐘方向,所以要減掉90度,達(dá)到需要
radius - 3 是為了讓秒針短一些,不至于戳到表盤上
解決了秒針,分針時(shí)針就簡單了
畫分針和時(shí)針
# 畫分針
minute_angle = wrap_angle(minute * (360 / 60) - 90) # 分針也是60進(jìn)制,原理同秒針
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)
# 畫時(shí)針
# 時(shí)針?biāo)憬嵌葧r(shí)增加了一部分,因?yàn)殓姳矸轴樧叩臅r(shí)候,時(shí)針也在走一個(gè)很小的角度 即30/60,
# 加上這個(gè)角度,表才更加逼真,否則分針走的時(shí)候,時(shí)針一直保持指到整點(diǎn),是錯(cuò)誤的
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)
這里有點(diǎn)小技巧,我們看到計(jì)算hour_angle的時(shí)候,在后面加了 minute * 30 / 60,這里實(shí)際上應(yīng)該這么寫minute / 60* (360/12) minute是當(dāng)前的分鐘數(shù),拿他除以60分鐘得到一個(gè)比例,然后12個(gè)小時(shí),每兩個(gè)數(shù)字之間的角度是360/12即30度
加上這一塊,使分針每走一分鐘,時(shí)針也會(huì)相應(yīng)的走一點(diǎn),更逼真不是
然后寫上當(dāng)前時(shí)間,比較表針位置是不是當(dāng)前時(shí)間
# 寫時(shí)間
print_text(font, 10, 10, str(hour) + " : " + str(minute) + " : " + str(second), white)
最后在圓點(diǎn)位置畫一個(gè)點(diǎn),蓋住三個(gè)表針交叉的位置,好看一點(diǎn)
# 畫表中心的圓點(diǎn) 之所以放在最后是想蓋住三個(gè)針的原點(diǎn)
pygame.draw.circle(screen, white, (pos_x, pos_y), 8, 0)
最最后,別忘了刷新
完整代碼如下
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)
# 寫表盤數(shù)字
for n in range(1, 13): # range(x,y)是從x開始到y(tǒng)結(jié)束 但不包括y,所以這里是1-13
# 一共12個(gè)數(shù)字,平均分到一個(gè)圓內(nèi) 每兩個(gè)數(shù)字之間的角度為 360/12
# 減90是因?yàn)槟J(rèn)開始點(diǎn)是3點(diǎn)鐘方向,而實(shí)際上是12點(diǎn)鐘方向,下面畫分針、時(shí)針、秒針時(shí)也是這個(gè)道理
angle = n * 360 / 12 - 90
# 這里x,y減5減7,是因?yàn)閷懳淖值臅r(shí)候坐標(biāo)不是文字的中心點(diǎn)而是文字的左上角
# ,所以文字會(huì)顯得往右下角偏,稍微的修正看起來更舒服
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)
# 獲取時(shí)間
time = datetime.today()
hour = time.hour % 12
minute = time.minute
second = time.second
# 畫秒針
second_angle = wrap_angle(second * (360 / 60) - 90) # 秒針是60進(jìn)制,所以一秒的角度為 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進(jìn)制,原理同秒針
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)
# 畫時(shí)針
# 時(shí)針?biāo)憬嵌葧r(shí)增加了一部分,因?yàn)殓姳矸轴樧叩臅r(shí)候,時(shí)針也在走一個(gè)很小的角度 即30/60,
# 加上這個(gè)角度,表才更加逼真,否則分針走的時(shí)候,時(shí)針一直保持指到整點(diǎn),是錯(cuò)誤的
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)
# 寫時(shí)間
print_text(font, 10, 10, str(hour) + " : " + str(minute) + " : " + str(second), white)
# 畫表中心的圓點(diǎn) 之所以放在最后是想蓋住三個(gè)針的原點(diǎn)
pygame.draw.circle(screen, white, (pos_x, pos_y), 8, 0)
pygame.display.update()
效果圖
還是很丑,但是基本功能都實(shí)現(xiàn)了。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。