LoginSignup
1
0

More than 1 year has passed since last update.

【Playdate】Playdate用軽量版Box2DのPlaybox2dを見てみる

Posted at

PlaydateはLuaの他にC言語での開発が可能です。
C言語は主にパフォーマンスが必要な場合に利用するのですが、今回紹介する物理演算エンジンPlaybox2Dはこれを利用しています。

Playbox2D

Box2D-Liteをベースにしており、矩形リジッドボディやaddForce、摩擦、ジョイントなど制限されたBox2Dとなります。

サンプルを見ながら確認してみます。

main.luaのsetup関数でplaybox2dの設定を行い、draw関数で描画を行っています。

main.lua
function setup()
  
  -- 略 --
  
  -- World
  world = playbox.world.new(0.0, 9.81, 10)
  world:setPixelScale(WORLD_PIXEL_SCALE)
  
  -- 地面
  floor = playbox.body.new(FLOOR_WIDTH, FLOOR_HEIGHT, 0)
  floor:setCenter(WORLD_WIDTH/2, WORLD_HEIGHT)
  floor:setFriction(FLOOR_FRICTION)
  floor:setRotation(0.1)
  world:addBody(floor)
  
  -- 天井
  ceiling = playbox.body.new(CEILING_WIDTH, CEILING_HEIGHT, 0)
  ceiling:setCenter(WORLD_WIDTH/2, CEILING_HEIGHT/2)
  ceiling:setFriction(CEILING_FRICTION)
  world:addBody(ceiling)
  
  -- 箱
  for i = 1, BOX_COUNT do
    local box_mass <const> = math.random(MASS_MIN, MASS_MAX)
    local box = playbox.body.new(math.random() * 0.3 + 0.2, math.random() * 0.3 + 0.2, box_mass)
    box:setCenter(math.random() * WORLD_WIDTH, CEILING_HEIGHT)
    box:setFriction(0.8)
    box:setRotation(math.random() * 0.8 + 0.1)
    world:addBody(box)
    boxes[#boxes + 1] = box
    
    -- 箱の模様は質量と連動。明るい模様 = 軽い
    box_patterns[#box_patterns + 1] = math.max(math.min(1.0 - box_mass/MASS_MAX, 0.9), 0.1)
  end
  
  -- 揺れる板
  swing_box = playbox.body.new(0.1, 1.0, 80)
  swing_box:setCenter(0, CEILING_HEIGHT)
  swing_box:setFriction(1.0)
  world:addBody(swing_box)
  
  -- 揺れる板と結ばれている紐
  swing_joint = playbox.joint.new(ceiling, swing_box, WORLD_WIDTH/4, 0)
  swing_joint:setBiasFactor(0.3)
  swing_joint:setSoftness(0.0)
  world:addJoint(swing_joint)
end

playbox.world.new([X軸の重力加速度], [Y軸の重力加速度], [イテレーション])でWorld生成し、
floor、ceiling、box、swing_boxはplaybox.body.new([横幅], [縦幅], [質量])で生成しています。
playbox.bodyの質量を0にすると固定できます。
余談ですが、box同士がぶつかり合う際、この質量に大きい差があると、めり込みが起こってしまいます。
なぜそうなるのか理解していないので知見ある方教えていただけますとありがたいです🙏

ceilingとswing_boxをつなぐジョイントはplaybox.joint.new([対象A], [対象B], [worldからみたジョイントのX座標], [worldからみたジョイントのY座標])となります。

main.lua
function draw()
  
  -- 略 --
  
  -- 床描画
  local floor_polygon = geometry.polygon.new(floor:getPolygon())
  floor_polygon:close()
  graphics.fillPolygon(floor_polygon)
  
  -- 天井描画
  local ceiling_polygon = geometry.polygon.new(ceiling:getPolygon())
  ceiling_polygon:close()
  graphics.fillPolygon(ceiling_polygon)
  
  -- 箱描画
  graphics.setStrokeLocation(graphics.kStrokeInside)
  for i, box in ipairs(boxes) do
    local box_polygon = geometry.polygon.new(box:getPolygon())
    box_polygon:close()
    graphics.setDitherPattern(box_patterns[i])
    graphics.fillPolygon(box_polygon)
    graphics.setColor(graphics.kColorBlack)
    if i == selected_box then
      graphics.setLineWidth(3)
    else
      graphics.setLineWidth(1)
    end
    graphics.drawPolygon(box_polygon)
  end
  
  
  graphics.setLineWidth(1)
  graphics.setDitherPattern(0.5)
  
  -- 揺れる板描画
  local swing_box_polygon = geometry.polygon.new(swing_box:getPolygon())
  swing_box_polygon:close()
  graphics.fillPolygon(swing_box_polygon)
  
  -- 揺れる板と結ばれている紐描画
  graphics.setStrokeLocation(graphics.kStrokeCentered)
  local _, _, px1, py1, x2, y2, _, _ = swing_joint:getPoints()
  graphics.setDitherPattern(0.5)
  graphics.drawLine(x2, y2, px1, py1)
  
  -- 略 --

end

draw関数ではplaybox.body:getPolygon()でポリゴンを取得し、各boxを描画しています。
ジョイントについてはplaybox.joint:getPoints()で座標を取得し、drawLineで線を描画しています。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0