RubySketch - A game engine based on the Processing API

Ask DeepWiki License Build Status Gem Version

⚠️ Notice

This repository is a read-only mirror of our monorepo. We do not accept pull requests or direct contributions here.

🔄 Where to Contribute?

All development happens in our xord/all monorepo, which contains all our main libraries. If you'd like to contribute, please submit your changes there.

For more details, check out our Contribution Guidelines.

Thanks for your support! 🙌

🚀 About

RubySketch is a 2D game engine for Ruby. It takes the Processing for CRuby sketch loop — setup / draw / mousePressed / ... — and layers a game-oriented vocabulary on top of it: Sprite, world-based 2D physics (via Box2D), Sound and MML (Music Macro Language) for audio, animation timers (animate, setInterval, setTimeout), and a small library of easing curves.

📋 Requirements

  • Ruby 3.0.0 or later
  • All the runtime requirements of Reflex (Rays, Rucy, Xot, plus the platform GUI backend — AppKit / UIKit / Win32 / SDL2 — and OpenGL)
  • The dependent gems are installed automatically: xot, rucy, beeps, rays, reflexion, processing

There is no native C/C++ extension in this gem; the heavy lifting is done by the underlying gems' extensions.

📦 Installation

Add this line to your Gemfile:

gem 'rubysketch'

Then install:

$ bundle install

Or install it directly:

$ gem install rubysketch

📚 What's Provided

require 'rubysketch' and using RubySketch make the whole Processing API (camelCase) plus the RubySketch additions available as top-level methods in your file. As with Processing, a window opens and the sketch runs automatically on file exit; you do not need an explicit start call.

using RubySketch(snake_case: true) adds snake_case aliases (create_sprite, set_interval, ...) alongside the camelCase originals.

On top of Processing, RubySketch adds:

Sprites — RubySketch::Sprite

createSprite returns a Sprite whose position, size, angle, velocity, image, offset, pivot, shape, draw block, and per-sprite mouse events you can drive directly.

Capability API
Position / size pos, x, y, z, left, top, right, bottom, center, size, width, height
Motion velocity, vx, vy, angle, fixAngle, pivot
Appearance image, offset (texture offset), draw block
Physics dynamic = true, static = true, restitution, density, friction, shape
Interaction mousePressed, mouseReleased, mouseMoved, mouseDragged, mouseClicked (per-sprite)
Lifecycle update { ... }, draw { ... }, show, hide, capture = true/false

Sprites can be sorted by z and drawn in bulk via the top-level sprite(*sprites) call.

2D physics

API Purpose
gravity(x, y) / gravity(vec) Set the gravity of the active world
Sprite#shape = Box2D fixture shape (rect, ellipse, polygon)

Sound

API Purpose
loadSound(path) Load a sample (WAV / AIFF / ...) into a RubySketch::Sound
Sound#play(gain:) Play; returns a handle exposing stop, playing?, seconds
Sound#stop Stop all instances

Music Macro Language (MML)

A tiny MML compiler (RubySketch::MML) that turns a string like "t120 l4 cdefgab>c" into a RubySketch::Sound.

  • MML.compile(str, streaming = false) — compile and return a Sound you can play later.
  • MML.play(str) — shortcut for compile(str).play.

Animation and timers

API Purpose
setTimeout(seconds) { ... } Run a block once after a delay; returns an id usable with clearTimer
setInterval(seconds, now:) { ... } Run a block every N seconds
clearTimer(id) Cancel a timer
animate(seconds, easing:) { ... } Drive a block from 0.0 to 1.0 over time, optionally with an easing curve
animateValue(seconds, from:, to:, easing:) { ... } Same but yields the interpolated value

Easing names: linear, sineIn / sineOut / sineInOut, quadIn / ... / cubicIn / ..., expoIn / expoOut / expoInOut, circIn / ..., backIn / backOut / backInOut, elasticIn / elasticOut / elasticInOut, bounceIn / bounceOut / bounceInOut. See lib/rubysketch/easings.rb.

MIDI input (forwarded from Reflex)

notePressed, noteReleased, controlChange blocks; noteNumber, noteFrequency, noteVelocity, controllerIndex, controllerValue accessors during a callback.

Miscellaneous

  • vibrate (mobile)
  • Vector, Image, WheelEvent — re-exported from Processing for convenience

💡 Usage

Hello, RubySketch

require 'rubysketch'
using RubySketch

draw do
  background 0
  textSize 30
  text 'hello, rubysketch!', 10, 100
end

Sprites and per-sprite input

require 'rubysketch'
using RubySketch

player = createSprite 200, 200, 40, 40
player.image = loadImage 'player.png'

player.update do
  player.x += 2 if keyIsDown(RIGHT)
  player.x -= 2 if keyIsDown(LEFT)
end

player.mouseClicked do
  player.z += 10              # bring forward on click
end

draw do
  background 30
  sprite player
end

2D physics

require 'rubysketch'
using RubySketch

noStroke
gravity 0, 1000              # pixels / s^2 downward

ground  = createSprite 0, height - 10, width, 10   # static by default
sprites = []

draw do
  background 100
  sprite ground, *sprites
end

mousePressed do
  sp             = createSprite mouseX + rand, mouseY + rand,
                                shape: Circle.new(0, 0, 20)
  sp.dynamic     = true
  sp.restitution = 0.5
  sprites << sp
end

Sound and MML

require 'rubysketch'
using RubySketch

bgm = loadSound 'bgm.wav'

setup do
  bgm.play(gain: 0.6)
end

# play an MML phrase on every click
mousePressed do
  RubySketch::MML.play 't140 l8 ccggaag4 ffeeddc4'
end

Animation with easing

require 'rubysketch'
using RubySketch

x = 0
animateValue(2.0, from: 0, to: width, easing: :elasticOut) {|v| x = v }

draw do
  background 0
  fill 1
  ellipse x, height / 2, 40, 40
end

See examples/ for hello.rb, sprite.rb, physics.rb, and toon.rb.

🛠️ Development

$ rake test    # run the test suite
$ rake doc     # generate YARD docs
$ rake         # default tasks

In the xord/all monorepo you can scope by module, e.g. rake rubysketch test.

📜 License

RubySketch is licensed under the MIT License. See the LICENSE file for details.