Eaglev0.1.0

2D physics

Rigid bodies, stacking, ramps, sensors and additive particle bursts.

Click to spawn bodies

Source: examples/physics/main.cr

examples/physics/main.cr

require "../../src/eagle"
include Eagle

# Physics + particles playground. Click to spawn boxes/balls; watch them pile up.
class Playground < App
  @spawned = 0
  @fx = Particles2D.new(amount: 0, position: v2(400, 300))

  def load
    root = SceneTree.root
    root.add(StaticBody2D.new(position: v2(400, 580)).box(760, 40).tap(&.debug = true))
    root.add(StaticBody2D.new(position: v2(20, 300)).box(40, 600).tap(&.debug = true))
    root.add(StaticBody2D.new(position: v2(780, 300)).box(40, 600).tap(&.debug = true))
    ramp = StaticBody2D.new(position: v2(250, 420))
    ramp.rotation = 0.3
    ramp.box(300, 20)
    ramp.debug = true
    root.add(ramp)
    30.times { |i| spawn(v2(150 + (i % 10) * 50, 50 + (i // 10) * 60)) }
    @fx.lifetime = 0.8
    @fx.speed = 100..250
    @fx.spread = Math::PI
    @fx.gravity = v2(0, 400)
    @fx.scale_start = 1.5
    @fx.scale_end = 0.2
    @fx.color_over_life = [Color::YELLOW, Color::ORANGE, Color::RED.with_alpha(0)]
    @fx.blend = GPU::BlendMode::Additive
    root.add(@fx)
    Timer.new(0.7) { @fx.position = v2(rand(200..600), rand(100..300)); @fx.emit(60) }.start.tap { |t| root.add(t) }
  end

  def spawn(at : Vec2)
    b = RigidBody2D.new(position: at)
    if (@spawned += 1).odd?
      b.circle(rand(10..20))
    else
      s = rand(18..36)
      b.box(s, s)
    end
    b.restitution = 0.3
    b.rotation = (rand * 3).to_f32
    b.debug = true
    b.modulate = Color.hsv(@spawned * 25, 0.7, 1)
    SceneTree.root.add(b)
  end

  def input(e : Event)
    if e.is_a?(MouseButtonEvent) && e.pressed?
      spawn(e.position)
    end
  end

  def draw(g : Graphics)
    g.print("click to spawn  bodies #{Physics2D.world.bodies.size}  fps #{Clock.fps.round}  particles #{@fx.alive_count}", 10, 10, Color::WHITE)
  end
end

Eagle.run(Playground, title: "Eagle physics", width: 800, height: 600)