I've seen some code to draw filled circles, but not for empty or hollow circles. So I ended up writing a little script to do it for me. The script can create a circle of any size or color and of different thicknesses. The script can also make arcs or partial circles. The circles, unfortunately, are not perfect, although they are pretty close. Sometimes a small pixel-sized gap can form (which you can actually see in the first screen shot). There's also some code in the script that can be used to create gradients within the circle. That code is based on previous work by Ryex. I've made a minor update to the script, it now uses set_pixel instead of fill_rect, as recommended by Modern Algebra.
#==============================================================================
# Extends the Bitmap class with circle drawing functions
# v 1.1 (May 23, 2010) by scanime@gmail.com
#==============================================================================
class Bitmap
#--------------------------------------------------------------------------
# * Draws a hollow circle (or pretty close to it)
# x = x of center coordinate
# y = y of center coordinate
# r = radius of the circle (distance from center)
# c = color of the circle -- ie, Color.new(255, 0, 0)
# thickness = the thickness of the line for the circle
# Defaults to 5.
# percent = to create partial circles, set the size as a percent
# 0.5 makes a half circle, etc.
# Defaults to 1 (a full circle)
# start = the angle of the start of the circle, measured in radians. Useful
# to rotate partial circles.
# Defaults to pi (starts at the top)
#--------------------------------------------------------------------------
def draw_circle(x, y, r, c, thickness = 5, percent = 1, start = Math::PI)
size = Math::PI * 2 * percent
for i in 0...thickness
radians = 0
while radians >= -size
set_pixel(x + r * Math.sin(radians + start), y + r * Math.cos(radians + start), c)
radians = radians - 0.017453293
end
r = r - 1
end
end
#--------------------------------------------------------------------------
# * Draws circular gradients for HP, SP, or whatever
# Based on Ryex's code for gradient bars
#--------------------------------------------------------------------------
def draw_circle_gradient(x, y, radius, c, thickness = 5, percent = 1)
gray = Color.new(100, 100, 100)
white = Color.new(255, 255, 255)
draw_circle(x, y, radius, Color.new(0, 0, 0), thickness)
for i in 0...(thickness - 1)
gr = gray.red * i / (thickness - 1)
gg = gray.green * i / (thickness - 1)
gb = gray.blue * i / (thickness - 1)
draw_circle(x, y, radius - i - 1, Color.new(gr-255, gg-255, gb-255), 1)
end
for i in 0...(thickness / 2)
r = c.red + (white.red - c.red) * i / (thickness / 2 - 1)
g = c.green + (white.green - c.green) * i / (thickness / 2 - 1)
b = c.blue + (white.blue - c.blue) * i / (thickness / 2 - 1)
draw_circle(x, y, radius - thickness / 2 + i, Color.new(r, g, b), 1, percent)
end
for i in 0...(thickness / 2 - 1)
r = c.red * i / (thickness / 2)
g = c.green * i / (thickness / 2)
b = c.blue * i / (thickness / 2)
draw_circle(x, y, radius - thickness / 2 - (thickness / 2 - 1 - i), Color.new(r, g, b), 1, percent)
end
end
end
And I've also written an add-on for the KGC 2D Drawing functions that creates gradient-filled circles. The circles made this way are definitely cleaner looking and don't have the missing pixels that show up sometimes in the circles my script above draws. You can find the KGC 2D Drawing script at
http://ytomy.sakura.ne.jp/tkool/rpgtech/tech_xp/draw_function/2d_drawing_xp.html. It adds a large collection of tools for drawing 2D shapes. Big props to Mr Wiggles for pointing this collection of functions out to me.
I also added a variant to draw_arc that draws arcs clockwise rather than counter-clockwise.
#==============================================================================
# The following extends the Bitmap class modifications made by
# KGC, available at:
# http://ytomy.sakura.ne.jp/tkool/rpgtech/tech_xp/draw_function/2d_drawing_xp.html.
#
# The functions offer a variety of drawing tools, but this script
# adds gradient filled arcs and circles. To use, place this script below
# the script available in the link above.
#
# v 1.0 (May 23, 2010) by scanime@gmail.com
#==============================================================================
class Bitmap
# Modified version of draw_arc that draws arcs clockwise rather than
# counter-clockwise
def draw_arc_clockwise(*args)
# ????
cx, cy, r, st_ang, end_ang, color, size = _arc_args(args)
return unless cx
# ???????
x = r * Math.cos(Math::PI * st_ang / 180.0)
y = r * -Math.sin(Math::PI * st_ang / 180.0)
dfx = dfy = 0
pr = Integer([100, r].max ** 1.6)
a = 6.3 / pr
pr = pr * (end_ang - st_ang) / 360
# ?????
pr.times { |i|
x, y = x - dfx, y + dfy
dx, dy = x + cx, y + cy
if size == 1
self.set_pixel(dx, dy, color)
else
self.fill_rect(dx, dy, size, size, color)
end
dfx, dfy = a * y, a * x
}
end
#--------------------------------------------------------------------------
# * Draws circular gradients for HP, SP, or whatever
# Based on Ryex's code for gradient bars
# x = x of center coordinate
# y = y of center coordinate
# r = radius of the circle (distance from center)
# c = color of the circle -- ie, Color.new(255, 0, 0)
# thickness = the thickness of the line for the circle
# Defaults to 5.
# percent = to create partial circles, set the size as a percent
# 0.5 makes a half circle, etc.
# Defaults to 1 (a full circle)
# start = the angle of the start of the circle, measured in radians. Useful
# to rotate partial circles.
# Defaults to pi / 2 (starts at the top)
#--------------------------------------------------------------------------
def draw_circle_gradient(x, y, radius, c, t = 5, p = 1, start = Math::PI / 2)
# convert angle from radians to degrees
start_angle = (start * 180 / Math::PI).to_i
end_angle = (360 * p + start_angle).to_i
gray = Color.new(100, 100, 100)
white = Color.new(255, 255, 255)
for i in 0...(t - 1)
gr = gray.red * (t - i) / (t - 1)
gg = gray.green * (t - i) / (t - 1)
gb = gray.blue * (t - i) / (t - 1)
draw_circle(x, y, radius - i - 1, Color.new(gr-255, gg-255, gb-255))
end
for i in 0...(t / 2)
r = c.red + (white.red - c.red) * i / (t / 2 - 1)
g = c.green + (white.green - c.green) * i / (t / 2 - 1)
b = c.blue + (white.blue - c.blue) * i / (t / 2 - 1)
draw_arc_clockwise(x, y, radius - t / 2 + i, start_angle, end_angle, Color.new(r, g, b))
end
for i in 0...(t / 2 - 1)
r = c.red * i / (t / 2)
g = c.green * i / (t / 2)
b = c.blue * i / (t / 2)
draw_arc_clockwise(x, y, radius - t / 2 - (t / 2 - 1 - i), start_angle, end_angle, Color.new(r, g, b))
end
end
end
A basic example of the script:
And something a little more practical looking: