🚙️

基本的なイージング用計算式まとめ

2023/10/09に公開

等速

f = -> t { t }
(0..1).step(0.1) do |e|
  f[e].floor(1)  # => 0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0
end

加速

f = -> t { t**2 }
(0..1).step(0.1) do |e|
  f[e].floor(1)  # => 0.0, 0.0, 0.0, 0.0, 0.1, 0.2, 0.3, 0.4, 0.6, 0.8, 1.0
end

減速

f = -> t { -t**2 + 2 * t }
(0..1).step(0.1) do |e|
  f[e].floor(1)  # => 0.0, 0.1, 0.3, 0.5, 0.6, 0.7, 0.8, 0.9, 0.9, 0.9, 1.0
end

加速+減速

f = -> t { -2 * t**3 + 3 * t**2 }
(0..1).step(0.1) do |e|
  f[e].floor(1)  # => 0.0, 0.0, 0.1, 0.2, 0.3, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0
end

超速+減速 (計算量低め)

相手との差分の半分を自分に足していく方法で掛け算を使わないので非常に速い。

a = 0
b = 100
a += (b - a) >> 1  # => 50
a += (b - a) >> 1  # => 75
a += (b - a) >> 1  # => 87
a += (b - a) >> 1  # => 93
a += (b - a) >> 1  # => 96
a += (b - a) >> 1  # => 98
a += (b - a) >> 1  # => 99
a += (b - a) >> 1  # => 99
a += (b - a) >> 1  # => 99
a += (b - a) >> 1  # => 99

ただし、いくら足しても目的地に着かないため、一定の距離まで近づいたら移動し終わったことにしないといけない。

if (b - a).abs < 5
  a = b  # => 100
end
コード
class App < Base
  def initialize
    super

    @counter = 0
  end

  def button_down(id)
    super

    if id == Gosu::KB_Z
      @counter = 0
    end
  end

  def draw
    super

    duration = 60.0 * 2

    if @counter >= duration + 60 * 0.5
      @counter = 60 * -0.5
    end

    t = @counter.fdiv(duration).clamp(0, 1)

    list = [
      { name: "linear",   f: -> t { t                    }, },
      { name: "ease-in",  f: -> t { t**2                 }, },
      { name: "ease-out", f: -> t { -t**2 + 2 * t        }, },
      { name: "ease",     f: -> t { -2 * t**3 + 3 * t**2 }, },
    ]
    radius = window_wh.y / list.count * 0.5
    rr = V[radius, radius]
    list.each.with_index do |e, i|
      y = i * 1.0 / list.count
      a = window_wh * V[0.0, y] + rr
      b = window_wh * V[1.0, y] - V[radius * 2, 0] + rr
      point_draw(a.lerp(b, e[:f][t]), radius: radius * 0.8)
    end

    @counter += 1
  end

  def window_size_default
    V[800, 320]
  end

  show
end

参照

Discussion