import tkinter as tk
from tkinter import messagebox
import random
import time
import threading
import winsound  # Windows系统音效，其他系统可能需要替换

class MusicGame:
    def __init__(self, root):
        self.root = root
        self.root.title("音乐节奏游戏")
        self.root.geometry("800x600")
        self.root.configure(bg='#2c3e50')
        
        # 游戏状态变量
        self.score = 0
        self.combo = 0
        self.notes = []
        self.game_running = False
        self.beat_interval = 1.0  # 初始节拍间隔（秒）
        self.beat_timer = None
        self.note_speed = 3  # 音符下落速度
        
        # 颜色定义
        self.colors = {
            'bg': '#2c3e50',
            'target': '#e74c3c',
            'note': '#3498db',
            'success': '#2ecc71',
            'miss': '#e74c3c',
            'perfect': '#f1c40f'
        }
        
        self.setup_ui()
        self.setup_keyboard_bindings()
        
    def setup_ui(self):
        """设置用户界面"""
        # 标题
        title_frame = tk.Frame(self.root, bg='#2c3e50')
        title_frame.pack(pady=10)
        
        title_label = tk.Label(title_frame, text="🎵 音乐节奏游戏 🎵", 
                               font=('Arial', 24, 'bold'), 
                               fg='white', bg='#2c3e50')
        title_label.pack()
        
        # 得分显示
        score_frame = tk.Frame(self.root, bg='#2c3e50')
        score_frame.pack(pady=10)
        
        self.score_label = tk.Label(score_frame, text="得分: 0", 
                                   font=('Arial', 18), 
                                   fg='white', bg='#2c3e50')
        self.score_label.pack(side=tk.LEFT, padx=20)
        
        self.combo_label = tk.Label(score_frame, text="连击: 0", 
                                   font=('Arial', 18), 
                                   fg='white', bg='#2c3e50')
        self.combo_label.pack(side=tk.LEFT, padx=20)
        
        # 游戏画布（音符下落区域）
        self.canvas = tk.Canvas(self.root, width=600, height=400, 
                               bg='#34495e', highlightthickness=2, 
                               highlightbackground='#ecf0f1')
        self.canvas.pack(pady=20)
        
        # 目标区域（打击区域）
        self.target_y = 350  # 目标Y坐标
        self.target_line = self.canvas.create_line(0, self.target_y, 
                                                   600, self.target_y, 
                                                   width=3, fill='#e74c3c')
        
        # 目标区域标记
        self.target_area = self.canvas.create_rectangle(0, self.target_y - 20,
                                                        600, self.target_y + 20,
                                                        outline='#e74c3c', 
                                                        width=2, fill='',
                                                        stipple='gray50')
        
        # 控制面板
        control_frame = tk.Frame(self.root, bg='#2c3e50')
        control_frame.pack(pady=20)
        
        self.start_button = tk.Button(control_frame, text="开始游戏", 
                                     command=self.start_game, 
                                     font=('Arial', 14), 
                                     bg='#27ae60', fg='white',
                                     padx=20, pady=10)
        self.start_button.pack(side=tk.LEFT, padx=10)
        
        self.stop_button = tk.Button(control_frame, text="停止游戏", 
                                    command=self.stop_game, 
                                    font=('Arial', 14), 
                                    bg='#e74c3c', fg='white',
                                    padx=20, pady=10, state='disabled')
        self.stop_button.pack(side=tk.LEFT, padx=10)
        
        # 难度选择
        difficulty_frame = tk.Frame(self.root, bg='#2c3e50')
        difficulty_frame.pack(pady=10)
        
        tk.Label(difficulty_frame, text="难度:", 
                font=('Arial', 12), fg='white', bg='#2c3e50').pack(side=tk.LEFT)
        
        self.difficulty_var = tk.StringVar(value="中等")
        difficulties = ["简单", "中等", "困难"]
        for diff in difficulties:
            rb = tk.Radiobutton(difficulty_frame, text=diff, 
                               variable=self.difficulty_var, value=diff,
                               command=self.change_difficulty,
                               bg='#2c3e50', fg='white', selectcolor='#2c3e50')
            rb.pack(side=tk.LEFT, padx=10)
        
        # 提示标签
        self.hint_label = tk.Label(self.root, 
                                  text="按空格键或点击音符进行打击\n红色区域为打击区域", 
                                  font=('Arial', 10), 
                                  fg='#bdc3c7', bg='#2c3e50')
        self.hint_label.pack(pady=5)
        
        # 效果显示
        self.effect_label = tk.Label(self.root, text="", 
                                    font=('Arial', 16, 'bold'), 
                                    bg='#2c3e50')
        self.effect_label.pack(pady=10)
        
    def setup_keyboard_bindings(self):
        """设置键盘绑定"""
        self.root.bind('<space>', self.key_hit)
        self.root.bind('<Return>', self.key_hit)
        self.root.bind('<KeyPress>', self.on_key_press)
        
    def on_key_press(self, event):
        """键盘事件处理"""
        if event.keysym == 'space' or event.keysym == 'Return':
            self.key_hit(event)
            
    def key_hit(self, event):
        """打击音符"""
        if not self.game_running:
            return
            
        # 检查是否有音符在打击区域内
        hit_note = None
        for note in self.notes:
            y1, y2 = self.canvas.coords(note['id'])[1], self.canvas.coords(note['id'])[3]
            note_center_y = (y1 + y2) / 2
            
            # 检查音符是否在打击区域内
            if abs(note_center_y - self.target_y) <= 25:
                hit_note = note
                break
        
        if hit_note:
            # 计算打击准确度
            note_center_y = (self.canvas.coords(hit_note['id'])[1] + 
                           self.canvas.coords(hit_note['id'])[3]) / 2
            distance = abs(note_center_y - self.target_y)
            
            # 根据准确度给分
            if distance <= 10:
                points = 100
                effect = "完美!"
                color = self.colors['perfect']
                self.combo += 1
                self.play_sound(1000)  # 高音
            elif distance <= 20:
                points = 50
                effect = "不错!"
                color = self.colors['success']
                self.combo += 1
                self.play_sound(800)   # 中音
            else:
                points = 25
                effect = "还行"
                color = self.colors['success']
                self.combo += 1
                self.play_sound(600)   # 低音
            
            self.score += points
            self.update_score_display()
            
            # 显示效果
            self.show_effect(effect, color)
            
            # 移除音符
            self.canvas.delete(hit_note['id'])
            self.notes.remove(hit_note)
        else:
            # 没有击中任何音符
            self.combo = 0
            self.show_effect("失误!", self.colors['miss'])
            self.play_sound(200)  # 错误音
            self.update_score_display()
            
    def play_sound(self, frequency):
        """播放音效（Windows系统）"""
        try:
            winsound.Beep(frequency, 100)
        except:
            pass  # 非Windows系统或其他错误
            
    def show_effect(self, text, color):
        """显示打击效果"""
        self.effect_label.config(text=text, fg=color)
        self.root.after(500, lambda: self.effect_label.config(text=""))
        
    def update_score_display(self):
        """更新得分显示"""
        self.score_label.config(text=f"得分: {self.score}")
        self.combo_label.config(text=f"连击: {self.combo}")
        
    def change_difficulty(self):
        """改变游戏难度"""
        difficulty = self.difficulty_var.get()
        if difficulty == "简单":
            self.beat_interval = 1.5
            self.note_speed = 2
        elif difficulty == "中等":
            self.beat_interval = 1.0
            self.note_speed = 3
        else:  # 困难
            self.beat_interval = 0.6
            self.note_speed = 4
            
    def start_game(self):
        """开始游戏"""
        self.score = 0
        self.combo = 0
        self.notes = []
        self.game_running = True
        
        # 清除画布上的所有音符
        self.canvas.delete("note")
        
        # 更新UI状态
        self.start_button.config(state='disabled')
        self.stop_button.config(state='normal')
        
        # 更新显示
        self.update_score_display()
        
        # 开始生成音符
        self.generate_note()
        
        # 开始动画更新
        self.update_animation()
        
    def generate_note(self):
        """生成音符"""
        if not self.game_running:
            return
            
        # 随机生成音符（3种颜色，可以扩展为不同按键）
        x = random.randint(50, 550)
        note_size = 30
        
        note_id = self.canvas.create_oval(x - note_size//2, 0,
                                         x + note_size//2, note_size,
                                         fill=self.colors['note'], 
                                         tags="note",
                                         outline='white', width=2)
        
        self.notes.append({
            'id': note_id,
            'x': x,
            'y': 0
        })
        
        # 根据难度设置下次生成时间
        self.beat_timer = self.root.after(int(self.beat_interval * 1000), 
                                         self.generate_note)
        
    def update_animation(self):
        """更新音符动画"""
        if not self.game_running:
            return
            
        # 移动所有音符
        notes_to_remove = []
        for note in self.notes:
            self.canvas.move(note['id'], 0, self.note_speed)
            coords = self.canvas.coords(note['id'])
            
            # 检查音符是否超出画布
            if coords[3] > self.target_y + 50:
                # 音符掉落到打击线以下，判定为miss
                self.canvas.delete(note['id'])
                notes_to_remove.append(note)
                self.combo = 0
                self.update_score_display()
                self.show_effect("错过!", self.colors['miss'])
                self.play_sound(200)
                
        # 移除超出的音符
        for note in notes_to_remove:
            if note in self.notes:
                self.notes.remove(note)
                
        # 继续动画
        self.root.after(20, self.update_animation)  # 20毫秒更新一次
        
    def stop_game(self):
        """停止游戏"""
        self.game_running = False
        
        # 停止生成音符
        if self.beat_timer:
            self.root.after_cancel(self.beat_timer)
            
        # 清除所有音符
        self.canvas.delete("note")
        self.notes = []
        
        # 显示游戏结束信息
        messagebox.showinfo("游戏结束", f"游戏结束!\n最终得分: {self.score}\n最高连击: {self.combo}")
        
        # 重置UI
        self.start_button.config(state='normal')
        self.stop_button.config(state='disabled')
        
        # 清除效果显示
        self.show_effect("", "")

def main():
    root = tk.Tk()
    game = MusicGame(root)
    root.mainloop()

if __name__ == "__main__":
    main()