commit 8859dc0da5a26d64d3ddfb1c13b1b7603fff9114 Author: Frost-ZX Date: Wed Jul 22 20:34:10 2026 +0800 feat: 初始版本 diff --git a/DesktopRoachRampage/app/DesktopRoachRampage.exe b/DesktopRoachRampage/app/DesktopRoachRampage.exe new file mode 100644 index 0000000..5656014 Binary files /dev/null and b/DesktopRoachRampage/app/DesktopRoachRampage.exe differ diff --git a/DesktopRoachRampage/app/Program.cs b/DesktopRoachRampage/app/Program.cs new file mode 100644 index 0000000..54ca45a --- /dev/null +++ b/DesktopRoachRampage/app/Program.cs @@ -0,0 +1,706 @@ +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); + } + } +} diff --git a/DesktopRoachRampage/bin/DesktopRoachRampage.exe b/DesktopRoachRampage/bin/DesktopRoachRampage.exe new file mode 100644 index 0000000..5656014 Binary files /dev/null and b/DesktopRoachRampage/bin/DesktopRoachRampage.exe differ diff --git a/DesktopRoachRampage/bin/images/fly_00.png b/DesktopRoachRampage/bin/images/fly_00.png new file mode 100644 index 0000000..f4b8ffa Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_00.png differ diff --git a/DesktopRoachRampage/bin/images/fly_01.png b/DesktopRoachRampage/bin/images/fly_01.png new file mode 100644 index 0000000..e1c5b83 Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_01.png differ diff --git a/DesktopRoachRampage/bin/images/fly_02.png b/DesktopRoachRampage/bin/images/fly_02.png new file mode 100644 index 0000000..45993fe Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_02.png differ diff --git a/DesktopRoachRampage/bin/images/fly_03.png b/DesktopRoachRampage/bin/images/fly_03.png new file mode 100644 index 0000000..a2cf92d Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_03.png differ diff --git a/DesktopRoachRampage/bin/images/fly_04.png b/DesktopRoachRampage/bin/images/fly_04.png new file mode 100644 index 0000000..ef40510 Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_04.png differ diff --git a/DesktopRoachRampage/bin/images/fly_05.png b/DesktopRoachRampage/bin/images/fly_05.png new file mode 100644 index 0000000..a43bce2 Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_05.png differ diff --git a/DesktopRoachRampage/bin/images/fly_06.png b/DesktopRoachRampage/bin/images/fly_06.png new file mode 100644 index 0000000..4a328f1 Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_06.png differ diff --git a/DesktopRoachRampage/bin/images/fly_07.png b/DesktopRoachRampage/bin/images/fly_07.png new file mode 100644 index 0000000..01ca750 Binary files /dev/null and b/DesktopRoachRampage/bin/images/fly_07.png differ diff --git a/DesktopRoachRampage/bin/images/walk_00.png b/DesktopRoachRampage/bin/images/walk_00.png new file mode 100644 index 0000000..7853398 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_00.png differ diff --git a/DesktopRoachRampage/bin/images/walk_01.png b/DesktopRoachRampage/bin/images/walk_01.png new file mode 100644 index 0000000..eb09998 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_01.png differ diff --git a/DesktopRoachRampage/bin/images/walk_02.png b/DesktopRoachRampage/bin/images/walk_02.png new file mode 100644 index 0000000..26a774b Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_02.png differ diff --git a/DesktopRoachRampage/bin/images/walk_03.png b/DesktopRoachRampage/bin/images/walk_03.png new file mode 100644 index 0000000..c330dc5 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_03.png differ diff --git a/DesktopRoachRampage/bin/images/walk_04.png b/DesktopRoachRampage/bin/images/walk_04.png new file mode 100644 index 0000000..b95bc91 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_04.png differ diff --git a/DesktopRoachRampage/bin/images/walk_05.png b/DesktopRoachRampage/bin/images/walk_05.png new file mode 100644 index 0000000..fb7bd93 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_05.png differ diff --git a/DesktopRoachRampage/bin/images/walk_06.png b/DesktopRoachRampage/bin/images/walk_06.png new file mode 100644 index 0000000..edb6e8e Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_06.png differ diff --git a/DesktopRoachRampage/bin/images/walk_07.png b/DesktopRoachRampage/bin/images/walk_07.png new file mode 100644 index 0000000..db22eb8 Binary files /dev/null and b/DesktopRoachRampage/bin/images/walk_07.png differ diff --git a/DesktopRoachRampage/build.bat b/DesktopRoachRampage/build.bat new file mode 100644 index 0000000..005ff2f --- /dev/null +++ b/DesktopRoachRampage/build.bat @@ -0,0 +1,24 @@ +@echo off +REM Build script for Desktop Roach Rampage +REM Compiles the C# source code into a Windows executable + +echo Building Desktop Roach Rampage... +cd /d "%~dp0app" + +REM Use .NET Framework compiler +C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe /target:winexe /r:System.dll /r:System.Drawing.dll /r:System.Windows.Forms.dll /out:DesktopRoachRampage.exe Program.cs + +if %ERRORLEVEL% NEQ 0 ( + echo Build failed! + pause + exit /b 1 +) + +echo Copying executable to bin directory... +if not exist "..\bin" mkdir "..\bin" +copy /Y "DesktopRoachRampage.exe" "..\bin\" > nul + +echo. +echo Build completed successfully! +echo Executable: DesktopRoachRampage\bin\DesktopRoachRampage.exe +pause diff --git a/DesktopRoachRampage/run.bat b/DesktopRoachRampage/run.bat new file mode 100644 index 0000000..7d7626f --- /dev/null +++ b/DesktopRoachRampage/run.bat @@ -0,0 +1,12 @@ +@echo off +REM Run Desktop Roach Rampage + +cd /d "%~dp0bin" +if not exist "DesktopRoachRampage.exe" ( + echo Executable not found! Please run build.bat first. + pause + exit /b 1 +) + +echo Starting Desktop Roach Rampage... +start "" DesktopRoachRampage.exe diff --git a/tools/GenerateCockroaches.cs b/tools/GenerateCockroaches.cs new file mode 100644 index 0000000..d80004d --- /dev/null +++ b/tools/GenerateCockroaches.cs @@ -0,0 +1,283 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; + +class GenerateCockroaches +{ + static string saveDir = @"e:\Temp\desktop-pets\DesktopRoachRampage\images"; + + static void DrawPixel(Bitmap bmp, int x, int y, Color color) + { + if (x >= 0 && x < bmp.Width && y >= 0 && y < bmp.Height) + bmp.SetPixel(x, y, color); + } + + static void DrawThickLeg(Bitmap bmp, int x1, int y1, int x2, int y2, int x3, int y3, Color color, Color colorDark) + { + // 第一段 - 3像素宽 + DrawPixel(bmp, x1, y1, color); + DrawPixel(bmp, x1 - 1, y1, color); + DrawPixel(bmp, x1 + 1, y1, color); + DrawPixel(bmp, x1, y1 - 1, color); + DrawPixel(bmp, x1, y1 + 1, color); + + // 第二段 - 3像素宽 + DrawPixel(bmp, x2, y2, color); + DrawPixel(bmp, x2 - 1, y2, color); + DrawPixel(bmp, x2 + 1, y2, color); + DrawPixel(bmp, x2, y2 - 1, color); + DrawPixel(bmp, x2, y2 + 1, color); + + // 第三段末端(深色)- 略窄 + DrawPixel(bmp, x3, y3, colorDark); + DrawPixel(bmp, x3 - 1, y3, colorDark); + DrawPixel(bmp, x3 + 1, y3, colorDark); + } + + static void DrawCockroachBody(Bitmap bmp, int centerX, int centerY, int frame, int totalFrames, bool isFlying, bool isScared = false, bool isCrawling = false) + { + // 蟑螂颜色 + var colorHead = Color.FromArgb(100, 65, 35); + var colorBody = Color.FromArgb(80, 50, 25); + var colorBodyDark = Color.FromArgb(55, 30, 10); + var colorLeg = Color.FromArgb(110, 75, 45); + var colorLegDark = Color.FromArgb(85, 55, 30); + var colorAnt = Color.FromArgb(130, 90, 60); + var colorWing = Color.FromArgb(160, 130, 100); + var colorWingLight = Color.FromArgb(200, 170, 140); + var colorWingVein = Color.FromArgb(120, 90, 60); + + int cy = centerY; + + // 受惊吓时身体略抬高 + int bodyOffsetY = isScared ? -3 : (isCrawling ? 2 : 0); + + // ========================================== + // 身体主体 + // ========================================== + + // 头部 + DrawPixel(bmp, centerX - 1, cy - 14 + bodyOffsetY, colorHead); + DrawPixel(bmp, centerX, cy - 14 + bodyOffsetY, colorHead); + DrawPixel(bmp, centerX + 1, cy - 14 + bodyOffsetY, colorHead); + + // 头部区域 + for (int y = -13; y <= -10; y++) { + int width = (y + 13) * 2 + 3; + for (int x = -width / 2; x <= width / 2; x++) { + DrawPixel(bmp, centerX + x, cy + y + bodyOffsetY, colorHead); + } + } + + // 前胸区域 + for (int y = -9; y <= -5; y++) { + int width = 9 + (y + 9) * 2; + for (int x = -width / 2; x <= width / 2; x++) { + DrawPixel(bmp, centerX + x, cy + y + bodyOffsetY, colorBody); + } + } + + // 腹部主体 + for (int y = -4; y <= 8; y++) { + for (int x = -8; x <= 8; x++) { + DrawPixel(bmp, centerX + x, cy + y + bodyOffsetY, colorBodyDark); + } + } + + // 腹部后段 + for (int y = 9; y <= 12; y++) { + int width = 17 - (y - 9) * 2; + for (int x = -width / 2; x <= width / 2; x++) { + DrawPixel(bmp, centerX + x, cy + y + bodyOffsetY, colorBodyDark); + } + } + + // 尾部末端 + for (int x = -3; x <= 3; x++) + DrawPixel(bmp, centerX + x, cy + 13 + bodyOffsetY, colorBodyDark); + for (int x = -2; x <= 2; x++) + DrawPixel(bmp, centerX + x, cy + 14 + bodyOffsetY, colorBodyDark); + + // 身体中线纹理 + for (int y = -10; y <= 12; y++) { + DrawPixel(bmp, centerX, cy + y + bodyOffsetY, colorBody); + } + + // ========================================== + // 翅膀 + // ========================================== + if (isFlying) + { + double wingPhase = (double)frame / totalFrames * Math.PI * 2; + int wingSpread = (int)(Math.Sin(wingPhase) * 4) + 8; + int wingAngle = (int)(Math.Sin(wingPhase * 2) * 2); + + // 左翅膀 + for (int i = 1; i <= wingSpread; i++) { + for (int j = -3; j <= 7; j++) { + int yOffset = j + wingAngle; + if (i > wingSpread - 2) { + DrawPixel(bmp, centerX - 8 - i, cy + yOffset - 4 + bodyOffsetY, colorWingLight); + } else { + DrawPixel(bmp, centerX - 8 - i, cy + yOffset - 4 + bodyOffsetY, colorWing); + } + } + } + + // 右翅膀 + for (int i = 1; i <= wingSpread; i++) { + for (int j = -3; j <= 7; j++) { + int yOffset = j - wingAngle; + if (i > wingSpread - 2) { + DrawPixel(bmp, centerX + 8 + i, cy + yOffset - 4 + bodyOffsetY, colorWingLight); + } else { + DrawPixel(bmp, centerX + 8 + i, cy + yOffset - 4 + bodyOffsetY, colorWing); + } + } + } + + // 翅膀纹理 + for (int i = 2; i <= wingSpread - 2; i += 3) { + for (int j = 0; j <= 4; j++) { + DrawPixel(bmp, centerX - 8 - i, cy + j - 3 + bodyOffsetY, colorWingVein); + DrawPixel(bmp, centerX + 8 + i, cy + j - 3 + bodyOffsetY, colorWingVein); + } + } + } + + // ========================================== + // 6条腿 - 非常粗壮 + // ========================================== + int[] legPosY = { cy - 8 + bodyOffsetY, cy + bodyOffsetY, cy + 10 + bodyOffsetY }; + + double phase = (double)frame / totalFrames * Math.PI * 2; + + if (isFlying) + { + // 飞行时腿悬空摆动 + for (int i = 0; i < 3; i++) { + double legPhase = phase + i * 0.8; + int swingX = (int)(Math.Sin(legPhase) * 4); + int swingY = (int)(Math.Cos(legPhase) * 2); + + // 左腿 + DrawThickLeg(bmp, + centerX - 8 + swingX, legPosY[i] + swingY, + centerX - 11 + swingX, legPosY[i] + 2 + swingY, + centerX - 14 + swingX, legPosY[i] + swingY, + colorLeg, colorLegDark); + + // 右腿 + DrawThickLeg(bmp, + centerX + 8 - swingX, legPosY[i] + swingY, + centerX + 11 - swingX, legPosY[i] + 2 + swingY, + centerX + 14 - swingX, legPosY[i] + swingY, + colorLeg, colorLegDark); + } + } + else + { + // 走路、爬行、受惊吓时的腿 + for (int i = 0; i < 3; i++) { + double legPhase = phase + i * 0.8; + int swing = (int)(Math.Sin(legPhase) * 2); + + // 爬行时腿的位置更低 + int crawlOffset = isCrawling ? 2 : 0; + int scaredOffset = isScared ? -1 : 0; + + // 左腿 + DrawThickLeg(bmp, + centerX - 8, legPosY[i] + crawlOffset + scaredOffset, + centerX - 11, legPosY[i] + 2 + swing + crawlOffset + scaredOffset, + centerX - 14, legPosY[i] + swing + crawlOffset + scaredOffset, + colorLeg, colorLegDark); + + // 右腿 + DrawThickLeg(bmp, + centerX + 8, legPosY[i] + crawlOffset + scaredOffset, + centerX + 11, legPosY[i] + 2 - swing + crawlOffset + scaredOffset, + centerX + 14, legPosY[i] - swing + crawlOffset + scaredOffset, + colorLeg, colorLegDark); + } + } + + // ========================================== + // 触角 + // ========================================== + double antPhase = phase * 0.5; + int antSwingL = (int)(Math.Sin(antPhase) * 2); + int antSwingR = (int)(Math.Sin(antPhase + Math.PI) * 2); + + // 受惊吓时触角竖起 + int antHeight = isScared ? -2 : 0; + + // 左触角 - 加粗 + for (int i = 1; i <= 7; i++) { + DrawPixel(bmp, centerX - 3 - i * 2, cy - 15 - i + antSwingL + bodyOffsetY + antHeight, colorAnt); + if (i > 2) { + DrawPixel(bmp, centerX - 3 - i * 2 + 1, cy - 15 - i + antSwingL + bodyOffsetY + antHeight, colorAnt); + } + } + + // 右触角 - 加粗 + for (int i = 1; i <= 7; i++) { + DrawPixel(bmp, centerX + 3 + i * 2, cy - 15 - i + antSwingR + bodyOffsetY + antHeight, colorAnt); + if (i > 2) { + DrawPixel(bmp, centerX + 3 + i * 2 - 1, cy - 15 - i + antSwingR + bodyOffsetY + antHeight, colorAnt); + } + } + } + + static void CreateCockroachImage(string filename, int frame, int totalFrames, bool isFlying, bool isScared = false, bool isCrawling = false) + { + int size = 64; + using (var bmp = new Bitmap(size, size, PixelFormat.Format32bppArgb)) + { + // 清空为透明 + for (int y = 0; y < size; y++) + for (int x = 0; x < size; x++) + bmp.SetPixel(x, y, Color.Transparent); + + int centerX = size / 2; + int centerY = size / 2 + 5; + + DrawCockroachBody(bmp, centerX, centerY, frame, totalFrames, isFlying, isScared, isCrawling); + + bmp.Save(Path.Combine(saveDir, filename), ImageFormat.Png); + } + Console.WriteLine("Saved: " + filename); + } + + static void Main() + { + if (!Directory.Exists(saveDir)) + Directory.CreateDirectory(saveDir); + + Console.WriteLine("正在生成像素风格蟑螂动画帧..."); + + // 生成8个行走动画帧 + int walkFrames = 8; + for (int i = 0; i < walkFrames; i++) { + CreateCockroachImage(string.Format("walk_{0:D2}.png", i), i, walkFrames, false); + } + + // 生成8个飞行动画帧 + int flyFrames = 8; + for (int i = 0; i < flyFrames; i++) { + CreateCockroachImage(string.Format("fly_{0:D2}.png", i), i, flyFrames, true); + } + + // 空闲帧 + CreateCockroachImage("cockroach_idle.png", 0, walkFrames, false); + + // 单独的动作帧 - 腿部加粗版本 + CreateCockroachImage("cockroach_walk1.png", 0, 4, false); + CreateCockroachImage("cockroach_walk2.png", 2, 4, false); + CreateCockroachImage("cockroach_crawl.png", 1, 4, false, false, true); // 爬行状态 + CreateCockroachImage("cockroach_scared.png", 0, 4, false, true, false); // 受惊吓状态 + + Console.WriteLine("所有图片生成完成!"); + } +} diff --git a/tools/GenerateCockroaches.exe b/tools/GenerateCockroaches.exe new file mode 100644 index 0000000..4c97ddb Binary files /dev/null and b/tools/GenerateCockroaches.exe differ diff --git a/tools/generate_images.py b/tools/generate_images.py new file mode 100644 index 0000000..05750b4 --- /dev/null +++ b/tools/generate_images.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +import urllib2 +import urllib +import os + +# create save directory +save_dir = r"e:\Temp\desktop-pets\images" +if not os.path.exists(save_dir): + os.makedirs(save_dir) + +# image API base URL +base_url = "https://trae-api-cn.mchost.guru/api/ide/v1/text_to_image" + +# cockroach action list +cockroach_actions = [ + ("cockroach_idle.png", "pixel art cockroach standing still, cute pixel style, transparent background, 64x64 pixels, dark brown color, detailed antennae, cartoon style"), + ("cockroach_walk1.png", "pixel art cockroach walking pose 1, cute pixel style, transparent background, 64x64 pixels, dark brown color, legs in motion, cartoon style"), + ("cockroach_walk2.png", "pixel art cockroach walking pose 2, cute pixel style, transparent background, 64x64 pixels, dark brown color, legs in different position, cartoon style"), + ("cockroach_crawl.png", "pixel art cockroach crawling low, cute pixel style, transparent background, 64x64 pixels, dark brown color, cartoon style"), + ("cockroach_scared.png", "pixel art cockroach scared pose, antennae raised, cute pixel style, transparent background, 64x64 pixels, dark brown color, cartoon style") +] + +# download each image +for filename, prompt in cockroach_actions: + print("Generating: " + filename) + url = base_url + "?prompt=" + urllib.quote(prompt) + "&image_size=square_hd" + + try: + response = urllib2.urlopen(url, timeout=60) + image_data = response.read() + + # save image + save_path = os.path.join(save_dir, filename) + with open(save_path, 'wb') as f: + f.write(image_data) + print("Saved: " + save_path) + except Exception as e: + print("Failed to generate " + filename + ": " + str(e)) + +print("All images generated!")