1
0

feat: 初始版本

This commit is contained in:
2026-07-22 20:34:10 +08:00
commit 8859dc0da5
24 changed files with 1065 additions and 0 deletions
Binary file not shown.
+706
View File
@@ -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<Cockroach> 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<ClickEffect> clickEffects; // 点击特效
private Font scoreFont;
public MainForm()
{
random = new Random();
cockroaches = new List<Cockroach>();
clickEffects = new List<ClickEffect>();
// 启用双缓冲优化
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);
}
}
}
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 639 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 634 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 629 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 649 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 590 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 585 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

+24
View File
@@ -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
+12
View File
@@ -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
+283
View File
@@ -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("所有图片生成完成!");
}
}
Binary file not shown.
+40
View File
@@ -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!")