You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java 2D游戏中利用像素数组绘制圆形?

嘿,刚好我之前在Java里做过类似的2D像素游戏绘图,给你几个实用的方案来实现圆形绘制,完全适配你现在用的pixels[x+y*width] = color;像素数组索引逻辑~

基础圆方程法(简单易理解)

最直接的方式就是利用圆的笛卡尔方程:(x - cx)² + (y - cy)² = r²,其中(cx, cy)是圆心坐标,r是圆的半径。我们可以遍历y轴方向的所有可能像素,计算出对应x轴的范围,然后填充像素。

空心圆实现

// 定义圆的参数
int cx = 150;    // 圆心x坐标
int cy = 150;    // 圆心y坐标
int radius = 60; // 半径
int color = 0xFF00FF; // 紫色(ARGB格式)
int width = 300; // 游戏窗口宽度
int height = 300;// 游戏窗口高度
int[] pixels = new int[width * height]; // 你的像素数组

// 遍历y轴上所有可能在圆范围内的像素
for (int y = cy - radius; y <= cy + radius; y++) {
    // 计算当前y与圆心的垂直距离
    int dy = y - cy;
    // 根据圆方程推导x的平方值
    int dxSquared = radius * radius - dy * dy;
    
    // 如果dx平方为负,说明当前y没有对应的x像素,直接跳过
    if (dxSquared < 0) continue;
    // 计算x的偏移量
    int dx = (int) Math.sqrt(dxSquared);
    
    // 绘制左右两个对称点,同时做边界检查避免数组越界
    int xLeft = cx - dx;
    int xRight = cx + dx;
    if (xLeft >= 0 && y >= 0 && xLeft < width && y < height) {
        pixels[xLeft + y * width] = color;
    }
    if (xRight >= 0 && y >= 0 && xRight < width && y < height && xRight != xLeft) {
        pixels[xRight + y * width] = color;
    }
}

实心圆实现

如果要画实心圆,只需要把每个y对应的x范围从左到右全部填充即可:

for (int y = cy - radius; y <= cy + radius; y++) {
    int dy = y - cy;
    int dxSquared = radius * radius - dy * dy;
    if (dxSquared < 0) continue;
    int dx = (int) Math.sqrt(dxSquared);
    
    // 跳过超出窗口的y值
    if (y < 0 || y >= height) continue;
    // 确保x范围在窗口内,避免越界
    int startX = Math.max(cx - dx, 0);
    int endX = Math.min(cx + dx, width - 1);
    
    // 填充当前y行内的所有x像素
    for (int x = startX; x <= endX; x++) {
        pixels[x + y * width] = color;
    }
}

这个方法的优点是逻辑直观,容易上手,缺点是用到了Math.sqrt(),计算量稍大,如果是游戏里频繁绘制圆,可能会有点影响性能。

中点圆算法(高效适合游戏)

如果追求更高的绘制效率,推荐用中点圆算法——这是专门为像素绘制设计的算法,不需要开根号,只用整数运算,速度快很多,特别适合实时游戏场景。

它的核心思路是通过跟踪圆的中点,每次判断下一个像素的最优位置,利用圆的8对称性减少重复计算:

// 绘制空心圆的方法
void drawCircle(int cx, int cy, int radius, int color, int[] pixels, int width, int height) {
    int x = radius;
    int y = 0;
    int error = 0;

    // 先绘制四个轴上的初始点
    setSafePixel(cx + x, cy, color, pixels, width, height);
    setSafePixel(cx - x, cy, color, pixels, width, height);
    setSafePixel(cx, cy + x, color, pixels, width, height);
    setSafePixel(cx, cy - x, color, pixels, width, height);

    // 利用对称性绘制其他点
    while (x > y) {
        y++;
        error += 2 * y + 1;
        // 判断是否需要向左调整x坐标
        if (error > 0) {
            x--;
            error -= 2 * x + 1;
        }

        // 绘制8个对称方向的像素
        setSafePixel(cx + x, cy + y, color, pixels, width, height);
        setSafePixel(cx - x, cy + y, color, pixels, width, height);
        setSafePixel(cx + x, cy - y, color, pixels, width, height);
        setSafePixel(cx - x, cy - y, color, pixels, width, height);
        setSafePixel(cx + y, cy + x, color, pixels, width, height);
        setSafePixel(cx - y, cy + x, color, pixels, width, height);
        setSafePixel(cx + y, cy - x, color, pixels, width, height);
        setSafePixel(cx - y, cy - x, color, pixels, width, height);
    }
}

// 辅助函数:安全设置像素,自动处理边界检查
void setSafePixel(int x, int y, int color, int[] pixels, int width, int height) {
    if (x >= 0 && x < width && y >= 0 && y < height) {
        pixels[x + y * width] = color;
    }
}

如果要画实心圆,可以在这个基础上,每次绘制对称点时,填充对应行的x范围,或者结合扫描线填充逻辑,效率同样很高。

额外注意事项
  • 边界检查很重要:一定要确保x和y在窗口的[0, width)和[0, height)范围内,不然会抛出ArrayIndexOutOfBoundsException,上面的代码里都加了安全判断。
  • 锯齿问题:因为是像素绘制,圆形边缘必然会有锯齿,中点算法已经是能做到的最平滑的整数像素方案了,如果想要更平滑的效果,可以尝试抗锯齿(计算像素覆盖率混合颜色),但对于大多数2D像素游戏来说可能没必要。
  • 颜色格式:注意你的color变量要符合像素数组的格式,比如常见的ARGB(32位),比如0xFF00FF是不透明的紫色,0x80FF00FF是半透明的紫色。

内容的提问来源于stack exchange,提问作者TinMan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 08:00:20