Files
2026-07-28 03:21:34 +08:00

220 lines
8.2 KiB
Python

import tkinter as tk
import math
import time
import random
from tkinter import Canvas
class SwingingClock:
def __init__(self, root):
self.root = root
self.root.title("Swinging Clock")
# Set to fullscreen
self.root.attributes('-fullscreen', True)
self.root.configure(bg="black")
# Get screen dimensions
self.screen_width = self.root.winfo_screenwidth()
self.screen_height = self.root.winfo_screenheight()
# Main canvas
self.canvas = Canvas(root, width=self.screen_width, height=self.screen_height,
bg="black", highlightthickness=0)
self.canvas.pack(fill=tk.BOTH, expand=True)
# Clock parameters
self.clock_radius = min(self.screen_width, self.screen_height) * 0.3
self.center_x = self.screen_width // 2
self.center_y = self.screen_height // 2
self.clock_color = "white"
self.bg_color = "black"
# Swing parameters
self.swing_angle = 0
self.swing_direction = 1
self.swing_speed = 2
self.max_swing = 30 # Max swing angle
# Wave parameters
self.wave_radius = self.clock_radius + 20
self.wave_width = 100 # Increased wave width
self.wave_spacing = 30 # Wave spacing
self.wave_alpha = 0
self.wave_growing = True
self.waves = [] # To track multiple waves
# Time and animation parameters
self.start_time = time.time()
self.current_speed = -30 * 60 # Start at 30 minutes per second counter-clockwise
self.last_update_time = time.time()
self.total_elapsed = 0 # Track total elapsed time in clock's perspective
# Hand angles for smooth animation
self.smooth_hour_angle = 0
self.smooth_minute_angle = 0
# Draw initial clock
self.draw_clock()
# Start animation loop
self.animate()
# Bind escape key to exit fullscreen
self.root.bind('<Escape>', lambda e: self.root.attributes('-fullscreen', False))
self.root.bind('<F11>', lambda e: self.root.attributes('-fullscreen', True))
def draw_clock(self):
"""Draw the clock"""
self.canvas.delete("all")
# Draw wave effects
for wave in self.waves:
radius, alpha = wave
if alpha > 0:
wave_color = self.get_wave_color(alpha)
self.canvas.create_oval(
self.center_x - radius,
self.center_y - radius,
self.center_x + radius,
self.center_y + radius,
outline=wave_color,
width=self.wave_width
)
# Draw clock outer circle
self.canvas.create_oval(
self.center_x - self.clock_radius,
self.center_y - self.clock_radius,
self.center_x + self.clock_radius,
self.center_y + self.clock_radius,
outline=self.clock_color,
width=3
)
# Draw clock center point
self.canvas.create_oval(
self.center_x - 5,
self.center_y - 5,
self.center_x + 5,
self.center_y + 5,
fill=self.clock_color,
outline=self.clock_color
)
# Draw clock numbers (counter-clockwise)
for i in range(1, 13):
angle = math.radians(-(i * 30 - 90)) # Negative for counter-clockwise
x = self.center_x + (self.clock_radius - 30) * math.cos(angle)
y = self.center_y + (self.clock_radius - 30) * math.sin(angle)
self.canvas.create_text(x, y, text=str(i), fill=self.clock_color,
font=("Arial", 12, "bold"))
# Draw clock hands
self.draw_clock_hands()
def draw_clock_hands(self):
"""Draw clock hands with smooth animation (always counter-clockwise)"""
current_time = time.time()
elapsed = current_time - self.last_update_time
self.last_update_time = current_time
# Update total elapsed time (always negative)
self.total_elapsed += elapsed * self.current_speed
# Calculate accelerated time components (always negative)
accelerated_hours = self.total_elapsed / 3600
accelerated_minutes = self.total_elapsed / 60
# Calculate angles (negative for counter-clockwise)
hour_angle = -((accelerated_hours % 12) * 30) # 30 degrees per hour
minute_angle = -((accelerated_minutes % 60) * 6) # 6 degrees per minute
# Smooth transitions for hands
self.smooth_hour_angle = self.smooth_hour_angle * 0.8 + hour_angle * 0.2
self.smooth_minute_angle = self.smooth_minute_angle * 0.7 + minute_angle * 0.3
# Add swing effect
hour_angle_swing = math.radians(self.smooth_hour_angle - 90 + self.swing_angle)
minute_angle_swing = math.radians(self.smooth_minute_angle - 90 + self.swing_angle)
# Hour hand
hour_x = self.center_x + (self.clock_radius * 0.5) * math.cos(hour_angle_swing)
hour_y = self.center_y + (self.clock_radius * 0.5) * math.sin(hour_angle_swing)
self.canvas.create_line(
self.center_x, self.center_y, hour_x, hour_y,
fill=self.clock_color, width=4
)
# Minute hand
minute_x = self.center_x + (self.clock_radius * 0.7) * math.cos(minute_angle_swing)
minute_y = self.center_y + (self.clock_radius * 0.7) * math.sin(minute_angle_swing)
self.canvas.create_line(
self.center_x, self.center_y, minute_x, minute_y,
fill=self.clock_color, width=2
)
def get_wave_color(self, alpha):
"""Get wave color based on alpha"""
alpha_hex = hex(int(alpha * 255))[2:].zfill(2)
return f"#{alpha_hex}{alpha_hex}{alpha_hex}"
def animate(self):
"""Animation loop"""
# Update swing angle
self.swing_angle += self.swing_speed * self.swing_direction
# Check if direction needs to reverse
if abs(self.swing_angle) >= self.max_swing:
self.swing_direction *= -1
self.shake_screen()
self.invert_colors()
self.start_wave()
# Update wave effects
new_waves = []
for wave in self.waves:
radius, alpha = wave
if alpha > 0:
radius += 15 # Wave expansion speed
alpha -= 0.02 # Fade speed
if alpha > 0:
new_waves.append((radius, alpha))
# Add new wave if needed (based on spacing)
if not self.waves or (self.waves[-1][0] >= self.wave_radius + self.wave_spacing):
self.waves.append((self.wave_radius, 1.0))
self.waves = new_waves
# Redraw clock
self.draw_clock()
# Continue animation
self.root.after(16, self.animate) # ~60fps
def shake_screen(self):
"""Screen shake effect"""
original_x = self.root.winfo_x()
original_y = self.root.winfo_y()
for i in range(5):
offset_x = random.randint(-10, 10)
offset_y = random.randint(-5, 5)
self.root.geometry(f"+{original_x + offset_x}+{original_y + offset_y}")
self.root.update()
time.sleep(0.02)
self.root.geometry(f"+{original_x}+{original_y}")
def invert_colors(self):
"""Invert colors without affecting clock direction"""
self.clock_color, self.bg_color = self.bg_color, self.clock_color
self.canvas.config(bg=self.bg_color)
def start_wave(self):
"""Start a new wave effect"""
self.waves.append((self.wave_radius, 1.0))
if __name__ == "__main__":
root = tk.Tk()
app = SwingingClock(root)
root.mainloop()