Hi,
I really liked your code sample as this is something I’ve been thinking/wondering/mulling for a while and your implementation is really good.
Personally, I don’t like using the enterFrame event as it very easily increases the chance of performance problems and often requires a lot more code to manage the operations taking place there. So I came up with the following modification of your code.
I’ve added a ball which can be thrown around, to affect the buoyant box, which is still draggable. The problem is that the box does not seem to have any friction against the ‘water’, so it’s rotation would need to be adjusted somehow - my answer to this would be another joint.
So, the core of my implementation is simply: Create an invisible anchor (off screen) to which other objects can be jointed to. Use this anchor to create a horizontal piston joint to limit a ‘lifting’ object. (Imagine a crane working at a port - it moves left and right and has a lifting platform which can move up and down.)
So, the lifter (moving along the piston) has a distance joint attaching it to the box. The distance joint is made rather springy, to mimic the fluidity of the water.
So, in short, I’ve tried to get buoyancy by using a distance joint which itself can move around, so that it is not always pulling the box back towards one fixed location.
I hope you like it - sorry for the overly long description…
Matt.
[lua]-- INIT PHYSICS
local physics = require(“physics”)
physics.start()
physics.setGravity( 0, 40 )
local gx, gy = physics.getGravity()
– FORWARD REFS
local _W = display.contentWidth
local _H = display.contentHeight
local ground, ceiling, leftWall, rightWall
local box
local waterLevel
– CREATE SCREEN BOUNDARY
ground = display.newRect(0,0,_W,20)
ground.x = _W * 0.5; ground.y = _H + (ground.height * 0.5)
ceiling = display.newRect(0,0,_W,20);
ceiling.x = _W * 0.5; ceiling.y = 0 - (ceiling.height * 0.5)
leftWall = display.newRect(0,0,10,_H)
leftWall.x = 0 - (leftWall.width * 0.5); leftWall.y = _H * 0.5
rightWall = display.newRect(0,0,10,_H)
rightWall.x = _W + (rightWall.width * 0.5); rightWall.y = _H * 0.5
physics.addBody(ground, “static”, {friction = 0.1})
physics.addBody(ceiling, “static”, {friction = 0.1})
physics.addBody(leftWall, “static”, {friction = 0.1})
physics.addBody(rightWall, “static”, {friction = 0.1})
– CREATE ‘BOX’
local box = display.newRect(_W * 0.5, _H * 0.5, 64, 64)
box.x = _W * 0.5; box.y = 64
box.area = box.height * box.width
box.density = 3.0
box.mass = box.area * box.density
physics.addBody( box, { density=3.0, friction=0.5 } )
box.y = display.contentCenterY
– CREATE WATER
local water = display.newRect(0, 0, _W, _H * 0.5)
water:setFillColor(0, 102, 255)
water.alpha = 0.3
water:setReferencePoint(display.TopCenterReferencePoint)
water.x = _W * 0.5
water.y = _H * 0.5
– *** START OF NEW CODE ***
– CREATE GLOBAL ANCHOR
local anchor = display.newCircle( -100, -100, 10 )
physics.addBody( anchor, “static”, { friction=0, density=0, radius=10, bounce=0 } )
– CREATE LIFTING ANCHOR
local lift = display.newCircle( box.x, 10, 10 )
physics.addBody( lift, “dynamic”, { friction=0, density=1, radius=10, bounce=0 } )
– CREATE JOINT TO BOY THE BOX IN THE WATER
–local myJoint = physics.newJoint( “piston”, anchor, box, anchor.x,display.contentCenterY, 5,0 )
– CREATE JOINT HOLDING THE LIFT
local piston = physics.newJoint( “piston”, anchor, lift, anchor.x,anchor.y, 5,0 )
– CREATE JOINT HOLDING THE BOX BY THE LIFT
local distance = physics.newJoint( “distance”, lift, box, lift.x,lift.y , box.x,box.y )
–distance.length = box.y - lift.y
distance.dampingRatio = 100
distance.frequency = 8
print(distance.length…’ ‘…distance.frequency…’ '…distance.dampingRatio)
– CREATE THROWABLE BALL
local ball = display.newCircle( box.x,100,20 )
physics.addBody( ball, “dynamic”, { friction=1,bounce=0,density=3,radius=20 } )
– *** END OF NEW CODE ***
– TOUCH TO DRAG FUNCTION
local function dragBody(e)
local body = e.target
local phase = e.phase
local stage = display.getCurrentStage()
if(phase == “began”) then
stage:setFocus(body, e.id)
body.isFocus = true
body.tempJoint = physics.newJoint(“touch”, body, e.x, e.y)
elseif(phase == “moved”) then
if(body.tempJoint ~= nil) then
body.tempJoint:setTarget(e.x, e.y)
end
elseif(phase == “ended” or phase == “cancelled”) then
if(body.tempJoint ~= nil) then
stage:setFocus(body, nil)
body.isFocus = false
body.tempJoint:removeSelf()
body.tempJoint = nil
end
end
return true
end
box:addEventListener(“touch”, dragBody)
ball:addEventListener(“touch”, dragBody) — *** NEW ***
– FLOAT/BUOYANCY FUNCTION
local function float()
if (box.y + (box.height * 0.5)) >= water.y then
local submergedPercent = math.floor (100 - (((water.y - box.y + (box.height * 0.5)) / box.height) * 100))
if submergedPercent > 100 then
submergedPercent = 100
end
if submergedPercent > 40 then
local buoyancyForce = (box.mass * gy)
box:applyForce( 0, buoyancyForce * -0.002, box.x, box.y )
box.linearDamping = 4
box.angularDamping = 5
else
box.linearDamping = 0
box.angularDamping = 0
end
end
end
–Runtime:addEventListener( “enterFrame”, float ) – *** COMMENTED OUT ***[/lua]
[import]uid: 8271 topic_id: 16060 reply_id: 60127[/import]