加速スイングバイ:
減速スイングバイ:
require "physics" require "color"
function pV(x, y) return physics.Vect(x, y) end
function sum(list) local result = ZERO for _, v in ipairs(list) do result = result + v end return result end
function on.resize()
W, H = platform.window:width(), platform.window:height()
X0, Y0, UNIT = W/2, H/2, math.floor(W/90)
end
TICKING = false
GRID = true
drawHistory, maxHistory, penHistory = true, 200, "thin"
ZERO = pV(0, 0)
LARGE = physics.misc.INFINITY()
dtLua = 1/(2^6)
dtChipmunk = 1/(2^6)
GRAVITY = 0
pBall = class()
function pBall:init(mass, radius, elasticity, friction, color, group)
self.color = color
self.history = {}
local inertia = physics.misc.momentForCircle(mass, 0, radius, ZERO)
self.body = physics.Body(mass, inertia)
self.shape = physics.CircleShape(self.body, radius, ZERO)
:setRestitution(elasticity)
:setFriction(friction)
if group then self.shape:setGroup(group) end
end
function pBall:paint(gc)
local pos = self.body:pos()
local cx, cy = X0 + UNIT * pos:x(), Y0 - UNIT * pos:y()
local radius = UNIT * self.shape:radius()
local diameter = radius + radius
local angle = self.body:angle()
local x0, y0 = cx - radius, cy - radius
gc:setColorRGB(self.color)
if drawHistory then
gc:setPen(penHistory)
self.history[#self.history+1] = cx
self.history[#self.history+1] = cy
if #self.history > maxHistory then table.remove(self.history, 1) table.remove(self.history, 1) end
gc:drawPolyLine(self.history)
end
gc:fillArc(x0, y0, diameter, diameter, 0, 360)
gc:setPen("thin")
gc:setColorRGB(color.black)
end
pSpace = class()
function pSpace:init(GRAVITY)
self.space = physics.Space()
:setGravity(pV(0, GRAVITY))
self.objects = {}
end
function pSpace:step(DT)
self.space:step(DT)
end
function pSpace:addObj(obj, velx, vely, cx, cy)
obj.body:setVel(pV(velx, vely))
:setPos(pV(cx, cy))
self.space:addBody(obj.body)
:addShape(obj.shape)
self.objects[#self.objects+1] = obj
end
function pSpace:attractBetween()
local forceTable = {}
for r = 1, #self.objects do
forceTable[r] = {}
for c = 1, #self.objects do
if r == c then
forceTable[r][c] = ZERO
elseif r > c then
forceTable[r][c] = -forceTable[c][r]
else
local posA = self.objects[r].body:pos()
local posB = self.objects[c].body:pos()
local massA = self.objects[r].body:mass()
local massB = self.objects[c].body:mass()
local vectAB = posB - posA
local lengthABsq = vectAB:lengthsq()
local normAB = vectAB:normalize()
forceTable[r][c] = normAB:mult(massA * massB/lengthABsq)
end
end
self.objects[r].body:setForce(sum(forceTable[r]))
end
end
function pSpace:paint(gc)
gc:setColorRGB(color.gray)
if GRAVITY ~= 0 then gc:drawString(string.format("acceleration of gravity: %3.1f", GRAVITY), 5, -3, "top") end
if TICKING == true then gc:drawString("running", W - 70, 12, "top") end
if TICKING == false then gc:drawString("stopped", W - 70, 12, "top") end
gc:drawString(string.format("t = %4.1f", timeElapsed), W - 70, -3, "top")
for _, v in ipairs(self.objects) do
v:paint(gc)
end
end
function grid(gc)
gc:setPen("thin")
gc:setColorRGB(0x6495ED)
gc:drawLine(0, Y0, W, Y0)
gc:drawLine(X0, 0, X0, H)
gc:fillPolygon({W, Y0, W - 7, Y0 - 4, W - 3, Y0, W - 7, Y0 + 4, W, Y0})
gc:fillPolygon({X0, 0, X0 - 4, 7, X0, 3, X0 + 4, 7, X0, 0})
gc:setColorRGB(0xCAE1FF)
local i1 = 1; while Y0 - UNIT * i1 > 0 do gc:drawLine(0, Y0 - UNIT * i1, W, Y0 - UNIT * i1); i1 = i1 + 1 end
local i2 = 1; while Y0 + UNIT * i2 < H do gc:drawLine(0, Y0 + UNIT * i2, W, Y0 + UNIT * i2); i2 = i2 + 1 end
local i3 = 1; while X0 + UNIT * i3 < W do gc:drawLine(X0 + UNIT * i3, 0, X0 + UNIT * i3, H); i3 = i3 + 1 end
local i4 = 1; while X0 - UNIT * i4 > 0 do gc:drawLine(X0 - UNIT * i4, 0, X0 - UNIT * i4, H); i4 = i4 + 1 end
gc:setColorRGB(0x6495ED)
gc:drawString("x", W - 10, Y0 - 21)
gc:drawString("y", X0 + 5, -6)
end
function reset()
on.resize()
timeElapsed = 0
space = pSpace(GRAVITY)
ball1 = pBall(1500, 2, 1, 0, color.navy, 999)
ball2 = pBall(0.0000000000001, 1.5, 1, 0, color.red, 999)
space:addObj(ball1, 3.5, 0, -20, 0); space:addObj(ball2, 12, 8, -40, -35)
platform.window:invalidate()
end
function on.construction() reset() end
function on.escapeKey() reset() end
function on.paint(gc)
if GRID then grid(gc) end
space:paint(gc)
end
function on.timer()
print(timeElapsed, space.objects[2].body:vel():length())
space:step(dtChipmunk)
space:attractBetween()
timeElapsed = timeElapsed + dtChipmunk
platform.window:invalidate()
end
function on.enterKey()
if TICKING == false then timer.start(dtLua) TICKING = true
elseif TICKING == true then timer.stop() TICKING = false
end
end