=begin
Blockade.rb | Port of HUMP.timer to Ruby, aimed at RGSS
===
Early Beta v0.1.0
============================================================
It is essentially my attempt to abstract away fiber for async code.
This script is licensed under the APACHE-2.0 license, see
http://www.apache.org/licenses/LICENSE-2.0.html for more details.
Heavily inspired by HUMP.timer for Love2d:
http://hump.readthedocs.io/en/latest/timer.html
=end
=begin
This script uses the easying methods ported to Ruby by Damián Silvani,
see https://github.com/munshkr/easing-ruby for more details
=end
=begin
Copyright (c) 2013 Damián Silvani
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=end
module Easing
extend self
def linear_tween(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
c * t / d + b
end
def ease_in_quad(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*(t/=d)*t + b;
end
def ease_out_quad(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c *(t/=d)*(t-2) + b;
end
def ease_in_out_quad(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
t /= d / 2
return c / 2*t*t + b if (t < 1)
t -= 1
return -c/2 * (t*(t-2) - 1) + b
end
def ease_in_cubic(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*(t/=d)*t*t + b
end
def ease_out_cubic(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*((t=t/d-1)*t*t + 1) + b
end
def ease_in_out_cubic(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c/2*t*t*t + b if ((t/=d/2) < 1)
return c/2*((t-=2)*t*t + 2) + b
end
def ease_in_quart(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*(t/=d)*t*t*t + b
end
def ease_out_quart(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c * ((t=t/d-1)*t*t*t - 1) + b
end
def ease_in_out_quart(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c/2*t*t*t*t + b if ((t/=d/2) < 1)
return -c/2 * ((t-=2)*t*t*t - 2) + b
end
def ease_in_quint(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*(t/=d)*t*t*t*t + b
end
def ease_out_quint(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c*((t=t/d-1)*t*t*t*t + 1) + b
end
def ease_in_out_quint(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c/2*t*t*t*t*t + b if ((t/=d/2) < 1)
return c/2*((t-=2)*t*t*t*t + 2) + b
end
def ease_in_sine(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c * Math.cos(t/d * (Math::PI/2)) + c + b
end
def ease_out_sine(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c * Math.sin(t/d * (Math::PI/2)) + b
end
def ease_in_out_sine(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c/2 * (Math.cos(Math::PI*t/d) - 1) + b
end
def ease_in_expo(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return (t==0) ? b : c * (2 ** (10 * (t/d - 1))) + b
end
def ease_out_expo(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return (t==d) ? b+c : c * (-2**(-10 * t/d) + 1) + b
end
def ease_in_out_expo(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return b if t == 0
return b + c if t == d
return (c/2) * 2**(10 * (t-1)) + b if ((t /= d/2) < 1)
return (c/2) * (-2**(-10 * t-=1) + 2) + b
end
def ease_in_circ(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b
end
def ease_out_circ(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return c * Math.sqrt(1 - (t=t/d-1)*t) + b
end
def ease_in_out_circ(t, b, c, d)
t = t.to_f; b = b.to_f; c = c.to_f; d = d.to_f
return -c/2 * (Math.sqrt(1 - t*t) - 1) + b if ((t/=d/2) < 1)
return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b
end
end
class Blockade
class BFiber < Fiber
attr_reader :alive
attr_accessor :timer
def initialize *args
super *args
@alive = true
@timer = 0
end
def resume *args
begin
super *args
@timer += 1
rescue FiberError => e
@alive = false
end
end
def alive?
@alive
end
end
def initialize
@pool = []
@timer = 0
end
def fmap_tween meth, start, final, t, d
delta = start.zip(final).map{|e| e[1] - e[0]}
start.zip(delta).map do |tup|
Easing.send(meth, t, *tup, d)
end
end
def tween meth, obj, attrs, final, d
initial = attrs.map{|sym| obj.send(sym)}
schedule do |f|
loop do
timer = f.timer
ans = fmap_tween meth, initial, final, timer, d
ans.each_with_index do |rhs, i|
obj.send("#{attrs[i]}=", rhs)
end
yield f, obj if block_given?
if timer < d
wait
else
break
end
end
end
end
def schedule &b
b.binding.eval <<-HERE
def wait t=1
t.times {Fiber.yield}
end
HERE
ele = BFiber.new(&b)
@pool << ele
return ele.hash
end
def after time, &b
schedule do |tick|
wait(time)
tick.timer -= time
b[tick]
end
end
def every time, &b
schedule do |tick|
loop do
if tick.timer % time == 0
instance_exec tick, &b
end
Fiber.yield
end
end
end
def during range, &b
schedule do |tick|
loop do
if range.include?(tick.timer)
instance_exec tick, &b
end
Fiber.yield
end
end
end
def cancel k
@pool.delete_if{|it| it.hash == k}
end
def clear
@pool = []
end
def update
@pool.each do |f|
f.resume(f)
end
@pool.keep_if{|v| v.alive?}
@timer += 1
end
end