• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!

Drawing Pixel Perfect Circles

Bearious

Member
I assume there is a simple answer here, but can't find any help. Can someone please tell me why the circle in image A looks like its drawn as a vector, and the circle in image B looks like a pixel perfect circle. I just want a pixel perfect circle.

Both circles are drawn using draw_circle(x, y, 40, false);
 

Attachments

TsukaYuriko

☄️
Forum Staff
Moderator
The first one is drawn at a much larger resolution (which is not necessarily the same as its size, due to scaling). Circles are internally drawn as a triangle strip, and this may be more or less visible depending on the circle's size. You can control the vertices (and therefore smoothness) of drawn circles via draw_set_circle_precision.
 

Bearious

Member
The first one is drawn at a much larger resolution (which is not necessarily the same as its size, due to scaling). Circles are internally drawn as a triangle strip, and this may be more or less visible depending on the circle's size. You can control the vertices (and therefore smoothness) of drawn circles via draw_set_circle_precision.
Yea I tried draw_set_circle_precision, but I'm not looking to control the vertices. I kinda figured it had to do with the camera, but I am still confused how this is the case when they are both being drawn with draw_circle(x, y, 40, false). I would assume regardless of the viewport/camera resolution they would be drawn the exact same.
 

TsukaYuriko

☄️
Forum Staff
Moderator
B looks like the game handles scaling by drawing stuff at native resolution to a surface (of said native resolution). This surface was then drawn to the screen, upscaled by an even factor, to be as big as the viewport size.

A looks like you set the viewport of the room to a multiple of the camera size. This then resized the application surface and therefore affected how the shape functions operate. Alternatively, something else changed the viewport size or application surface's size to match the window size.
 
Ive had problems with using some art drawing programs that drew circles incorrectly and so I had import circles that I drew on a old drawing program into the art program that I was using ... however, when I change the resolution size I get this strange Moiré effect at different resolution sizes that have bugged me. I discovered that there were two types of ways of drawing circles in the art programs that I used. One type uses a frame to define the circle using a frame ( this is what MS Paint uses ), the other way which I prefer uses the pixel point as the center and the size is determined how far you pull the mouse pointer away from that point to make it big or small ( this is used in Deluxe Paint IV, III, IIe ( IBM only ) by Electronic Arts ). So Here are two samples of circles that I had to import because one of art programs that I used did not draw circles symmetrically. Feel free to use the pictures , they are both pixel based.

This one has a Moiré effect that I dont understand the cause of....

dpcircs3.gif

This one uses smaller circles that one of my paint programs could not do correctly....

dpcircs2.gif

Feel free to use these images, you may have to tailor the bigger one for a specific circle size by using flood fill and erase in the same color of the circles that are drawn ( white I assume ) to get the specific circle size you want. I experimented with the large circles to create images such as these where there is an intersection differences at 90 and 45 degree angles.

moray6_1.gif

Have fun ...
 
R

robproctor83

Guest
To get pixelated shapes from drawing shapes you have to draw the shape really small at it's base pixel size onto a surface and then scale the surface up to the size you want. However at that point there is no reason not to import the circle as a Sprite as long as it's just a static circle. Anytime you draw shapes in game they take on the full resolution of the camera. So if your base resolution is 480x270 and you upscale to fullscreen then the shape you draw will end up being high resolution and not pixelated. It makes using in game draw functions a pain with pixel art because to get the pixel style on drawn shapes it requires drawing to a surface and scaling it back up. Other than that drawing shapes is also very taxing for some reason so really you would not want to draw a bunch of shapes each step anyways.
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
Here's a really old script, I think using Bresenham's algorithm
Code:
/// draw_circle_px(x, y, r, outline)
var cx = argument0;
var cy = argument1;
var dx = argument2;
var dy = 0;
var re = 1 - dx;
if (argument3) {
    for (var step = 0; step < 2; step++) {
        if (!step || (step && dx == dy)) {
            draw_rectangle_px(cx - dx, cy - dy, 1, 1, 0)
            draw_rectangle_px(cx + dy, cy - dx, 1, 1, 0)
            draw_rectangle_px(cx + dx, cy + dy, 1, 1, 0)
            draw_rectangle_px(cx - dy, cy + dx, 1, 1, 0)
        }
        if (!step) {
            dy++
            if (re >= 0) {
                re += 2 * (dy - --dx) + 1
            } else re += 2 * dy + 1
            var vx = dx, vy0 = dy, vy1 = dy;
            while (dx > dy) {
                vy1 = dy;
                dy++
                var draw = false;
                if (re >= 0) {
                    draw = true
                    re += 2 * (dy - --dx) + 1
                } else re += 2 * dy + 1
                if (draw || dx <= dy) {
                    draw_line_px(cx - vx, cy - vy0, cx - vx, cy - vy1)
                    draw_line_px(cx - vy0, cy - vx, cx - vy1, cy - vx)
                    draw_line_px(cx + vx, cy - vy0, cx + vx, cy - vy1)
                    draw_line_px(cx + vy0, cy - vx, cx + vy1, cy - vx)
                    draw_line_px(cx - vx, cy + vy0, cx - vx, cy + vy1)
                    draw_line_px(cx - vy0, cy + vx, cx - vy1, cy + vx)
                    draw_line_px(cx + vx, cy + vy0, cx + vx, cy + vy1)
                    draw_line_px(cx + vy0, cy + vx, cx + vy1, cy + vx)
                    vx = dx
                    vy0 = dy
                }
            }
        }
    }
} else { // filled
    dy++
    if (re >= 0) {
        re += 2 * (dy - --dx) + 1
    } else re += 2 * dy + 1
    var vx = dx, vy0 = dy, vy1 = dy;
    while (dx > dy) {
        vy1 = dy;
        dy++
        if (re >= 0) {
            re += 2 * (dy - --dx) + 1
            //
            draw_line_px(cx - vx, cy - vy1, cx - vx, cy + vy1) // l
            draw_line_px(cx + vx, cy - vy1, cx + vx, cy + vy1) // r
            draw_line_px(cx - vy1, cy - vx, cx + vy1, cy - vx) // t
            draw_line_px(cx - vy1, cy + vx, cx + vy1, cy + vx) // b
            vx = dx
            vy0 = dy
        } else re += 2 * dy + 1
    } // while (dx > dy)
    draw_rectangle_px(cx - vx, cy - vx, vx * 2 + 1, vx * 2 + 1, false)
}
draw_line_px:
Code:
/// draw_line_px(x1, y1, x2, y2, ?headless)
var x1 = argument[0];
var y1 = argument[1];
var x2 = argument[2];
var y2 = argument[3];
var lp;
if (argument_count > 4) lp = !argument[4] else lp = true
var ax, ay, dx, dy;
ax = abs(x2 - x1)
ay = abs(y2 - y1)
//
if (ax == 0) {
    if (ay == 0) { // single pixel
        if (lp) draw_rectangle_px(x1, y1, 1, 1, 0)
        return 1
    }
    // vertical:
    ay += lp
    if (y2 > y1) {
        draw_rectangle_px(x1, y1, 1, ay, 0)
    } else {
        draw_rectangle_px(x1, y1 - ay + 1, 1, ay, 0)
    }
    return 1
}
if (ay == 0) { // horizontal
    ax += lp
    if (x2 > x1) {
        draw_rectangle_px(x1, y1, ax, 1, 0)
    } else {
        draw_rectangle_px(x1 - ax + 1, y1, ax, 1, 0)
    }
    return 1
}
var ds, dc = 0.5;
if (x2 > x1) dx = 1 else dx = -1
if (y2 > y1) dy = 1 else dy = -1
if (ax > ay) { // left/right
    ds = ay / ax
    repeat (ax) {
        draw_rectangle_px(x1, y1, 1, 1, 0)
        x1 += dx
        dc += ds
        if (dc >= 1) {
            y1 += dy
            dc -= 1
        }
    }
} else { // up/down
    ds = ax / ay
    repeat (ay) {
        draw_rectangle_px(x1, y1, 1, 1, 0)
        y1 += dy
        dc += ds
        if (dc >= 1) {
            x1 += dx
            dc -= 1
        }
    }
}
if (lp) draw_rectangle_px(x1, y1, 1, 1, 0)
and then draw_rectangle_px is expected to draw a rectangle by stretching a sprite
 

Bearious

Member
Thank you everyone for all the responses. The issue does seem to be the way I am scaling the game up. I appreciate the suggestions and will look into drawing the circle on it's own surface :)
 
Top