using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Windows.Forms; using System.IO; using Microsoft.Win32; namespace DesktopRoachRampage { static class Program { [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new MainForm()); } } enum CockroachState { Walking, Flying, Dead // 死亡状态 } class Cockroach { public float X { get; set; } public float Y { get; set; } public float DirectionX { get; set; } public float DirectionY { get; set; } public float CurrentAngle { get; set; } public int CurrentFrame { get; set; } public Random Random { get; set; } public CockroachState State { get; set; } public float FlyHeightOffset { get; set; } public float StateTimer { get; set; } public float DeathTimer { get; set; } // 死亡后消失计时器 public float Scale { get; set; } // 缩放比例,死亡时缩小 public Cockroach(float x, float y, Random rand) { X = x; Y = y; Random = rand; State = CockroachState.Walking; FlyHeightOffset = 0; StateTimer = 0; DeathTimer = 0; Scale = 1f; double angle = rand.NextDouble() * Math.PI * 2; float speed = 2f + (float)rand.NextDouble() * 2f; DirectionX = (float)Math.Cos(angle) * speed; DirectionY = (float)Math.Sin(angle) * speed; CurrentAngle = (float)(angle * 180 / Math.PI) + 90f; CurrentFrame = rand.Next(8); } // 被打死 public void Kill() { if (State == CockroachState.Dead) return; State = CockroachState.Dead; DeathTimer = 0; DirectionX = 0; DirectionY = 0; } public void Update(Rectangle totalBounds, int petSize) { // 如果已经死亡,处理消失动画 if (State == CockroachState.Dead) { DeathTimer++; Scale = Math.Max(0, 1f - DeathTimer / 30f); // 30帧内缩小到消失 return; } StateTimer++; // 更频繁检查状态切换(约5秒),飞行概率更高 if (StateTimer > 100) { StateTimer = 0; if (Random.NextDouble() < 0.7) // 70%概率切换 { if (State == CockroachState.Walking) { // 开始飞行 - 速度大幅提升 State = CockroachState.Flying; float flySpeed = 7f + (float)Random.NextDouble() * 4f; // 飞行速度7-11 double flyAngle = Random.NextDouble() * Math.PI * 2; DirectionX = (float)Math.Cos(flyAngle) * flySpeed; DirectionY = (float)Math.Sin(flyAngle) * flySpeed; } else { // 降落 State = CockroachState.Walking; FlyHeightOffset = 0; float walkSpeed = 2f + (float)Random.NextDouble() * 2f; double walkAngle = Random.NextDouble() * Math.PI * 2; DirectionX = (float)Math.Cos(walkAngle) * walkSpeed; DirectionY = (float)Math.Sin(walkAngle) * walkSpeed; } } } // 飞行时高度偏移 if (State == CockroachState.Flying) { FlyHeightOffset = (float)Math.Sin(StateTimer * 0.1) * 5f - 8f; } // 移动 X += DirectionX; Y += DirectionY; // 边界检测与反弹 if (X <= totalBounds.Left || X >= totalBounds.Right - petSize) { DirectionX = -DirectionX + (float)(Random.NextDouble() - 0.5) * 2; float minSpeed = State == CockroachState.Flying ? 6f : 1.5f; if (Math.Abs(DirectionX) < minSpeed) DirectionX = DirectionX > 0 ? minSpeed + 1 : -minSpeed - 1; X = Math.Max(totalBounds.Left, Math.Min(X, totalBounds.Right - petSize)); } if (Y <= totalBounds.Top || Y >= totalBounds.Bottom - petSize) { DirectionY = -DirectionY + (float)(Random.NextDouble() - 0.5) * 2; float minSpeed = State == CockroachState.Flying ? 6f : 1.5f; if (Math.Abs(DirectionY) < minSpeed) DirectionY = DirectionY > 0 ? minSpeed + 1 : -minSpeed - 1; Y = Math.Max(totalBounds.Top, Math.Min(Y, totalBounds.Bottom - petSize)); } // 随机改变方向 if (Random.Next(100) < 5) { float changeRange = State == CockroachState.Flying ? 6f : 3f; DirectionX += (float)(Random.NextDouble() - 0.5) * changeRange; DirectionY += (float)(Random.NextDouble() - 0.5) * changeRange; float maxSpeed = State == CockroachState.Flying ? 12f : 5f; DirectionX = Math.Max(-maxSpeed, Math.Min(maxSpeed, DirectionX)); DirectionY = Math.Max(-maxSpeed, Math.Min(maxSpeed, DirectionY)); } CurrentFrame = (CurrentFrame + 1) % 8; } public void Draw(Graphics g, Image[] walkFrames, Image[] flyFrames, int petSize) { Image[] frames = State == CockroachState.Flying ? flyFrames : walkFrames; if (frames == null || frames.Length == 0) return; Image frame = frames[CurrentFrame % frames.Length]; if (frame == null) return; float targetAngle = (float)(Math.Atan2(DirectionY, DirectionX) * 180 / Math.PI) + 90f; float angleDiff = targetAngle - CurrentAngle; if (angleDiff > 180) angleDiff -= 360; if (angleDiff < -180) angleDiff += 360; CurrentAngle += angleDiff * 0.15f; Matrix oldMatrix = g.Transform; float drawY = Y + FlyHeightOffset; float drawSize = petSize * Scale; // 绘制缩放和旋转 g.TranslateTransform(X + drawSize / 2, drawY + drawSize / 2); g.RotateTransform(CurrentAngle); g.ScaleTransform(Scale, Scale); g.TranslateTransform(-drawSize / 2, -drawSize / 2); g.DrawImage(frame, 0, 0, drawSize, drawSize); g.Transform = oldMatrix; } } // 点击特效类 class ClickEffect { public float X { get; set; } public float Y { get; set; } public float Timer { get; set; } public const float MaxTime = 15f; // 持续15帧 public ClickEffect(float x, float y) { X = x; Y = y; Timer = 0; } public void Update() { Timer++; } public void Draw(Graphics g) { float progress = Timer / MaxTime; float size = 20 + progress * 30; // 从20扩散到50 float alpha = 1f - progress; // 逐渐透明 using (Pen pen = new Pen(Color.FromArgb((int)(alpha * 200), 255, 100, 100), 3)) { g.DrawEllipse(pen, X - size / 2, Y - size / 2, size, size); } } public bool IsDead() { return Timer >= MaxTime; } } class MainForm : Form { private List cockroaches; private Image[] walkFrames; private Image[] flyFrames; private Timer mainTimer; private Timer breedTimer; private Random random; private const int PetSize = 64; private bool dragging = false; private int dragIndex = -1; private Point dragOffset; private const int MaxCockroaches = 50; private Rectangle totalScreenBounds; private Bitmap bufferBitmap; private Graphics bufferGraphics; // 打蟑螂相关 private int score = 0; // 分数 private int lastScore = 0; // 上次的分数 private float scoreIdleTimer = 0; // 分数没变化的时间 private bool showScore = true; // 是否显示分数 private List clickEffects; // 点击特效 private Font scoreFont; public MainForm() { random = new Random(); cockroaches = new List(); clickEffects = new List(); // 启用双缓冲优化 this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); this.UpdateStyles(); CalculateTotalScreenBounds(); this.FormBorderStyle = FormBorderStyle.None; this.ShowInTaskbar = false; this.TopMost = true; this.TransparencyKey = Color.Magenta; this.BackColor = Color.Magenta; this.Bounds = totalScreenBounds; LoadFrames(); // 创建双缓冲位图 CreateBufferBitmap(); // 创建分数字体 scoreFont = new Font("Arial", 14f, FontStyle.Bold); SpawnCockroachOnPrimary(); mainTimer = new Timer(); mainTimer.Interval = 50; mainTimer.Tick += MainTimer_Tick; mainTimer.Start(); breedTimer = new Timer(); breedTimer.Interval = 8000; breedTimer.Tick += BreedTimer_Tick; breedTimer.Start(); ContextMenuStrip menu = new ContextMenuStrip(); menu.Items.Add("清除所有蟑螂", null, (s, e) => ClearAll()); menu.Items.Add("添加一只蟑螂", null, (s, e) => SpawnCockroach()); menu.Items.Add("让所有蟑螂起飞!", null, (s, e) => MakeAllFly()); menu.Items.Add("让所有蟑螂降落!", null, (s, e) => MakeAllLand()); menu.Items.Add("随机分布到所有屏幕", null, (s, e) => RedistributeAll()); menu.Items.Add("-", null, null); menu.Items.Add("重置分数", null, (s, e) => ResetScore()); menu.Items.Add("-", null, null); menu.Items.Add("Exit / 退出", null, (s, e) => Application.Exit()); this.ContextMenuStrip = menu; this.MouseDown += MainForm_MouseDown; this.MouseMove += MainForm_MouseMove; this.MouseUp += MainForm_MouseUp; SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged; } private void ResetScore() { score = 0; lastScore = 0; showScore = true; scoreIdleTimer = 0; this.Invalidate(); } private void CreateBufferBitmap() { if (bufferBitmap != null) { bufferBitmap.Dispose(); bufferGraphics.Dispose(); } bufferBitmap = new Bitmap(totalScreenBounds.Width, totalScreenBounds.Height, PixelFormat.Format32bppArgb); bufferGraphics = Graphics.FromImage(bufferBitmap); bufferGraphics.InterpolationMode = InterpolationMode.NearestNeighbor; bufferGraphics.SmoothingMode = SmoothingMode.None; } private void CalculateTotalScreenBounds() { totalScreenBounds = Rectangle.Empty; foreach (Screen screen in Screen.AllScreens) { totalScreenBounds = Rectangle.Union(totalScreenBounds, screen.Bounds); } } private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e) { CalculateTotalScreenBounds(); this.Bounds = totalScreenBounds; CreateBufferBitmap(); this.Invalidate(); } private void SpawnCockroachOnPrimary() { if (cockroaches.Count >= MaxCockroaches) return; Rectangle primary = Screen.PrimaryScreen.WorkingArea; float x = primary.Left + random.Next(100, primary.Width - 100 - PetSize); float y = primary.Top + random.Next(100, primary.Height - 100 - PetSize); cockroaches.Add(new Cockroach(x, y, random)); UpdateTitle(); } private void SpawnCockroach() { if (cockroaches.Count >= MaxCockroaches) return; Screen[] screens = Screen.AllScreens; Screen randomScreen = screens[random.Next(screens.Length)]; Rectangle workingArea = randomScreen.WorkingArea; float x = workingArea.Left + random.Next(50, workingArea.Width - 50 - PetSize); float y = workingArea.Top + random.Next(50, workingArea.Height - 50 - PetSize); cockroaches.Add(new Cockroach(x, y, random)); UpdateTitle(); } private void MakeAllFly() { foreach (var roach in cockroaches) { if (roach.State != CockroachState.Dead) { roach.State = CockroachState.Flying; roach.StateTimer = 0; float flySpeed = 7f + (float)random.NextDouble() * 4f; double flyAngle = random.NextDouble() * Math.PI * 2; roach.DirectionX = (float)Math.Cos(flyAngle) * flySpeed; roach.DirectionY = (float)Math.Sin(flyAngle) * flySpeed; } } this.Invalidate(); } private void MakeAllLand() { foreach (var roach in cockroaches) { if (roach.State != CockroachState.Dead) { roach.State = CockroachState.Walking; roach.FlyHeightOffset = 0; roach.StateTimer = 0; float walkSpeed = 2f + (float)random.NextDouble() * 2f; double walkAngle = random.NextDouble() * Math.PI * 2; roach.DirectionX = (float)Math.Cos(walkAngle) * walkSpeed; roach.DirectionY = (float)Math.Sin(walkAngle) * walkSpeed; } } this.Invalidate(); } private void RedistributeAll() { Screen[] screens = Screen.AllScreens; foreach (var roach in cockroaches) { if (roach.State != CockroachState.Dead) { Screen randomScreen = screens[random.Next(screens.Length)]; Rectangle workingArea = randomScreen.WorkingArea; roach.X = workingArea.Left + random.Next(50, workingArea.Width - 50 - PetSize); roach.Y = workingArea.Top + random.Next(50, workingArea.Height - 50 - PetSize); } } this.Invalidate(); } private void UpdateTitle() { int flyCount = 0; int walkCount = 0; int deadCount = 0; foreach (var roach in cockroaches) { if (roach.State == CockroachState.Flying) flyCount++; else if (roach.State == CockroachState.Walking) walkCount++; else deadCount++; } this.Text = string.Format("Desktop Roach Rampage - {0} roaches alive (flying:{1} walking:{2}) - killed: {3}", cockroaches.Count - deadCount, flyCount, walkCount, score); } private void BreedTimer_Tick(object sender, EventArgs e) { // 检查是否所有蟑螂都被消灭了 int aliveCount = cockroaches.FindAll(r => r.State != CockroachState.Dead).Count; if (aliveCount == 0) { // 蟑螂全被消灭了,自动生成一只 SpawnCockroachOnPrimary(); return; } int currentCount = cockroaches.Count; for (int i = 0; i < currentCount && cockroaches.Count < MaxCockroaches; i++) { // 飞行中的蟑螂繁殖概率更高 double breedChance = cockroaches[i].State == CockroachState.Flying ? 0.6 : 0.4; if (cockroaches[i].State != CockroachState.Dead && random.NextDouble() < breedChance) { Cockroach parent = cockroaches[i]; float offsetX = (float)(random.NextDouble() - 0.5) * 80; float offsetY = (float)(random.NextDouble() - 0.5) * 80; float newX = parent.X + offsetX; float newY = parent.Y + offsetY; newX = Math.Max(totalScreenBounds.Left, Math.Min(newX, totalScreenBounds.Right - PetSize)); newY = Math.Max(totalScreenBounds.Top, Math.Min(newY, totalScreenBounds.Bottom - PetSize)); cockroaches.Add(new Cockroach(newX, newY, random)); } } UpdateTitle(); this.Invalidate(); } private void ClearAll() { cockroaches.Clear(); SpawnCockroachOnPrimary(); this.Invalidate(); } private void MainForm_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Left) { Point mousePos = this.PointToClient(e.Location); // 从后往前检测(点到最上面的蟑螂) bool hit = false; for (int i = cockroaches.Count - 1; i >= 0; i--) { Cockroach roach = cockroaches[i]; if (roach.State == CockroachState.Dead) continue; float drawY = roach.Y + roach.FlyHeightOffset; RectangleF rect = new RectangleF(roach.X - this.Left, drawY - this.Top, PetSize, PetSize); if (rect.Contains(mousePos)) { // 打到蟑螂了! roach.Kill(); score++; hit = true; showScore = true; // 立即显示分数 scoreIdleTimer = 0; // 添加点击特效 float effectX = mousePos.X + this.Left; float effectY = mousePos.Y + this.Top; clickEffects.Add(new ClickEffect(effectX, effectY)); break; } } // 如果没打到,也添加一个空的点击特效 if (!hit) { float effectX = mousePos.X + this.Left; float effectY = mousePos.Y + this.Top; clickEffects.Add(new ClickEffect(effectX, effectY)); } // 检查是否拖动(只有没打到蟑螂时才拖动) if (!hit) { for (int i = cockroaches.Count - 1; i >= 0; i--) { Cockroach roach = cockroaches[i]; if (roach.State == CockroachState.Dead) continue; float drawY = roach.Y + roach.FlyHeightOffset; RectangleF rect = new RectangleF(roach.X - this.Left, drawY - this.Top, PetSize, PetSize); if (rect.Contains(mousePos)) { dragging = true; dragIndex = i; dragOffset = new Point(mousePos.X - (int)(roach.X - this.Left), mousePos.Y - (int)(drawY - this.Top)); break; } } } } } private void MainForm_MouseMove(object sender, MouseEventArgs e) { if (dragging && dragIndex >= 0 && dragIndex < cockroaches.Count) { Point mousePos = this.PointToClient(e.Location); Cockroach roach = cockroaches[dragIndex]; roach.X = mousePos.X - dragOffset.X + this.Left; roach.Y = mousePos.Y - dragOffset.Y + this.Top - roach.FlyHeightOffset; this.Invalidate(); } } private void MainForm_MouseUp(object sender, MouseEventArgs e) { dragging = false; dragIndex = -1; } private void LoadFrames() { string basePath = AppDomain.CurrentDomain.BaseDirectory; string imagePath = Path.Combine(basePath, "images"); if (!Directory.Exists(imagePath)) { imagePath = Path.Combine(basePath, "..", "images"); } walkFrames = new Image[8]; flyFrames = new Image[8]; for (int i = 0; i < 8; i++) { string walkFrameFile = Path.Combine(imagePath, string.Format("walk_{0:D2}.png", i)); if (File.Exists(walkFrameFile)) walkFrames[i] = Image.FromFile(walkFrameFile); string flyFrameFile = Path.Combine(imagePath, string.Format("fly_{0:D2}.png", i)); if (File.Exists(flyFrameFile)) flyFrames[i] = Image.FromFile(flyFrameFile); } } private void MainTimer_Tick(object sender, EventArgs e) { // 更新蟑螂 foreach (var roach in cockroaches) { roach.Update(totalScreenBounds, PetSize); } // 移除完全消失的死蟑螂 cockroaches.RemoveAll(r => r.State == CockroachState.Dead && r.Scale <= 0); // 更新点击特效 for (int i = clickEffects.Count - 1; i >= 0; i--) { clickEffects[i].Update(); if (clickEffects[i].IsDead()) { clickEffects.RemoveAt(i); } } // 分数显示逻辑:分数变化时显示,2秒不变化则隐藏 if (score != lastScore) { lastScore = score; scoreIdleTimer = 0; showScore = true; } else { scoreIdleTimer++; // 50ms每帧,40帧 = 2秒 if (scoreIdleTimer >= 40) { showScore = false; } } UpdateTitle(); this.Invalidate(); } protected override void OnPaint(PaintEventArgs e) { // 使用双缓冲绘制 Graphics g = bufferGraphics; g.Clear(Color.Magenta); g.TranslateTransform(-this.Left, -this.Top); // 绘制蟑螂 foreach (var roach in cockroaches) { roach.Draw(g, walkFrames, flyFrames, PetSize); } // 绘制点击特效 foreach (var effect in clickEffects) { effect.Draw(g); } // 绘制分数(在主屏幕左上角) if (showScore) { g.ResetTransform(); g.TranslateTransform(Screen.PrimaryScreen.Bounds.Left - this.Left, Screen.PrimaryScreen.Bounds.Top - this.Top); string scoreText = string.Format("Killed: {0}", score); g.DrawString(scoreText, scoreFont, Brushes.Red, 10, 10); // 绘制剩余数量 int alive = cockroaches.FindAll(r => r.State != CockroachState.Dead).Count; string countText = string.Format("Alive: {0}", alive); g.DrawString(countText, scoreFont, Brushes.DarkOrange, 10, 35); g.ResetTransform(); } // 一次性绘制到屏幕 e.Graphics.DrawImage(bufferBitmap, 0, 0); } protected override void Dispose(bool disposing) { if (disposing) { SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged; if (mainTimer != null) mainTimer.Dispose(); if (breedTimer != null) breedTimer.Dispose(); if (bufferBitmap != null) bufferBitmap.Dispose(); if (bufferGraphics != null) bufferGraphics.Dispose(); if (scoreFont != null) scoreFont.Dispose(); if (walkFrames != null) foreach (var frame in walkFrames) if (frame != null) frame.Dispose(); if (flyFrames != null) foreach (var frame in flyFrames) if (frame != null) frame.Dispose(); } base.Dispose(disposing); } } }