The RPG Maker Resource Kit

RMRK RPG Maker Creation => XP => XP Scripts Database => Topic started by: scanime on May 20, 2010, 01:28:09 PM

Title: [XP] Drawing Circles
Post by: scanime on May 20, 2010, 01:28:09 PM
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.

Code: [Select]
#==============================================================================
#  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 (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.
Code: [Select]
#==============================================================================
# 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:

Spoiler for Screenshot:
(https://rmrk.net/proxy.php?request=http%3A%2F%2Fi835.photobucket.com%2Falbums%2Fzz277%2Fscanime%2Fcircle_sample.jpg&hash=f69999301643603c4c5d8174ac4c832dd3466ffe)

And something a little more practical looking:

Spoiler for Screenshot:
(https://rmrk.net/proxy.php?request=http%3A%2F%2Fi835.photobucket.com%2Falbums%2Fzz277%2Fscanime%2Fcircle_hud.jpg&hash=2762b5826812192fc613cba32b90353c744ec41a)
Title: Re: [XP] Drawing Circles
Post by: cozziekuns on May 21, 2010, 01:19:31 AM
Looks cute.

Too bad it's not for VX, or I might have stolen this :P
Title: Re: [XP] Drawing Circles
Post by: modern algebra on May 21, 2010, 02:28:05 AM
I don't see anything that would make this not work in VX. I could just be missing something though.

Anyway, nice job scanime. Since you are only filling one pixel at a time though, I would recommend the method:

Code: [Select]
set_pixel (x, y, colour)

It's a little more direct.
Title: Re: [XP] Drawing Circles
Post by: cozziekuns on May 21, 2010, 02:46:06 AM
Oh never mind, it did work. I was sure that VX's bitmap method would screw it up, but I guess I was wrong. Great job Scan.
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 21, 2010, 09:28:57 AM
This is cool that you made this, im sure that this took a lot of work.  Will you be adding more features to it?

isn't there a compilation script that allows you to draw all kinds of objects in 2D in the base class?
Spoiler for:
Plane Drawing - KGC_Drawing 2D
http://ytomy.sakura.ne.jp/tkool/rpgtech/tech_xp/draw_function/2d_drawing_xp.html
Title: Re: [XP] Drawing Circles
Post by: scanime on May 21, 2010, 01:16:52 PM
Thanks all!  I'll definitely be updating the script with set_pixel (thanks, MA!) and I'm planning on adding a few other functions.  I'll at least be adding a way to draw an arc from one point on the circle to another by using radians instead of using a percentage.  The percentage just made it easier for making circle-shaped gradient bars.

The KGC_Drawing 2D tools look like they have a lot of features... I'll definitely take a look at them.  I especially like the way the functions can handle multiple arguments... I never thought of that with Ruby before!
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 22, 2010, 01:09:02 AM
The KGC_Drawing 2D tools look like they have a lot of features... I'll definitely take a look at them.  I especially like the way the functions can handle multiple arguments... I never thought of that with Ruby before!

I have the script translated into English already i can send it to you if you'd like.
Title: Re: [XP] Drawing Circles
Post by: scanime on May 24, 2010, 02:29:55 PM
Okay, I've made a minor update to my script, and added a new script that works with the KGC Drawing tools.  I've updated my original post with the new code.

I have the script translated into English already i can send it to you if you'd like.

I wish I had checked the forums over the weekend!  That would be a great help, thanks.
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 24, 2010, 04:29:01 PM
It's attached, cool update.

[edit]
I'm getting an error when i use the "draw_circle_gradient", wrong number of arguments 4 of 6.

i have the command set up like so:
Code: [Select]
min = 5
max = 10
percent = min / max.to_f if max != 0
#                   draw_circle_gradient(x, y, radius, c, t = 5, p = 1, start = Math::PI / 2)
self.contents.draw_circle_gradient(300, 300, 80, Color.new(255, 0, 0), 10, percent)

i have the max and min set to fixnum cause i was testing it.
Title: Re: [XP] Drawing Circles
Post by: scanime on May 24, 2010, 06:28:45 PM
I'm getting an error when i use the "draw_circle_gradient", wrong number of arguments 4 of 6.

i have the command set up like so:
Code: [Select]
min = 5
max = 10
percent = min / max.to_f if max != 0
#                   draw_circle_gradient(x, y, radius, c, t = 5, p = 1, start = Math::PI / 2)
self.contents.draw_circle_gradient(300, 300, 80, Color.new(255, 0, 0), 10, percent)

i have the max and min set to fixnum cause i was testing it.

Thanks for the translation!  I tried your code, and it seems to work fine on my end.  I changed the KGC drawing script to the one you included, just in case. The error sounds like it's not passing all of the arguments when it calls the function for the arc. Does it say which line number is throwing the error?  (I'm guessing it's line 479.)  Can you add the line "p args" there so that I can see which arguments it isn't passing along?
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 24, 2010, 06:37:35 PM
yea hold on a sec.

yea it is line 479
(https://rmrk.net/proxy.php?request=http%3A%2F%2Fscreensnapr.com%2Fu%2Fy2vw5g.png&hash=803711f29ec65c0a7bee08d314cd3a1bfb4fc6c2)
Title: Re: [XP] Drawing Circles
Post by: scanime on May 24, 2010, 07:20:21 PM
Huh, it's breaking when it draws just the circle, then, and not the arc like I thought.  They're basically the same thing, but the circle automatically goes from 0 to 360 degrees.  So let's try changing line 67 of my code from this:

draw_circle(x, y, radius - i - 1, Color.new(gr-255, gg-255, gb-255))

To this:

draw_arc(x, y, radius - i - 1, 0, 360, Color.new(gr-255, gg-255, gb-255))

And see if that works.
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 25, 2010, 11:04:04 PM
yea it works but when i was using it it seemed to lag a lot. i was using it in my HUD, and i have a limit on the script so that it will only update when its time, (every 10 frames) i suppose i could put another limiter on the bar so that it will update less often or if the old value changed.

[edit]
did that, but still lags when the value changes any suggestions? (i have it update only when the actor's hp changes, but there is some noticeable lag when it does this.)
Title: Re: [XP] Drawing Circles
Post by: scanime on May 26, 2010, 02:21:45 PM
yea it works but when i was using it it seemed to lag a lot. i was using it in my HUD, and i have a limit on the script so that it will only update when its time, (every 10 frames) i suppose i could put another limiter on the bar so that it will update less often or if the old value changed.

[edit]
did that, but still lags when the value changes any suggestions? (i have it update only when the actor's hp changes, but there is some noticeable lag when it does this.)

Glad to know the fix worked!

How much lag are you seeing? If I have four gradient circles, the fps will drop to 25-35 if they are redrawn all at once.  Like you, I've got it set up on my HUD so that the circles are only redrawn when HP or SP changes.  That's using the KGC drawing methods.  Using my original stand-alone script, the framerate changes to 33-36, so it's a little bit faster, but the lag is still noticeable sometimes.  KGC draws better circles, but that requires more calls to set_pixel, which slows it down a bit more.  I don't know if there's a good way to speed up the process.  If a filled circle would work, it could be drawn faster, but the hollow circles require a lot of calls to set_pixel.
Title: Re: [XP] Drawing Circles
Post by: Mr_Wiggles on May 26, 2010, 09:37:10 PM
ah, well that makes sense. i bet it could be how i have it set up (81 diameter, 7 thickness) but its only one circle.

well im still working on my game and ATM it runs at 34 - 38 fps (i blame my pc), when the hp changes it will drop down to 21 - 26 fps.