We fold code like origami.

Aesthetic, elegant solutions to all your software needs.

Moon

2D game engine for developing games with elegance.
Simple, fast & and extensive.

Write your game in Ruby

Creating games should be a simple and fun process. We offer an elegant ruby interface bundled with all of the core modules and interfaces to graphics, sound and video and you will ever need in order to craft your next masterpiece, in a fast and efficient way.

Learn more

Simple to learn

The core library is deliberately kept tiny and concise to make it easy to get started.

Learn more

Batteries included

We include a standard library that covers just about anything you could think of. Collision checking? Check. Spacial partitioning, scene graphs? Scene management? Entity system? Animation tweening, transitions, and so on? All of these (and more) are available in the extra repository.

Learn more
# Common transducers

def mapping(&transform)
  return -> (reduce) {
    return -> (result, input) {
      return reduce.(result, transform.(input))
    }
  }
end

def filtering(&predicate)
  return -> (reduce) {
    return -> (result, input) {
      predicate.(input) ?
        reduce.(result, input) :
        result
    }
  }
end

## Transduce! The "traditional" example

def transduce(xform, f, init, coll)
  coll.reduce(init, &xform.(f))
end

# To be moon stdlib

# Generates a filter step function using the filtering transducer, matching the
# pressed key.

Event = Struct.new(:type, :key, :x, :y)

def key(sym)
  filtering { |event| event.key == sym }
end

fn = -> (e) {
  puts "Got enter key! #{e}"
}

# * is our compose operator, where fn compose(f, g) = g(f(x))
# note that we inverse the order of operators (so it works like piping)
def compose(*args)
  _compose = -> f, g { -> x { f[g[x]] } }
  args.reduce(&_compose)
end

@listeners = Hash.new { |h, k| h[k] = [] }

def on(types, reducer = nil, &block)
  reducer ||= -> x { x } # identity
  types = Array(types).each do |type|
    @listeners[type] << [block, reducer]
  end
end

def trigger(event)
  @listeners[event.type].each do |block, reducer|
    # we can do buffering in the future
    transduce(reducer, :<<.to_proc, [], [event]).each do |e|
      block.call(e)
    end
  end
end

on([:press], key(:enter), &fn)

trigger(Event.new(:press, :not))
trigger(Event.new(:press, :enter))

# Complex gate filter

def gate(opener, closer)
  open = false
  return -> (e) {
    open = true if e.type == opener
    open = false if e.type == closer
    return open
  }
end

def type(sym)
  filtering {|event| event.type == sym }
end

ch = compose(
  # Only allow through when mouse has been down
  filtering(&gate(:mousedown, :mouseup)),
  # Filter by e.type === 'mousemove'
  type(:mousemove),
  # e -> [type, x, y]
  mapping { |e| [e.type, e.x, e.y] }
)


# Listen for relevant events
on [:mousemove, :mouseup, :mousedown], ch do |e|
  puts "Got a dragging event! #{e}"
  #trigger :dragging, self # generates a new event
end

trigger(Event.new(:mousemove, nil, 10, 20))
trigger(Event.new(:mousedown))
trigger(Event.new(:mousemove, nil, 12, 20))
trigger(Event.new(:mousemove, nil, 14, 20))
trigger(Event.new(:mouseup))
trigger(Event.new(:mousemove, nil, 16, 20))
trigger(Event.new(:mousemove, nil, 18, 20))