133 lines
4.2 KiB
C#
133 lines
4.2 KiB
C#
using System.Diagnostics;
|
|
using System.Drawing.Drawing2D;
|
|
|
|
namespace TempleRun;
|
|
|
|
/// <summary>
|
|
/// 主窗体:负责游戏循环(定时器 + 高精度计时)、键盘输入、双缓冲绘制调度。
|
|
/// </summary>
|
|
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());
|
|
}
|
|
}
|