using System.Diagnostics; using System.Drawing.Drawing2D; namespace TempleRun; /// /// 主窗体:负责游戏循环(定时器 + 高精度计时)、键盘输入、双缓冲绘制调度。 /// public class GameForm : Form { private readonly GameWorld _world = new(); private readonly System.Windows.Forms.Timer _timer; private readonly Stopwatch _watch = Stopwatch.StartNew(); private double _lastTime; private double _fpsAccum; private int _frameCount; private bool _showFps; public GameForm() { Text = "神庙逃亡 · Temple Run (WinForms)"; ClientSize = new Size(1024, 720); MinimumSize = new Size(760, 540); StartPosition = FormStartPosition.CenterScreen; BackColor = Color.FromArgb(12, 12, 20); DoubleBuffered = true; ResizeRedraw = true; AutoScaleMode = AutoScaleMode.None; SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true); try { Icon = BuildIcon(); } catch { /* 图标失败不影响运行 */ } _lastTime = _watch.Elapsed.TotalSeconds; _timer = new System.Windows.Forms.Timer { Interval = 15 }; // ≈66Hz _timer.Tick += OnTick; _timer.Start(); } // ------------------------------------------------------------------ 主循环 private void OnTick(object sender, EventArgs e) { double now = _watch.Elapsed.TotalSeconds; float dt = (float)(now - _lastTime); _lastTime = now; if (dt <= 0f) return; if (dt > 0.06f) dt = 0.06f; // 卡顿/拖动窗口后不产生穿模 // FPS 统计 _frameCount++; _fpsAccum += dt; if (_fpsAccum >= 0.5) { _world.Fps = (float)(_frameCount / _fpsAccum); _frameCount = 0; _fpsAccum = 0; } _world.Update(dt); Invalidate(); } protected override void OnPaint(PaintEventArgs e) { GameRenderer.Draw(e.Graphics, ClientSize.Width, ClientSize.Height, _world, _showFps); } // ------------------------------------------------------------------ 输入 protected override bool ProcessCmdKey(ref Message msg, Keys keyData) { Keys key = keyData & Keys.KeyCode; if (key == Keys.F1) { _showFps = !_showFps; Invalidate(); return true; } if (key == Keys.F11) { WindowState = WindowState == FormWindowState.Maximized ? FormWindowState.Normal : FormWindowState.Maximized; return true; } if (key == Keys.F12) { _world.Muted = !_world.Muted; return true; } if (_world.HandleKey(key)) return true; return base.ProcessCmdKey(ref msg, keyData); } protected override void OnMouseClick(MouseEventArgs e) { base.OnMouseClick(e); // 鼠标左键也能触发"开始/重开",方便触屏设备 if (e.Button == MouseButtons.Left) { if (_world.State == RunState.Ready) _world.Start(); else if (_world.State == RunState.GameOver && _world.CanRestart) { _world.Start(); } } } protected override void OnFormClosed(FormClosedEventArgs e) { _timer.Stop(); _timer.Dispose(); GameRenderer.ResetCache(); base.OnFormClosed(e); } // ------------------------------------------------------------------ 图标 private static Icon BuildIcon() { using var bmp = new Bitmap(32, 32); using (var g = Graphics.FromImage(bmp)) { g.SmoothingMode = SmoothingMode.AntiAlias; g.Clear(Color.Transparent); using (var bg = new SolidBrush(Color.FromArgb(46, 34, 28))) g.FillEllipse(bg, 0, 0, 31, 31); using (var gold = new SolidBrush(Cfg.Gold)) g.FillEllipse(gold, 7, 7, 18, 18); using (var dark = new Pen(Cfg.GoldDark, 2.4f)) g.DrawEllipse(dark, 7, 7, 18, 18); using (var hi = new SolidBrush(Color.FromArgb(230, 255, 250, 220))) g.FillEllipse(hi, 11, 10, 5, 4); } return Icon.FromHandle(bmp.GetHicon()); } }