仿抖音网红文字时钟python的pygame实现及代码分析

仿抖音网红文字时钟python的pygame实现及代码分析

首页休闲益智rotate hex更新时间:2024-04-29

本文较长,适合收藏,慢慢研读分析。

===========

一、开篇说明:

1.推荐指数:★★★★★

2.衷心感谢:原作者:执念执战(王成程)

3.代码说明:在原作者的基础上进行代码的整合、删减、增加、润色、注释,分享出来,仅供学习。

4.仿抖音网红文字时钟,目前有app可以下载,网上也有html和css的免费代码下载,python的很少,这怎么能让python缺席呢?

html代码实现的,网上有免费代码下载

==========================

二、python的pygame实现的效果图:

1.图:

2,非常漂亮。

★3.提前准备:★

3.1 python3以上,推荐python3.8

3.2 微软编辑器vscode

3.3 下载自己喜欢的字体,本文中hwfs=华文仿宋

3.4 二进制文件‘HZK16’,需要自己去下载。

请大家搜索原作者的博客(执念执战),也是对原作者的尊重,我故意留下一个小bug。

=============

三,代码及分析:

1.第1步:

#---第1步---导出模块--- from math import * import pygame from pygame.locals import * import time import sys import binascii #任意中文字符时使用到此库 import math

2.第2步:

#---第2步---初始化定义--- #字符倍数比例函数,修改次数据可以实现整体的放大和缩小,建议此数值在0.8-1.3 之间,看起来比较合适 fontmultiple=1 #屏幕的宽和高,圆心坐标是屏幕大小的一半 SCREEN_X_MAX = int(1500*fontmultiple) SCREEN_Y_MAX = int(1500*fontmultiple) #游戏初始化 pygame.init() #本人喜欢加RESIZABLE,屏幕大小 screen = pygame.display.set_mode((SCREEN_X_MAX,SCREEN_Y_MAX),RESIZABLE) FOCAL_DISTANCE = 512 #透视模型

3.第3步:

#---第3步---颜色定义--- BLACK=(0,0,0) WHITE=(255,255,255) RED=(255,0,0) GREEN=(0,255,0) BLUE=(0,0,255) ForeColor = RED #前景色和背景色 BackColor = BLACK #中文字体,可以自己下载,hwfs=hwfs font = pygame.font.Font('hwfs.ttf', 36)

4.第4步:原作者是放入一个py文件(Transform3D.py),用模块一样导出,我将他整合进去,删除不需要的部分。

#---第4步---3d相关定义--- #定义画点函数---need def Gui_Point(x,y,color): pygame.draw.line(screen,color,(int(x),int(y)),(int(x 1),int(y)),2) #定义坐标结构体类---need class zuobiaostruct: def __init__(self): self.x=0 self.y=0 self.z=0 #矩阵相乘函数---need def MATRIX_multiply(MAT1,MAT2): newMAT=[[0.0 for i in range(4)] for n in range(4)] for a in range(4): for b in range(4): newMAT[a][b]=MAT1[a][0]*MAT2[0][b] MAT1[a][1]*MAT2[1][b] MAT1[a][2]*MAT2[2][b] MAT1[a][3]*MAT2[3][b] return newMAT #矢量与矩阵相乘函数---need def vector_matrix_MULTIPLY(Source,MAT): Result=zuobiaostruct() Result.x=Source.x*MAT[0][0] Source.y*MAT[1][0] Source.z*MAT[2][0] MAT[3][0] Result.y=Source.x*MAT[0][1] Source.y*MAT[1][1] Source.z*MAT[2][1] MAT[3][1] Result.z=Source.x*MAT[0][2] Source.y*MAT[1][2] Source.z*MAT[2][2] MAT[3][2] return Result #构造单位矩阵函数 def structure_3D(): MAT=[[0.0 for i in range(4)] for i in range(4)] MAT[0][0]=1.0 MAT[0][1]=0.0 MAT[0][2]=0.0 MAT[0][3]=0.0 #// 1 0 0 0 MAT[1][0]=0.0 MAT[1][1]=1.0 MAT[1][2]=0.0 MAT[1][3]=0.0 #// 0 1 0 0 MAT[2][0]=0.0 MAT[2][1]=0.0 MAT[2][2]=1.0 MAT[2][3]=0.0 #// 0 0 1 0 MAT[3][0]=0.0 MAT[3][1]=0.0 MAT[3][2]=0.0 MAT[3][3]=1.0 #// 0 0 0 1 return MAT #平移变换矩阵函数---need def Translate3D(MAT,tx, ty, tz): tMAT=[[0.0 for i in range(4)] for i in range(4)] tMAT[0][0]=1 tMAT[0][1]=0 tMAT[0][2]=0 tMAT[0][3]=0 #// 1 0 0 tx tMAT[1][0]=0 tMAT[1][1]=1 tMAT[1][2]=0 tMAT[1][3]=0 #// 0 1 0 ty tMAT[2][0]=0 tMAT[2][1]=0 tMAT[2][2]=1 tMAT[2][3]=0 #// 0 0 1 tz tMAT[3][0]=tx tMAT[3][1]=ty tMAT[3][2]=tz tMAT[3][3]=1; #// 0 0 0 1 return MATRIX_multiply(MAT,tMAT)#//相乘 #比例(scale)变换矩阵函数---need def Scale_3D( MAT, sx, sy, sz): tMAT=[[0.0 for i in range(4)] for i in range(4)] tMAT[0][0]=sx tMAT[0][1]=0 tMAT[0][2]=0 tMAT[0][3]=0 #// sx0 0 0 tMAT[1][0]=0 tMAT[1][1]=sy tMAT[1][2]=0 tMAT[1][3]=0 #// 0 sy0 0 tMAT[2][0]=0 tMAT[2][1]=0 tMAT[2][2]=sz tMAT[2][3]=0 #// 0 0 sz0 tMAT[3][0]=0 tMAT[3][1]=0 tMAT[3][2]=0 tMAT[3][3]=1 #// 0 0 0 1 return MATRIX_multiply(MAT,tMAT) # //相乘 #旋转变换矩阵函数---need def Rotate_3D( MAT, ax, ay, az): MAT1=[[0.0 for i in range(4)] for i in range(4)] MAT2=[[0.0 for i in range(4)] for i in range(4)] MATx=[[0.0 for i in range(4)] for i in range(4)] MATy=[[0.0 for i in range(4)] for i in range(4)] MATz=[[0.0 for i in range(4)] for i in range(4)] ax=(3.1415926*ax)/180.0 #//角度转换为弧度量 ay=(3.1415926*ay)/180.0 az=(3.1415926*az)/180.0 #*****************************绕x轴旋转******************************************** MATx[0][0]=1 MATx[0][1]=0 MATx[0][2]=0 MATx[0][3]=0 #//1 0 0 0 MATx[1][0]=0 MATx[1][1]=cos(ax) MATx[1][2]=-sin(ax) MATx[1][3]=0 #//0 cos(ax) -sin(ax) 0 MATx[2][0]=0 MATx[2][1]=sin(ax) MATx[2][2]=cos(ax) MATx[2][3]=0 #//0 sin(ax) cos(ax) 0 MATx[3][0]=0 MATx[3][1]=0 MATx[3][2]=0 MATx[3][3]=1 #//0 0 0 1 #*****************************绕y轴旋转******************************************** MATy[0][0]=cos(ay) MATy[0][1]=0 MATy[0][2]=sin(ay) MATy[0][3]=0 #//cos(ay) 0 sin(ay) 0 MATy[1][0]=0 MATy[1][1]=1 MATy[1][2]=0 MATy[1][3]=0 #// 0 1 0 0 MATy[2][0]=-sin(ay) MATy[2][1]=0 MATy[2][2]=cos(ay) MATy[2][3]=0 #// -sin(ay) 0 cos(ay) 0 MATy[3][0]=0 MATy[3][1]=0 MATy[3][2]=0 MATy[3][3]=1 #// 0 0 0 1 #*****************************绕z轴旋转******************************************** MATz[0][0]=cos(az) MATz[0][1]=-sin(az) MATz[0][2]=0 MATz[0][3]=0 #//cos(az) -sin(az) 0 0 MATz[1][0]=sin(az) MATz[1][1]=cos(az) MATz[1][2]=0 MATz[1][3]=0 #// sin(az) cos(az) 0 0 MATz[2][0]=0 MATz[2][1]=0 MATz[2][2]=1 MATz[2][3]=0 #// 0 0 1 0 MATz[3][0]=0 MATz[3][1]=0 MATz[3][2]=0 MATz[3][3]=1 #// 0 0 0 1 MAT1=MATRIX_multiply(MAT,MATx) MAT2=MATRIX_multiply(MAT1,MATy) return MATRIX_multiply(MAT2,MATz) #透视投影(Perspective projection)---need def PerProject( Space, XO, YO): Screen=zuobiaostruct() if (Space.z==0): Space.z=0.01 #//被除数不能为零 Screen.x=(int)(FOCAL_DISTANCE*Space.x /(Space.z FOCAL_DISTANCE) XO) Screen.y=(int)(FOCAL_DISTANCE*Space.y /(Space.z FOCAL_DISTANCE) YO) return Screen #显示3D的16x16字符---need def Show3D16x16Char(font,ax,ay,az,x,y,Z_Size,frontcolor,backcolor,model=1.5,fontmultiple=1.0): length = len(font) if length == 0:#字符数要大于一个 return if length == 1: #只支持一个字符的显示 text = font else: text = font[0] m=0 i=0 k=0 j=0 XO=0 YO=0 gMAT=[[0.0 for i in range(4)] for n in range(4)] Point0=zuobiaostruct() Point1=zuobiaostruct() PointDis=zuobiaostruct() gMAT=structure_3D() #//构建单位矩阵 gMAT=Translate3D(gMAT,-8,-8,-8); #//平移变换矩阵 gMAT=Scale_3D(gMAT,fontmultiple,fontmultiple,fontmultiple); #//比例变换矩阵 gMAT=Rotate_3D(gMAT,ax,ay,az); #//旋转变换矩阵 for m in range(length): #理论上就是将单个的字符延长为多个字符,最重要的就是坐标的确定和计算 text=font[m] gb2312 = text.encode('gb2312') hex_str = binascii.b2a_hex(gb2312) result = str(hex_str,encoding = 'utf-8' ) #换算出汉字对应的字符地址 if eval('0x' result[:2]) <128: return else: area = eval('0x' result[:2]) - 0xA0 index = eval('0x' result[2:]) - 0xA0 #换算为16进制地址 offset = (94 * (area - 1) (index - 1))*32 #得出具体地址 font_rect = None #注意这个文件HZK16,二进制文件需要单独下载 with open("/home/xgj/Desktop/汉字时钟/pyxgj/HZK16","rb") as f: #16x16字符集的地址,从中读取出一个字符的点阵数据 f.seek(offset) font_rect = f.read(32)#得到32个点阵数据 f.close() for i in range(16): for k in range(8): temp = 0x01 << k for j in range(2): data=font_rect[i*2 j] #取出数据 if data & temp == temp: Point0.x=16-(k (1-j)*8) m*16 m*2 #第m个字符的当前点的坐标 #每个字符16个像素,第m个字符共m*16个像素,每两个字符间的间距设为2,则m*16 m*2,前面的时实现当前点阵坐标的计算 Point0.y=i #(i*8) k Point0.z=Z_Size #//此参数能够改变字符距离旋转轴中心的距离 Point1=vector_matrix_MULTIPLY(Point0,gMAT)#//矢量与矩阵相乘 PointDis=PerProject(Point1,XO,YO) #//映射投影 Gui_Point(PointDis.x x,PointDis.y y,frontcolor) else: if model ==1: #模式为1 时才会绘制底色 Point0.x=16-(k (1-j)*8) m*16 m*2 Point0.y=i #(i*8) k Point0.z=Z_Size #//此参数能够改变字符距离旋转轴中心的距离 Point1=vector_matrix_MULTIPLY(Point0,gMAT)#//矢量与矩阵相乘 PointDis=PerProject(Point1,XO,YO) #//映射投影 Gui_Point(PointDis.x x,PointDis.y y,backcolor)

5.第5步:我增加了秒的相关定义和设置,在后续中补充秒的部分代码。

#---第5步---中文标签定义------------- Week_zw=("一","二","三","四","五","六","日") #星期的中文 Day_zw=("零","一","二","三","四","五","六","七","八","九","十") #可用于所有需要0-10的中文的地方 Mouth_day=[31,28,31,30,31,30,31,31,30,31,30,31] #月份时长表 #秒 Second_add=['零','一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二', '十三', '十四', '十五', '十六', '十七', '十八', '十九', '二十','二十一', '二十二', '二十三', '二十四', '二十五', '二十六', '二十七', '二十八', '二十九', '三十','三十一', '三十二', '三十三', '三十四', '三十五', '三十六', '三十七', '三十八', '三十九', '四十','四十一', '四十二', '四十三', '四十四', '四十五', '四十六', '四十七', '四十八', '四十九', '五十', '五十一', '五十二', '五十三', '五十四', '五十五', '五十六', '五十七', '五十八', '五十九', ]

6.第6步:这里有增加秒的代码

#---第6步---相关显示函数定义--- #显示年 def Show_Year(x0,y0,r,angel): timenow=time.localtime(time.time()) #获取时间 yearstr=Day_zw[(int)(timenow[0]/1000)] Day_zw[int((timenow[0]00)/100)] Day_zw[int((timenow[0]0)/10)] Day_zw[int((timenow[0]))] "年" Show3D16x16Char(yearstr,0,0,angel-90,x0,y0,1,WHITE,BackColor,0,fontmultiple) #显示周(星期) def Show_Week(x0,y0,r,agl): timenow=time.localtime(time.time()) #获取时间 for i in range(7): angel=360/7 if i < timenow[6]: angel=agl-angel*(timenow[6]-i) ForeColor=RED elif i >timenow[6]: angel=agl angel*(i-timenow[6]) ForeColor=RED else : angel=agl #当前周设为90度,即在水平方向上 ForeColor=WHITE x1=x0 r * math.sin(angel * 3.14/180) #由角度计算出当前应在的坐标点 y1=y0 r * math.cos(angel * 3.14/180) Show3D16x16Char("周" Week_zw[i],0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple)#输出旋转后的字符串 #显示月份 def Show_Month(x0,y0,r,agl): timenow=time.localtime(time.time())#获取时间 for i in range(1,13): #一年12个月 angel=360/12 if i < timenow[1]: angel=agl-angel*(timenow[1]-i) #其他月份相应得到角度推算 ForeColor=GREEN elif i >timenow[1]: angel=agl angel*(i-timenow[1]) ForeColor=GREEN else : angel=agl #当前月份设为90度,即在水平方向上 ForeColor=WHITE x1=x0 r * math.sin(angel * 3.14/180) #由角度计算出当前应在的坐标点 y1=y0 r * math.cos(angel * 3.14/180) if i>10: monthstr=Day_zw[10] Day_zw[i] "月" #得出要显示的字符串 else: monthstr = Day_zw[i] "月" Show3D16x16Char(monthstr,0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple)#显示字符串 #显示日期 def Show_Day(x0,y0,r,agl): timenow=time.localtime(time.time()) #获取时间 if (timenow[0]%4==0 and timenow[0]0 !=0) or (timenow[0]@0 == 0): Mouth_day[1]=29 #闰年,补全二月的时长表 else: Mouth_day[1]=28 #Mouth_day 为月份的时长表 for i in range(1,Mouth_day[timenow[1]-1] 1): angel=360/Mouth_day[timenow[1]-1] if i < timenow[2]: angel=agl-angel*(timenow[2]-i)#其他日期相应得到角度推算 ForeColor=RED elif i >timenow[2]: angel=agl angel*(i-timenow[2]) ForeColor=RED else : angel=agl #当前日期设为90度,即在水平方向上 ForeColor=WHITE x1=x0 r * math.sin(angel * 3.14/180)#由角度计算出当前应在的坐标点 y1=y0 r * math.cos(angel * 3.14/180) if i>20: if i !=0: daystr= Day_zw[(int)(i/10) ] Day_zw[10] Day_zw[i] "日"#得出要显示的字符串 else: daystr= Day_zw[(int)(i/10) ] Day_zw[10] "日" elif i>10: daystr= Day_zw[10] Day_zw[i] "日" else: daystr=Day_zw[i] "日" Show3D16x16Char(daystr,0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple)#显示字符串 #显示时=小时=h def Show_Hour(x0,y0,r,agl): timenow=time.localtime(time.time())#获取时间 for i in range(0,24): angel=360/24 if i < timenow[3]: angel=agl-angel*(timenow[3]-i)#其他时间相应得到角度推算 ForeColor=GREEN elif i >timenow[3]: angel=agl angel*(i-timenow[3]) ForeColor=GREEN else : angel=agl #当前时间设为90度,即在水平方向上 ForeColor=WHITE x1=x0 r * math.sin(angel * 3.14/180) y1=y0 r * math.cos(angel * 3.14/180) if i>20: if i !=0: daystr= Day_zw[(int)(i/10) ] Day_zw[10] Day_zw[i] "时" #得到要显示的字符串 else: daystr= Day_zw[(int)(i/10) ] Day_zw[10] "时" elif i>10: daystr= Day_zw[10] Day_zw[i] "时" else: daystr=Day_zw[i] "时" Show3D16x16Char(daystr,0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple) #显示角度计算后的字符串 # 显示分=分钟=m def Show_Min(x0,y0,r,agl): timenow=time.localtime(time.time()) for i in range(0,60): angel = 360/60 if i < timenow[4]: #将秒数也代入角度计算中就可以得到更精确的角度偏移,而且每秒钟都会移动,好看 angel=agl-angel*(timenow[4]-i)-(360/60/60 * timenow[5] ) ForeColor=RED elif i > timenow[4]: angel = agl angel * (i-timenow[4]) - (360/60/60 * timenow[5] ) ForeColor = RED else : angel = agl - (360/60/60 * timenow[5] ) #当前日期设为90度-秒钟的角度,实现动态显示 ForeColor = WHITE x1 = x0 r * math.sin(angel * 3.14/180) #由角度计算出当前应在的坐标点 y1 = y0 r * math.cos(angel * 3.14/180) if i>=20: if i !=0: daystr = Day_zw[(int)(i/10) ] Day_zw[10] Day_zw[i] "分" #得到要显示的字符串 else: daystr = Day_zw[(int)(i/10) ] Day_zw[10] "分" elif i>10: daystr = Day_zw[10] Day_zw[i] "分" else: daystr = Day_zw[i] "分" Show3D16x16Char(daystr,0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple)#显示角度计算后的字符串 # 显示秒=秒针=s def Show_Sec(x0,y0,r,agl): #获取时间列表 timenow=time.localtime(time.time()) #print(timenow) #time.struct_time(tm_year=2020, tm_mon=3, tm_mday=28, tm_hour=9, tm_min=24, tm_sec=18) for i in range(0,60): angel = 360/60 if i < timenow[5]: #有一个bug,如何实现跳一秒走一格,整体转一圈优雅些,暂时不会。 angel=agl-angel*(timenow[5]-i)-(360/60 * timenow[5]) ForeColor=GREEN elif i > timenow[5]: angel = agl angel * (i-timenow[5])-(360/60 * timenow[5]) ForeColor = GREEN else : #当前日期设为90度-秒钟的角度,实现动态显示 angel = agl-(360/60 * timenow[5] ) #归零=o时显示红色 if angel ==90: ForeColor = RED #当前时间为白色 else: ForeColor = WHITE #根据秒表动态转圈 x1 = x0 r * math.sin(angel * 3.14/180) #由角度计算出当前应在的坐标点 y1 = y0 r * math.cos(angel * 3.14/180) if i>=20: if i !=0: #加入秒的字符串 daystr = Second_add[(int)(i/10) ] Second_add[10] Second_add[i] "秒" #得到要显示的字符串 else: daystr = Second_add[(int)(i/10) ] Second_add[10] "秒" elif i>10: daystr = Second_add[10] Second_add[i] "秒" else: daystr = Second_add[i] "秒" #显示秒的字符串一圈 Show3D16x16Char(daystr,0,0,angel-90,(int)(x1),(int)(y1),1,ForeColor,BackColor,0,fontmultiple)#显示角度计算后的字符串

7.第7步:我增加了打印当前时间的打印文字函数

#---第7步---定义打印屏幕文字函数--- def print_text(font, x, y, text, color=WHITE): imgText = font.render(text, True, WHITE) screen.blit(imgText, (int(float(x)),int(float(y))))

8.第8步:

#---第8步---游戏循环--- i=0 while True: #获取今天的时间 timenow=time.localtime(time.time()) #定义年月日 years=timenow[0] months=timenow[1] days=timenow[2] #定义时分秒 #hours = today.hour % 12 #显示12h制 hours = timenow[3] % 24 #显示24h制 minutes = timenow[4] seconds = timenow[5] #显示当前时间,x=400,y=550,为坐标 print_text(font, 500, 150, '当前时间:' str(years) '年' str(months) '月' str(days) '日' str(hours) '时' ":" str(minutes) '分' ":" str(seconds) '秒') #退出设置 for event in pygame.event.get(): if event.type in (QUIT,KEYDOWN): pygame.quit() sys.exit() i =1 #当i<90启动时整体圆盘都要转动,当≥90时停止 if i > 90: i=90 #圆盘设置 #坐标点,水平向右坐标定固定显示白色当前时间; Show_Year(SCREEN_X_MAX/2-40*fontmultiple,SCREEN_Y_MAX/2,32,90) #显示年 Show_Week(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,65*fontmultiple,180-i) #显示周 Show_Month(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,110*fontmultiple,i) #显示月份 Show_Day(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,170*fontmultiple,180-i) #显示日期 Show_Hour(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,245*fontmultiple,i) #显示时 Show_Min(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,325*fontmultiple,180-i) #显示分 Show_Sec(SCREEN_X_MAX/2,SCREEN_Y_MAX/2,425*fontmultiple,180-i) #显示秒 #线圈的设置 pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(55*fontmultiple),1) #显示几个圆 pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(100*fontmultiple),1) pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(160*fontmultiple),1) pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(235*fontmultiple),1) pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(315*fontmultiple),1) pygame.draw.circle(screen,ForeColor,((int)(SCREEN_X_MAX/2),(int)(SCREEN_Y_MAX/2)),int(415*fontmultiple),1) pygame.display.update() screen.fill(0) #屏幕清零

四、结束语:

据说python无所不能,可惜我也是新手小白,我也是站在巨人和大神的肩膀上的,感谢大神执念执战(王成程)。最重要的是python为什么这么火?第1是代码简洁;第2是代码及库很多,都是开源的、免费的,都是大神们之间互相免费提供的,在此多谢他们。

喜欢python的人,不管多大年纪、不管男女,看我的python,你学起来简单有趣,我都是亲测过的。

查看全文
大家还看了
也许喜欢
更多游戏

Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved