/b2d/world.lua
https://bitbucket.org/itraykov/boxy · Lua · 1116 lines · 937 code · 134 blank · 45 comment · 225 complexity · 89072377a359352099a1abc510fda1f8 MD5 · raw file
- World = {}
- WorldMT = { __index = World }
- function World:Create(def)
- local self = {}
- setmetatable(self, WorldMT)
-
- --assert(def.left < def.right)
- --assert(def.top < def.bottom)
- self.def = def
- self.bodies = {}
- self.joints = {}
- self.nextID = 1
- self.nextJID = 1
-
- return self
- end
- function World:Destroy()
- self.def = nil
- self.bodies = nil
- self.joints = nil
- self.nextID = nil
- self.nextJID = nil
- end
- function World:GetGravity()
- local g = self.def.gravity
- return g.x, g.y
- end
- function World:SetGravity(g)
- self.def.gravity = g
- end
- -- Returns available ID
- function World:GetAvailableID()
- local id = self.nextID
- self.nextID = self.nextID + 1
- -- make sure the id is available
- while self.bodies[id] ~= nil do
- id = self.nextID
- self.nextID = self.nextID + 1
- end
- return id
- end
- -- Returns body by ID
- function World:FindBody(id)
- return self.bodies[id]
- end
- function World:DestroyBody(b)
- local q = self:GetAssociatedJoints(b)
- for i, v in ipairs(q) do
- self:DestroyJoint(v)
- end
- self.bodies[b.id] = nil
- b:Destroy()
- end
- function World:CreateBodyID(id, def)
- local b = Body:Create(self, def)
- b.id = id
- assert(self.bodies[id] == nil, "Duplicate body id:" .. id)
- self.bodies[id] = b
- return b
- end
- -- circumvents def object
- function World:CreateBodyEx(t, x, y, a, ld, ad, fr, ib, is, as, gs)
- assert(x and y)
- local def = {}
- def.type = t
- def.position = { x = x, y = y }
- def.angle = a or 0
- def.linearDamping = ld or 0
- def.angularDamping = ad or 0
- def.fixedRotation = fr or false
- def.isBullet = ib or false
- def.allowSleep = as or false
- def.isSleeping = is or false
- def.gravityScale = gs or 1
- def.active = true
- local id = self:GetAvailableID()
- return self:CreateBodyID(id, def)
- end
- -- Returns available ID
- function World:GetAvailableJID()
- local jid = self.nextJID
- self.nextJID = self.nextJID + 1
- -- make sure the id is available
- while self.joints[jid] ~= nil do
- jid = self.nextJID
- self.nextJID = self.nextJID + 1
- end
- return jid
- end
- function World:DestroyJoint(j)
- self.joints[j.id] = nil
- j:Destroy()
- end
- function World:QueryAABB(l, r, t, b, q)
- q = q or {}
- for i, v in pairs(self.bodies) do
- v:QueryAABB(l, r, t, b, q)
- end
- return q
- end
- -- Returns body by ID
- function World:FindJoint(jid)
- return self.joints[jid]
- end
- function World:CreateJointID(jid, def)
- local t = def.type
- local ctor
- if t == "revolute" then
- ctor = RevoluteJoint
- elseif t == "weld" then
- ctor = WeldJoint
- elseif t == "distance" then
- ctor = DistanceJoint
- elseif t == "rope" then
- ctor = RopeJoint
- elseif t == "prismatic" then
- ctor = PrismaticJoint
- elseif t == "pulley" then
- ctor = PulleyJoint
- elseif t == "gear" then
- ctor = GearJoint
- else
- assert(false, "Unknown joing type: " .. t)
- end
- local j = ctor:Create(self, def)
- j.id = jid
- assert(self.joints[jid] == nil, "Duplicate joint id: " .. jid)
- self.joints[jid] = j
- return j
- end
- function World:CreateJointEx(t, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
- local def = {}
- def.type = t
- local b1, b2 = p1, p2
- def.body1 = b1
- def.body2 = b2
- def.collideConnected = p3
- if t == "revolute" then
- -- body1, body2, cc, ax, ay
- local l1x, l1y = b1:GetLocalPoint(p4, p5)
- local l2x, l2y = b2:GetLocalPoint(p4, p5)
- def.localAnchor1 = { x = l1x, y = l1y }
- def.localAnchor2 = { x = l2x, y = l2y }
- def.referenceAngle = b2:GetAngle() - b1:GetAngle()
- def.enableLimit = false
- def.lowerAngle = 0
- def.upperAngle = 0
- def.enableMotor = false
- def.motorSpeed = 0
- def.maxMotorTorque = 0
- elseif t == "weld" then
- -- body1, body2, cc, ax, ay
- local l1x, l1y = b1:GetLocalPoint(p4, p5)
- local l2x, l2y = b2:GetLocalPoint(p4, p5)
- def.localAnchor1 = { x = l1x, y = l1y }
- def.localAnchor2 = { x = l2x, y = l2y }
- def.referenceAngle = b2:GetAngle() - b1:GetAngle()
- def.frequencyHz = 0
- def.dampingRatio = 0
- elseif t == "distance" or t == "rope" then
- -- body1, body2, cc, a1x, a1y, a2x, a2y
- local l1x, l1y = b1:GetLocalPoint(p4, p5)
- local l2x, l2y = b2:GetLocalPoint(p6, p7)
- def.localAnchor1 = { x = l1x, y = l1y }
- def.localAnchor2 = { x = l2x, y = l2y }
- local lx, ly = p6 - p4, p7 - p5
- local l = math.sqrt(lx*lx + ly*ly)
- if t == "distance" then
- def.length = l
- def.frequencyHz = 0
- def.dampingRatio = 0
- else
- def.maxLength = l
- end
- elseif t == "prismatic" then
- -- body1, body2, cc, ax, ay, axisx, axisy
- local l1x, l1y = b1:GetLocalPoint(p4, p5)
- local l2x, l2y = b2:GetLocalPoint(p4, p5)
- def.localAnchor1 = { x = l1x, y = l1y }
- def.localAnchor2 = { x = l2x, y = l2y }
- local ax, ay = b1:GetLocalVector(p6, p7)
- def.localAxis1 = { x = ax, y = ay }
- def.referenceAngle = b2:GetAngle() - b1:GetAngle()
- def.enableLimit = false
- def.lowerTranslation = 0
- def.upperTranslation = 0
- def.enableMotor = false
- def.motorSpeed = 0
- def.maxMotorForce = 0
- elseif t == "pulley" then
- -- body1, body2, cc, g1x, g1y, g2x, g2y, a1x, a1y, a2x, a2y, ratio
- def.groundAnchor1 = { x = p4, y = p5 }
- def.groundAnchor2 = { x = p6, y = p7 }
- local l1x, l1y = b1:GetLocalPoint(p8, p9)
- local l2x, l2y = b2:GetLocalPoint(p10, p11)
- def.localAnchor1 = { x = l1x, y = l1y }
- def.localAnchor2 = { x = l2x, y = l2y }
-
- local lx, ly = p8 - p4, p9 - p5
- def.length1 = math.sqrt(lx*lx + ly*ly)
- local lx, ly = p8 - p6, p9 - p7
- def.length2 = math.sqrt(lx*lx + ly*ly)
- elseif t == "gear" then
- def.joint1 = p4
- def.joint2 = p5
- def.ratio = p6 or 1
- else
- assert(false, t)
- end
- local jid = self:GetAvailableJID()
- return self:CreateJointID(jid, def)
- end
- function World:GetAssociatedJoints(body)
- local q = {}
- for i, v in pairs(self.joints) do
- if v.def.body1 == body or v.def.body2 == body then
- table.insert(q, v)
- end
- end
- return q
- end
- -- xml v3 ----------------------------------------------------------------------------
- function World:CreateJointXML_v3(j)
- local def = {}
-
- local t = j.type
- if t == "g" then
- def.type = "gear"
- local j1 = xml.find(j, "J1")
- local j2 = xml.find(j, "J2")
- assert(j1, "Missing JointA tag: " .. j.id)
- assert(j2, "Missing JointB tag: " .. j.id)
- local jid1 = tonumber(j1[1])
- local jid2 = tonumber(j2[1])
- assert(jid1, "Invalid joint id: " .. j.id .. ' ' .. tostring(j1[1]))
- assert(jid2, "Invalid joint id: " .. j.id .. ' ' .. tostring(j2[1]))
- def.joint1 = self:FindJoint(jid1)
- def.joint2 = self:FindJoint(jid2)
- assert(def.joint1, "JointA does not exist: " .. j.id .. ' ' .. tostring(j1[1]))
- assert(def.joint2, "JointB does not exist: " .. j.id .. ' ' .. tostring(j2[1]))
- def.ratio = tonumber(xml.find(j, "RO")[1])
- else
- local a1 = xml.find(j, "A1")
- local a2 = xml.find(j, "A2")
- def.localAnchorA = b2.Vec2(a1.x,a1.y)
- def.localAnchorB = b2.Vec2(a2.x,a2.y)
- if t == "r" then
- def.type = "revolute"
- def.referenceAngle = tonumber(xml.find(j, "RA")[1])
- local lt = xml.find(j, "LT")
- if lt then
- def.enableLimit = (lt.e == "true")
- def.lowerAngle = tonumber(lt.l)
- def.upperAngle = tonumber(lt.u)
- end
- local mt = xml.find(j, "MT")
- if mt then
- def.enableMotor = (mt.e == "true")
- def.motorSpeed = tonumber(mt.s)
- def.maxMotorTorque = tonumber(mt.t)
- end
- elseif t == "w" then
- def.type = "weld"
- def.referenceAngle = tonumber(xml.find(j, "RA")[1])
- def.frequencyHz = tonumber(xml.find(j, "HZ")[1])
- def.dampingRatio = tonumber(xml.find(j, "DR")[1])
- elseif t == "p" then
- def.type = "prismatic"
- def.localAxisA = { "b2Vec2", b2.Vec2(0,0) }
- def.referenceAngle = tonumber(xml.find(j, "RA")[1])
- local lt = xml.find(j, "LT")
- if lt then
- def.enableLimit = (lt.e == "true")
- def.lowerTranslation = tonumber(lt.l)
- def.upperTranslation = tonumber(lt.u)
- end
- local mt = xml.find(j, "MT")
- if mt then
- def.enableMotor = (mt.e == "true")
- def.motorSpeed = tonumber(mt.s)
- def.maxMotorForce = tonumber(mt.f)
- end
- elseif t == "d" then
- def.type = "distance"
- def.dampingRatio = tonumber(xml.find(j, "DR")[1])
- def.frequencyHz = tonumber(xml.find(j, "HZ")[1])
- def.length = tonumber(xml.find(j, "L")[1])
- elseif t == "o" then
- def.type = "rope"
- def.maxLength = tonumber(xml.find(j, "ML")[1])
- elseif t == "u" then
- def.type = "pulley"
- local g1 = xml.find(j, "G1")
- local g2 = xml.find(j, "G2")
- def.groundAnchorA = b2.Vec2(g1.x,g1.y)
- def.groundAnchorB = b2.Vec2(g2.x,g2.y)
- def.lengthA = tonumber(xml.find(j, "L1")[1])
- def.lengthB = tonumber(xml.find(j, "L2")[1])
- def.maxLengthA = tonumber(xml.find(j, "ML1")[1])
- def.maxLengthB = tonumber(xml.find(j, "ML2")[1])
- def.ratio = tonumber(xml.find(j, "RO")[1])
- elseif t == "m" then
- def.type = "mouse"
- else
- assert(false, "Unknown joint type")
- end
- end
- def.collideConnected = (j.cc == "true")
-
- def.maxLength1 = def.maxLengthA
- def.maxLength2 = def.maxLengthB
- def.length1 = def.lengthA
- def.length2 = def.lengthB
- def.groundAnchor1 = def.groundAnchorA
- def.groundAnchor2 = def.groundAnchorB
-
- def.localAnchor1 = def.localAnchorA
- def.localAnchor2 = def.localAnchorB
- def.localAxis1 = def.localAxisA
- def.localAnchorA = nil
- def.localAnchorB = nil
- def.localAxisA = nil
- local id1 = tonumber(j.body1)
- local id2 = tonumber(j.body2)
- assert(id1 and id2)
- def.body1 = self:FindBody(id1)
- def.body2 = self:FindBody(id2)
-
- local jid = tonumber(j.id)
- assert(jid, "Bad joint id: " .. tostring(jid))
- return self:CreateJointID(jid, def)
- end
- function World:SaveXML_v3(file)
- local f = xml.new("B2D")
- f.version = "2.3.2"
- f.created = os.date()
- local world = self:GetXML_v3()
- f:append(world)
- xml.save(f, file)
- end
- function World:CreateXML_v3(w)
- local def = {}
- def.gravity = b2.Vec2(0,0)
- local self = World:Create(def)
- assert(self, "Could not create world")
- for i = 1, #w, 1 do
- local v = w[i]
- local tag = xml.tag(v)
- if tag == "G" then
- local g = b2.Vec2(v.x, v.y)
- self:SetGravity(g)
- elseif tag == "B" then
- self:CreateBodyXML_v3(v)
- else
- -- is it a joint?
- if tag == 'J' and v.type ~= "g" then
- self:CreateJointXML_v3(v)
- end
- end
- end
- for i = 1, #w, 1 do
- local v = w[i]
- local tag = xml.tag(v)
- if tag == "J" and v.type == "g" then
- -- is it a joint?
- self:CreateJointXML_v3(v)
- end
- end
- return self
- end
- function World:CreateBodyXML_v3(b)
- local id = xml.tonumber(b.id)
- local def = {}
-
- def.type = "staticBody"
- if b.type == "d" then
- def.type = "dynamicBody"
- elseif b.type == "k" then
- def.type = "kinematicBody"
- end
- def.position = b2.Vec2(b.x, b.y)
- def.angle = tonumber(b.a) or 0
-
- local ld = xml.find(b, "LD")
- if ld then
- def.linearDamping = tonumber(ld[1]) or 0
- else
- def.linearDamping = 0
- end
- local ad = xml.find(b, "AD")
- if ad then
- def.angularDamping = tonumber(ld[1]) or 0
- else
- def.angularDamping = 0
- end
- local fr = xml.find(b, "FR")
- if fr then
- def.fixedRotation = fr[1] == 'true'
- else
- def.fixedRotation = false
- end
- local ib = xml.find(b, "IB")
- if ib then
- def.isBullet = ib[1] == 'true'
- else
- def.isBullet = false
- end
- local sa = xml.find(b, "SA")
- if sa then
- def.allowSleep = sa[1] == 'true'
- else
- def.allowSleep = true
- end
- local aw = xml.find(b, "AW")
- if aw then
- def.isSleeping = not(aw[1] == 'true')
- else
- def.isSleeping = false
- end
- local gs = xml.find(b, 'GS')
- if gs then
- def.gravityScale = tonumber(gs[1])
- else
- def.gravityScale = 1
- end
- local ia = xml.find(b, 'IA')
- if ia then
- def.active = (ia[1] == 'true')
- else
- def.active = true
- end
-
- --def.isBullet = def.bullet
- --def.isSleeping = not def.awake
- --def.bullet = nil
- --def.awake = nil
-
- local body = self:CreateBodyID(id, def)
-
- for i = 1, #b, 1 do
- local v = b[i]
- local tag = xml.tag(v)
- if tag == "LV" then
- local lv = xml.cast.b2Vec2(v)
- body:SetLinearVelocity(lv.x, lv.y)
- elseif tag == "AV" then
- local av = xml.cast.number(v)
- body:SetAngularVelocity(av)
- elseif tag == "SS" then
- body.def.scale = xml.tonumber(b[i][1])
- elseif tag == "F" then
- body:CreateShapeXML_v3(v)
- end
- end
-
- return body
- end
- function World:GetXML_v3()
- local world = xml.new("W")
-
- local def = self.def
- local g = world:append("G")
- g.x = def.gravity.x
- g.y = def.gravity.y
-
- -- world.doSleep = def.doSleep
- for i, v in pairs(self.bodies) do
- local body = v:GetXML_v3()
- world:append(body)
- end
- -- save non-gear joints
- for i, v in pairs(self.joints) do
- if v:GetType() ~= "gear" then
- local joint = v:GetXML_v3()
- world:append(joint)
- end
- end
- -- save gear joints at the end
- for i, v in pairs(self.joints) do
- if v:GetType() == "gear" then
- local joint = v:GetXML_v3()
- world:append(joint)
- end
- end
- return world
- end
- -- xml v2 ----------------------------------------------------------------------------
- local revoluteJSkeleton =
- {
- referenceAngle = { "number", 0 },
- enableLimit = { "boolean", false },
- lowerAngle = { "number", 0 },
- upperAngle = { "number", 0 },
- enableMotor = { "boolean", false },
- motorSpeed = { "number", 0 },
- maxMotorTorque = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local weldJSkeleton =
- {
- referenceAngle = { "number", 0 },
- frequencyHz = { "number", 0 },
- dampingRatio = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local prismaticJSkeleton =
- {
- localAxisA = { "b2Vec2", b2.Vec2(0,0) },
- referenceAngle = { "number", 0 },
- enableLimit = { "boolean", false },
- lowerTranslation = { "number", 0 },
- upperTranslation = { "number", 0 },
- enableMotor = { "boolean", false },
- motorSpeed = { "number", 0 },
- maxMotorForce = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local distanceJSkeleton =
- {
- length = { "number", 0 },
- frequencyHz = { "number", 0 },
- dampingRatio = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local ropeJSkeleton =
- {
- maxLength = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local pulleyJSkeleton =
- {
- groundAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- groundAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- lengthA = { "number", 0 },
- lengthB = { "number", 0 },
- maxLengthA = { "number", 0 },
- maxLengthB = { "number", 0 },
- ratio = { "number", 0 },
- localAnchorA = { "b2Vec2", b2.Vec2(0,0) },
- localAnchorB = { "b2Vec2", b2.Vec2(0,0) },
- collideConnected = { "boolean", false }
- }
- local gearJSkeleton =
- {
- ratio = { "number", 1 },
- collideConnected = { "boolean", false }
- }
- function World:CreateJointXML_v2(j)
- local def = {}
-
- local t = xml.tag(j)
- local skeleton
- if t == "RevoluteJoint" then
- def.type = "revolute"
- skeleton = revoluteJSkeleton
- elseif t == "WeldJoint" then
- def.type = "weld"
- skeleton = weldJSkeleton
- elseif t == "PrismaticJoint" then
- def.type = "prismatic"
- skeleton = prismaticJSkeleton
- elseif t == "DistanceJoint" then
- def.type = "distance"
- skeleton = distanceJSkeleton
- elseif t == "RopeJoint" then
- def.type = "rope"
- skeleton = ropeJSkeleton
- elseif t == "PulleyJoint" then
- def.type = "pulley"
- skeleton = pulleyJSkeleton
- elseif t == "MouseJoint" then
- def.type = "mouse"
- elseif t == "GearJoint" then
- def.type = "gear"
- skeleton = gearJSkeleton
- local j1 = xml.find(j, "JointA")
- local j2 = xml.find(j, "JointB")
- assert(j1, "Missing JointA tag: " .. j.id)
- assert(j2, "Missing JointB tag: " .. j.id)
- local jid1 = xml.cast.number(j1)
- local jid2 = xml.cast.number(j2)
- def.joint1 = self:FindJoint(jid1)
- def.joint2 = self:FindJoint(jid2)
- assert(def.joint1, "JointA does not exist: " .. j.id)
- assert(def.joint2, "JointB does not exist: " .. j.id)
- else
- assert(false, "Unknown joint type")
- end
- xml.loadSkeleton(skeleton, j, def)
-
- def.maxLength1 = def.maxLengthA
- def.maxLength2 = def.maxLengthB
- def.length1 = def.lengthA
- def.length2 = def.lengthB
- def.groundAnchor1 = def.groundAnchorA
- def.groundAnchor2 = def.groundAnchorB
-
- def.localAnchor1 = def.localAnchorA
- def.localAnchor2 = def.localAnchorB
- def.localAxis1 = def.localAxisA
- def.localAnchorA = nil
- def.localAnchorB = nil
- def.localAxisA = nil
- local id1 = tonumber(j.body1)
- local id2 = tonumber(j.body2)
- assert(id1 and id2)
- def.body1 = self:FindBody(id1)
- def.body2 = self:FindBody(id2)
-
- local jid = tonumber(j.id)
- return self:CreateJointID(jid, def)
- end
- function World:SaveXML_v2(file)
- local f = xml.new("XMLBox2D")
- f.version = "1.0"
- f.created = os.date()
- f['noNamespaceSchemaLocation']="level.xsd"
- f['xmlns:xsi']="http://www.w3.org/2001/XMLSchema-instance"
- local world = self:GetXML_v2()
- f:append(world)
- xml.save(f, file)
- end
- local jtypes =
- {
- "RevoluteJoint",
- "WeldJoint",
- "PrismaticJoint",
- "DistanceJoint",
- "RopeJoint",
- "PulleyJoint",
- "GearJoint",
- "MouseJoint"
- }
- function World:CreateXML_v2(w)
- local def = {}
- def.gravity = b2.Vec2(0,0)
- local self = World:Create(def)
- assert(self, "Could not create world")
- for i = 1, #w, 1 do
- local v = w[i]
- local tag = xml.tag(v)
- if tag == "Gravity" then
- local g = xml.cast.b2Vec2(v)
- self:SetGravity(g)
- elseif tag == "Body" then
- self:CreateBodyXML_v2(v)
- else
- -- is it a joint?
- for _, joint in ipairs(jtypes) do
- if tag == joint and tag ~= "GearJoint" then
- self:CreateJointXML_v2(v)
- break
- end
- end
- end
- end
- for i = 1, #w, 1 do
- local v = w[i]
- local tag = xml.tag(v)
- if tag == "GearJoint" then
- -- is it a joint?
- self:CreateJointXML_v2(v)
- end
- end
- return self
- end
- local bodyDefSkeleton =
- {
- type = { "string", "staticBody" },
- position = { "b2Vec2", b2.Vec2(0,0) },
- angle = { "number", 0 },
- linearDamping = { "number", 0 },
- angularDamping = { "number", 0 },
- fixedRotation = { "boolean", false },
- bullet = { "boolean", false },
- allowSleep = { "boolean", false },
- awake = { "boolean", true },
- gravityScale = { "number", 1 },
- active = { "boolean", true }
- }
- function World:CreateBodyXML_v2(b)
- local id = xml.tonumber(b.id)
- local def = {}
- xml.loadSkeleton(bodyDefSkeleton, b, def)
-
- def.isBullet = def.bullet
- def.isSleeping = not def.awake
- def.bullet = nil
- def.awake = nil
-
- local body = self:CreateBodyID(id, def)
-
- for i = 1, #b, 1 do
- local v = b[i]
- local tag = xml.tag(v)
- if tag == "LinearVelocity" then
- local lv = xml.cast.b2Vec2(v)
- body:SetLinearVelocity(lv.x, lv.y)
- elseif tag == "AngularVelocity" then
- local av = xml.cast.number(v)
- body:SetAngularVelocity(av)
- elseif tag == "Scale" then
- body.def.scale = xml.tonumber(b[i][1])
- elseif tag == "CircleShape" or tag == "PolygonShape" or tag == "ConcaveShape" or tag == "ChainShape" then
- body:CreateShapeXML_v2(v)
- end
- end
-
- return body
- end
- function World:GetXML_v2()
- local world = xml.new("World")
-
- local def = self.def
- local g = world:append("Gravity")
- g.x = def.gravity.x
- g.y = def.gravity.y
-
- -- world.doSleep = def.doSleep
- for i, v in pairs(self.bodies) do
- local body = v:GetXML_v2()
- world:append(body)
- end
- -- save non-gear joints
- for i, v in pairs(self.joints) do
- if v:GetType() ~= "gear" then
- local joint = v:GetXML_v2()
- world:append(joint)
- end
- end
- -- save gear joints at the end
- for i, v in pairs(self.joints) do
- if v:GetType() == "gear" then
- local joint = v:GetXML_v2()
- world:append(joint)
- end
- end
- return world
- end
- -- xml v1 ----------------------------------------------------------------------------------------
- function World:CreateJointXML_v1(j)
- local def
- local t = j.type
- local def = {}
- def.type = t
- if t == "revolute" then
- local a = xml.find(j, "ReferenceAngle")
- local l = xml.find(j, "Limit")
- local m = xml.find(j, "Motor")
- -- assign values
- def.referenceAngle = xml.tonumber(a[1])
- -- default values
- def.enableLimit = false
- def.lowerAngle = 0
- def.upperAngle = 0
- def.enableMotor = false
- def.motorSpeed = 0
- def.maxMotorTorque = 0
- -- optional
- if l then
- def.enableLimit = xml.toboolean(l.enabled)
- def.lowerAngle = xml.tonumber(l.lowerAngle)
- def.upperAngle = xml.tonumber(l.upperAngle)
- end
- if m then
- def.enableMotor = xml.toboolean(m.enabled)
- def.motorSpeed = xml.tonumber(m.speed)
- def.maxMotorTorque = xml.tonumber(m.maxTorque)
- end
- elseif t == "prismatic" then
- local la1 = xml.find(j, "LocalAxis1")
- local la1x, la1y = xml.toPosition_v1(la1[1])
- local a = xml.find(j, "ReferenceAngle")
- local l = xml.find(j, "Limit")
- local m = xml.find(j, "Motor")
- -- assign values
- def.localAxis1 = { x = la1x, y = la1y }
- def.referenceAngle = xml.tonumber(a[1])
- -- default values
- def.enableLimit = false
- def.lowerTranslation = 0
- def.upperTranslation = 0
- def.enableMotor = false
- def.motorSpeed = 0
- def.maxMotorForce = 0
- -- optional
- if l then
- def.enableLimit = xml.toboolean(l.enabled)
- def.lowerTranslation = xml.tonumber(l.lowerTranslation)
- def.upperTranslation = xml.tonumber(l.upperTranslation)
- end
- if m then
- def.enableMotor = xml.tonumber(m.enabled)
- def.motorSpeed = xml.tonumber(m.speed)
- def.maxMotorForce = xml.tonumber(m.maxForce)
- end
- elseif t == "distance" then
- local l = xml.find(j, "Length")
- local f = xml.find(j, "FrequencyHz")
- local d = xml.find(j, "DampingRatio")
- -- assign values
- def.length = xml.tonumber(l[1])
- def.frequencyHz = xml.tonumber(f[1])
- def.dampingRatio = xml.tonumber(d[1])
- elseif t == "pulley" then
- local ga1 = xml.find(j, "GroundAnchor1")
- local ga2 = xml.find(j, "GroundAnchor2")
- local ga1x, ga1y = xml.toPosition_v1(ga1[1])
- local ga2x, ga2y = xml.toPosition_v1(ga2[1])
- local l1 = xml.find(j, "Length1")
- local l2 = xml.find(j, "Length2")
- local maxl1 = xml.find(j, "MaxLength1")
- local maxl2 = xml.find(j, "MaxLength2")
- local r = xml.find(j, "Ratio")
- -- values
- def.groundAnchor1 = { x = ga1x, y = ga1y }
- def.groundAnchor2 = { x = ga2x, y = ga2y }
- def.length1 = xml.tonumber(l1[1])
- def.length2 = xml.tonumber(l2[1])
- def.maxLength1 = xml.tonumber(maxl1[1])
- def.maxLength2 = xml.tonumber(maxl2[1])
- def.ratio = xml.tonumber(r[1])
- elseif t == "mouse" then
- elseif t == "gear" then
- local j1 = xml.find(joint, "Joint1")
- local j2 = xml.find(joint, "Joint2")
- local jid1 = xml.tonumber(j1[1])
- local jid2 = xml.tonumber(j2[1])
- -- assign values
- def.joint1 = self:FindJoint(jid1)
- def.joint2 = self:FindJoint(jid2)
- end
- local id1 = xml.tonumber(j.body1)
- local id2 = xml.tonumber(j.body2)
- local la1 = xml.find(j, "LocalAnchor1")
- local la2 = xml.find(j, "LocalAnchor2")
- -- assign values
- def.body1 = self:FindBody(id1)
- def.body2 = self:FindBody(id2)
- def.collideConnected = xml.toboolean(j.collideConnected)
- def.localAnchor1 = { x = 0, y = 0 }
- def.localAnchor2 = { x = 0, y = 0 }
- if la1 then
- local la1x, la1y = xml.toPosition_v1(la1[1])
- def.localAnchor1.x = la1x
- def.localAnchor1.y = la1y
- end
- if la2 then
- local la2x, la2y = xml.toPosition_v1(la2[1])
- def.localAnchor2.x = la2x
- def.localAnchor2.y = la2y
- end
-
- local jid = xml.tonumber(j.id)
- return self:CreateJointID(jid, def)
- end
- function World:SaveXML_v1(file)
- local f = xml.new("XMLBox2D")
- f.version = "1.0"
- f.created = os.date()
- local world = self:GetXML_v1()
- f:append(world)
- xml.save(f, file)
- end
- function World:CreateXML_v1(w)
- local def = {}
- def.left = xml.tonumber(w.left)
- def.top = xml.tonumber(w.top)
- def.right = xml.tonumber(w.right)
- def.bottom = xml.tonumber(w.bottom)
- local gx, gy = xml.toPosition_v1(w.gravity)
- def.gravity = { x = gx, y = gy }
- def.doSleep = xml.toboolean(w.doSleep)
- local self = World:Create(def)
- assert(self, "Could not create world")
- local objects = #w
- for i = 1, objects, 1 do
- local object = w[i]
- local tag = xml.tag(object)
- if tag == "Body" then
- self:CreateBodyXML_v1(object)
- elseif tag == "Joint" then
- self:CreateJointXML_v1(object)
- else
- assert(false, "Unkown tag in world")
- end
- end
- return self
- end
- function World:CreateBodyXML_v1(b)
- local id = xml.tonumber(b.id)
- local def = {}
- def.type = b.type
- local px, py = xml.toPosition_v1(b.position)
- def.position = { x = px, y = py }
- def.angle = xml.tonumber(b.angle)
- def.linearDamping = xml.tonumber(b.linearDamping)
- def.angularDamping = xml.tonumber(b.angularDamping)
- def.fixedRotation = xml.toboolean(b.fixedRotation)
- def.isBullet = xml.toboolean(b.isBullet)
- def.allowSleep = xml.toboolean(b.allowSleep)
- def.isSleeping = xml.toboolean(b.isSleeping)
-
- local body = self:CreateBodyID(id, def)
- for i = 1, #b, 1 do
- local tag = xml.tag(b[i])
- if tag == "LinearVelocity" then
- local lvx, lvy = xml.toPosition_v1(b[i][1])
- body:SetLinearVelocity(lvx, lvy)
- elseif tag == "AngularVelocity" then
- local av = xml.tonumber(b[i][1])
- body:SetAngularVelocity(av)
- elseif tag == "Scale" then
- body.def.scale = xml.tonumber(b[i][1])
- elseif tag == "Shape" then
- body:CreateShapeXML_v1(b[i])
- end
- end
-
- return body
- end
- function World:GetXML_v1()
- local world = xml.new("World")
- local def = self.def
- world.left = def.left
- world.top = def.top
- world.right = def.right
- world.bottom = def.bottom
- local g = def.gravity
- world.gravity = xml.PositionStr_v1(g.x, g.y)
- world.doSleep = def.doSleep
- for i, v in pairs(self.bodies) do
- local body = v:GetXML_v1()
- world:append(body)
- end
- for i, v in pairs(self.joints) do
- local joint = v:GetXML_v1()
- world:append(joint)
- end
- return world
- end
- -----------------------------------------------------------------------------
- function World:GetLua_v1()
- local world = xml.new("World")
- local def = self.def
- local x, y = def.gravity.x, def.gravity.y
- local s = "false"
- if def.doSleep == true then
- s = "true"
- end
- local sz = "local world = love.physics.newWorld(%s, %s, %s)"
- sz = string.format(sz, x, y, s)
- local sz2 = "local bodies = {}"
- local sz3 = "local joints = {}"
-
- local out = { sz, sz2, sz3 }
-
- for i, v in pairs(self.bodies) do
- local body = v:GetLua_v1()
- table.insert(out, body)
- end
- -- save non-gear joints
- for i, v in pairs(self.joints) do
- if v:GetType() ~= "gear" then
- local joint = v:GetLua_v1()
- table.insert(out, joint)
- end
- end
- -- save gear joints at the end
- for i, v in pairs(self.joints) do
- if v:GetType() == "gear" then
- local joint = v:GetLua_v1()
- table.insert(out, joint)
- end
- end
- return table.concat(out, "\n")
- end
- function World:SaveLua(file)
- local sz = self:GetLua()
- local f = io.open(file, "w")
- f:write(sz)
- f:close()
- end
- -----------------------------------------------------------------------------
- function World:CreateXML(w)
- return self:CreateXML_v3(w)
- end
- function World:GetXML()
- return self:GetXML_v3()
- end
- function World:SaveXML(file)
- return self:SaveXML_v3(file)
- end
- function World:CreateBodyXML(b)
- return self:CreateBodyXML_v2(b)
- end
- function World:CreateJointXML(b)
- return self:CreateJointXML_v2(b)
- end
- function World:GetLua()
- return self:GetLua_v1()
- end