DEV Community

Justin
Justin

Posted on

DragonRuby: Rotating Rectangles

In DragonRuby, one of the drawing primitives is a "solid" - a rectangle, actually.

Rectangles are defined by the origin point of the bottom-right corner (x, y) and a size in height/width (h, w).

For example, this code paints a black rectangle in roughly the middle of the screen:

def tick(args)
  args.outputs.solids << {
    x: 490,
    y: 310,
    w: 300,
    h: 100,
  }
end
Enter fullscreen mode Exit fullscreen mode

DragonRuby window with a black rectangle in the middle

Rectangles are simple and (presumably) fast. But what if we want to put the rectangle at an angle? Or spin it around?

For sprites, there is an angle attribute. Will that work for rectangles? Unfortunately, no.

We could make a rectangle image and use it in a sprite, but that seems wasteful. I don't know if resizing a sprite is very resource-intensive, but I'm sure it takes more cycles than changing the size of a simple rectangle.

Fortunately, there is a middle way.

From the 2.26 release notes (and yes, this is the only place I could find this functionality formally documented, though it is used in examples):

** [API] Pre-defined ~:pixel~ render target now available.
Before ~(boot|tick)~ are invoked, a white solid with a size of 1280x1280
is added as a render target. You can use this predefined render target to
create solids and get ~args.outputs.sprites~ related capabilities.

In other words, it is possible to create an equivalent rectangle to the above like this:

def tick(args)
  args.outputs.sprites << {
    x: 490,
    y: 310,
    w: 300,
    h: 100,
    r: 0,
    g: 0,
    b: 0,
    path: :pixel,
  }
end
Enter fullscreen mode Exit fullscreen mode

The key piece is path: :pixel and creating a sprite instead of a solid.

As is mentioned above, the :pixel render target is white, so to get exactly the same results as before the color is set to black. If no rgb values were specified, it would be a white rectangle.

Now, can we rotate this rectangle?

Sure!

def tick(args)
  args.outputs.sprites << {
    x: 490,
    y: 310,
    w: 300,
    h: 100,
    r: 0,
    g: 0,
    b: 0,
    path: :pixel,
    angle: 45,
  }
end
Enter fullscreen mode Exit fullscreen mode

Image description

(By the way, angles in DragonRuby are in degrees.)

Spinning Round and Round

Here is an example of spinning the rectangle around:

def tick(args)
    args.outputs.sprites << {
      x: 490,
      y: 310,
      w: 300,
      h: 100,
      r: 0,
      g: 0,
      b: 0,
      path: :pixel,
      angle: args.tick_count % 360,
    }
end
Enter fullscreen mode Exit fullscreen mode

Black rectangle spinning around its center

This is great and all, but what if you'd rather have it spin around like this?

Black rectangle spinning around a corner

With some sleuthing, you might find the angle_anchor_x and angle_anchor_y attributes. And you would be forgiven for thinking those refer to points on the coordinate grid. But they do not!

Instead, angle_anchor_x and angle_anchor_y are percentages relative to the sprite itself.

In other words, if both anchors are set to 0.5 (the default), the center of the rotation will be the middle of the sprite (half of the width and half of the height).

0,0 is the bottom-left corner of the sprite, as shown above:

def tick(args)
    args.outputs.sprites << {
      x: 490,
      y: 310,
      w: 300,
      h: 100,
      r: 0,
      g: 0,
      b: 0,
      path: :pixel,
      angle: args.tick_count % 360,
      angle_anchor_x: 0,
      angle_anchor_y: 0,
    }
end
Enter fullscreen mode Exit fullscreen mode

Anchor values between 0 and 1 will be inside the sprite. But values greater than 1 or less than 0 will be outside the sprite.

Here is a little reference:

Angle anchors on a black rectangle

Happy rectangle rotating!

Five colorful rotating rectangles

Top comments (0)