import tkinter as tk
import math

class RocketSimulator:
    def __init__(self, root):
        self.root = root
        self.root.title("🚀 火箭发射模拟器")
        self.root.geometry("800x700")

        # ---------- 物理参数 ----------
        self.g = 9.8                # 重力加速度 (m/s²)
        self.m0 = 1000.0            # 初始总质量 (kg)
        self.m_fuel = 500.0         # 燃料质量 (kg)
        self.thrust = 15000.0       # 推力 (N)
        self.burn_rate = 10.0       # 燃料消耗率 (kg/s)
        self.Cd = 0.5               # 阻力系数
        self.A = 1.0               # 截面积 (m²)
        self.rho = 1.225           # 空气密度 (kg/m³)

        # ---------- 状态变量 ----------
        self.time = 0.0
        self.height = 0.0          # 高度 (m)
        self.velocity = 0.0        # 速度 (m/s)，向上为正
        self.mass = self.m0        # 当前质量 (kg)
        self.fuel_left = self.m_fuel
        self.is_running = False
        self.is_paused = False
        self.is_landed = False
        self.max_height = 0.0

        # ---------- 界面布局 ----------
        # 数据面板
        info_frame = tk.Frame(root, bg='#e0e0e0')
        info_frame.pack(fill=tk.X, padx=10, pady=5)

        self.labels = {}
        data = [
            ("时间", "time", "{:.1f} s"),
            ("高度", "height", "{:.1f} m"),
            ("速度", "velocity", "{:.1f} m/s"),
            ("加速度", "accel", "{:.2f} m/s²"),
            ("质量", "mass", "{:.1f} kg"),
            ("燃料", "fuel", "{:.1f} kg"),
            ("状态", "status", "{}")
        ]
        for i, (desc, key, fmt) in enumerate(data):
            lbl = tk.Label(info_frame, text=f"{desc}:", font=("Arial", 10, "bold"), bg='#e0e0e0')
            lbl.grid(row=0, column=i*2, padx=(5,0), pady=5, sticky='e')
            val = tk.Label(info_frame, text="0.0", font=("Arial", 10), bg='#e0e0e0', width=10, anchor='w')
            val.grid(row=0, column=i*2+1, padx=(0,10), pady=5, sticky='w')
            self.labels[key] = (val, fmt)

        # 画布 (显示火箭和轨迹)
        self.canvas = tk.Canvas(root, width=600, height=500, bg='#c8e6ff')
        self.canvas.pack(pady=10)

        # 绘制地面和参考线
        self.ground_y = 450        # 地面 y 坐标
        self.canvas.create_rectangle(0, self.ground_y, 600, 500, fill='#8b5a2b', outline='')
        self.canvas.create_line(0, self.ground_y, 600, self.ground_y, fill='#4a7a2b', width=3)

        # 刻度标记 (高度标尺)
        for h in range(0, 500, 100):
            y = self.ground_y - h * 0.8   # 比例：0.8 像素/米，最大显示约 500 米
            self.canvas.create_line(10, y, 20, y, fill='black')
            self.canvas.create_text(25, y, text=f"{h}m", anchor='w', font=("Arial", 8))

        # 火箭 (用三角形表示)
        self.rocket = self.canvas.create_polygon(
            295, self.ground_y-20, 305, self.ground_y-20, 300, self.ground_y-40,
            fill='red', outline='black', width=2
        )
        # 火焰 (初始隐藏)
        self.flame = self.canvas.create_polygon(
            295, self.ground_y, 305, self.ground_y, 300, self.ground_y+15,
            fill='orange', outline='orange', state='hidden'
        )

        # 控制按钮
        btn_frame = tk.Frame(root)
        btn_frame.pack(pady=10)

        self.btn_launch = tk.Button(btn_frame, text="🚀 发射", command=self.launch, width=10, bg='lightgreen')
        self.btn_launch.grid(row=0, column=0, padx=5)

        self.btn_pause = tk.Button(btn_frame, text="⏸ 暂停", command=self.toggle_pause, width=10, state='disabled', bg='lightyellow')
        self.btn_pause.grid(row=0, column=1, padx=5)

        self.btn_reset = tk.Button(btn_frame, text="🔄 重置", command=self.reset, width=10, bg='lightcoral')
        self.btn_reset.grid(row=0, column=2, padx=5)

        # 状态初始化
        self.update_display()

    # ---------- 物理更新 ----------
    def physics_step(self, dt):
        if not self.is_running or self.is_paused or self.is_landed:
            return

        # 计算当前推力
        if self.fuel_left > 0:
            thrust = self.thrust
            # 燃料消耗
            dm = self.burn_rate * dt
            if dm > self.fuel_left:
                dm = self.fuel_left
            self.fuel_left -= dm
            self.mass -= dm
        else:
            thrust = 0.0

        # 空气阻力 D = 0.5 * rho * v^2 * Cd * A，方向与速度相反
        if self.velocity > 0:
            drag = 0.5 * self.rho * self.velocity**2 * self.Cd * self.A
        else:
            drag = 0.0  # 下落时忽略阻力或按绝对值处理，此处简化

        # 合力 (向上为正)
        force_net = thrust - self.mass * self.g - drag
        accel = force_net / self.mass

        # 更新速度、位置 (欧拉积分)
        self.velocity += accel * dt
        self.height += self.velocity * dt
        self.time += dt

        # 记录最大高度
        if self.height > self.max_height:
            self.max_height = self.height

        # 检查着陆
        if self.height <= 0 and self.velocity <= 0:
            self.height = 0
            self.velocity = 0
            self.is_landed = True
            self.is_running = False
            self.btn_pause.config(state='disabled')
            self.btn_launch.config(state='disabled')
            self.update_display()
            self.update_canvas()
            self.canvas.itemconfig(self.flame, state='hidden')
            return

        # 更新显示
        self.update_display()
        self.update_canvas()

        # 继续循环
        self.root.after(30, self.physics_step, dt)   # 30ms 更新一次，dt 固定

    # ---------- 更新显示 ----------
    def update_display(self):
        status = "飞行中"
        if self.is_landed:
            status = "已着陆 🛬"
        elif not self.is_running:
            status = "待命"
        elif self.is_paused:
            status = "暂停 ⏸"

        # 计算加速度用于显示
        if self.mass > 0:
            if self.fuel_left > 0:
                thrust = self.thrust
            else:
                thrust = 0.0
            drag = 0.5 * self.rho * self.velocity**2 * self.Cd * self.A if self.velocity > 0 else 0.0
            accel = (thrust - self.mass * self.g - drag) / self.mass
        else:
            accel = 0.0

        data = {
            "time": self.time,
            "height": self.height,
            "velocity": self.velocity,
            "accel": accel,
            "mass": self.mass,
            "fuel": max(0, self.fuel_left),
            "status": status
        }
        for key, (label, fmt) in self.labels.items():
            label.config(text=fmt.format(data[key]))

    def update_canvas(self):
        # 将高度映射到画布坐标 (地面 y=ground_y, 每米 0.8 像素)
        y_pos = self.ground_y - self.height * 0.8
        if y_pos < 10:
            y_pos = 10  # 防止超出顶部

        # 更新火箭位置 (三角形底边中心在 x=300)
        x0 = 295
        x1 = 305
        y0 = y_pos
        y1 = y_pos - 20   # 火箭高度 20 像素
        self.canvas.coords(self.rocket, x0, y0, x1, y0, 300, y1)

        # 火焰：只在有推力且高度>0时显示
        if self.is_running and not self.is_paused and self.fuel_left > 0 and self.height > 0:
            self.canvas.itemconfig(self.flame, state='normal')
            # 火焰在火箭底部
            self.canvas.coords(self.flame, x0, y0, x1, y0, 300, y0+15)
        else:
            self.canvas.itemconfig(self.flame, state='hidden')

    # ---------- 控制函数 ----------
    def launch(self):
        if self.is_landed:
            return
        if self.is_running:
            return
        # 如果已经飞行结束，重置再发射 (但这里重置由reset处理)
        self.is_running = True
        self.is_paused = False
        self.btn_launch.config(state='disabled')
        self.btn_pause.config(state='normal')
        # 启动物理循环，dt = 0.02s (20ms)
        self.root.after(50, self.physics_step, 0.02)

    def toggle_pause(self):
        if not self.is_running:
            return
        self.is_paused = not self.is_paused
        self.btn_pause.config(text="▶ 继续" if self.is_paused else "⏸ 暂停")
        self.update_display()

    def reset(self):
        # 重置所有状态
        self.is_running = False
        self.is_paused = False
        self.is_landed = False
        self.time = 0.0
        self.height = 0.0
        self.velocity = 0.0
        self.mass = self.m0
        self.fuel_left = self.m_fuel
        self.max_height = 0.0

        self.btn_launch.config(state='normal')
        self.btn_pause.config(state='disabled', text="⏸ 暂停")
        self.canvas.itemconfig(self.flame, state='hidden')
        self.update_display()
        self.update_canvas()

# ---------- 运行主程序 ----------
if __name__ == "__main__":
    root = tk.Tk()
    app = RocketSimulator(root)
    root.mainloop()