Physics for door opening and closing

I know I’m doing something wrong here, I just can’t figure out what it is… In the code below, there is a “door” attached to 2 “frames” on each end of the door. When you touch the door it swings open. There is a timer to close it after 1 second.

That all works, but there are 2 problems:

  1. When the door swings back into place it gets misaligned and looks goofy.
  2. The joint doesn’t re-attach even though the code is there to reconnect it.

Any help would be much appreciated! :slight_smile:

Dave

-- main.lua  
  
local physics = require("physics")  
physics.start()  
  
local test = display.newText("touch the door", 75, 40, "Courier", 20)  
test:setTextColor(255, 255, 255, 255)  
  
-- globals  
joint1 = {}  
joint2 = {}  
frame1 = {}  
frame2 = {}  
  
local door = {}  
local doorHeight = 10  
local frameWidth = 20  
local frameHeight = 10  
local frame1X = 100  
local frame1Y = 150  
local frame2X = 210  
local frame2Y = 150  
local doorX  
local doorY  
local doorResetTimer = {}  
  
function doorResetTimer( event )  
 -- return the door back to original position  
 transition.to( door, { time=500, rotation=0.2, x=doorX, y=doorY } )  
  
 -- reconnect the joint  
 door["joint2"] = physics.newJoint( "pivot", frame2, door, doorX + door.width/2, doorY )  
 door["joint2"].isLimitEnabled = true  
 door["joint2"]:setRotationLimits( -90, -0 )  
  
 timer.cancel( doorResetTimer )  
end  
  
function openDoor( event )  
 local t = event.target  
 local phase = event.phase  
  
 if "ended" == phase then  
 door["joint2"]:removeSelf()  
  
 -- reset the door position  
 doorResetTimer = timer.performWithDelay( 1000, doorResetTimer, 1 )  
 end  
end  
local frame1 = display.newRect(0, 0, frameWidth, frameHeight)  
frame1:setFillColor(0, 0, 200, 255)  
frame1.x = frame1X; frame1.y = frame1Y  
physics.addBody( frame1, "static", { friction=0.5 } )  
  
local frame2 = display.newRect(0, 0, frameWidth, frameHeight)  
frame2:setFillColor(0, 0, 200, 255)  
frame2.x = frame2X; frame2.y = frame2Y  
physics.addBody( frame2, "static", { friction=0.5 } )  
  
door = display.newRect( frame1X, frame1Y - doorHeight/2, frame2X - frame1X, doorHeight )  
door:setFillColor(0,255,0,255)  
physics.addBody( door, { density=1.8, friction=0.3, bounce=0.3 } )  
doorX = door.x; doorY = door.y  
  
door["joint1"] = physics.newJoint( "pivot", frame1, door, door.x - door.width/2, door.y )  
door["joint1"].isLimitEnabled = true  
door["joint1"]:setRotationLimits( 0, 90 )  
door["joint2"] = physics.newJoint( "pivot", frame2, door, door.x + door.width/2, door.y )  
door["joint2"].isLimitEnabled = true  
door["joint2"]:setRotationLimits( -90, -0 )  
door:addEventListener( "touch", openDoor )  
-- config.lua  
  
application =  
{  
 content =  
 {  
 width = 320,  
 height = 480,  
 scale = "zoomEven"  
 },  
}  

[import]uid: 8194 topic_id: 1923 reply_id: 301923[/import]

Mr. Knell of the clan McKnells?
Mr DW here, if you are…
[import]uid: 8683 topic_id: 1923 reply_id: 5716[/import]

@squiffy

Huh??? [import]uid: 8194 topic_id: 1923 reply_id: 5717[/import]

Sorry, thought you might be a Dave Knell I knew (Coulomb).
If you were, I was just saying hi.
If you’re not then I was just making a load of incomprehensible drivelly sounds.

Many apalowgees for the inconweenience :slight_smile:
[import]uid: 8683 topic_id: 1923 reply_id: 5718[/import]

@dknell – your problem is here:

-- return the door back to original position  
transition.to( door, { time=500, rotation=0.2, x=doorX, y=doorY } )  

In general, it’s a bad idea to start pushing manual transitions onto a dynamic physics object that is already under the effect of simulated forces and constraints. In this case, you’ve got two things fighting each other:

(1) The door is a physics object with a pivot point at one end, and it’s trying to swing downwards under gravity.

(2) After one second of swinging down, when it’s still in motion, you’re applying a Corona “rotation” transition to it. Recall that Corona rotations will default to rotating a display object around its CENTER point. So the door tries to pivot around its center point, but it’s still attached at one end!

What happens next is that the two control systems fight each other, so you get that weird “jump” while it’s trying to swing. Then, your code wants to reattach the 2nd joint, but at that moment in time the door is nowhere near being closed, so then it creates a joint between the doorframe and some point way out in space (relative to the door). From that moment on, everything the door does will be pretty weird!

The fix is to avoid having two control schemes fighting each other:

  • You could set the door’s bodyType to “kinematic” during that “transition.to” period, so that it is temporarily removed from physical simulation and can be pushed around manually. Remember to also set the reference point of the door to where the hinge is, or Corona will simply pivot the door around its center point. Also remember to set its bodyType back to “dynamic” when the manual transition is over. This is similar to the technique shown in “DragPlatforms”, where the objects are set to “kinematic” during a drag so they can be pushed around with no physical limitations.

  • In this specific case, the physics engine is probably overkill, and you could simulate this behavior with Corona tweening and rotation (after setting the reference point to the left side of the door, so it rotates around that). But I assume the door is just an example.

[import]uid: 3007 topic_id: 1923 reply_id: 5881[/import]

Thanks Evan!

That totally makes sense - I guess I thought I could just fight gravity! :slight_smile:

Anyway, I will change the reference point and try your 2 suggestions (change the door physics type to kinematic; try using Corona’s tweening) and see which one works best for my project.

I will post the modified code here if anyone else is interested.

Dave [import]uid: 8194 topic_id: 1923 reply_id: 5889[/import]

I ended up going with the tweening method because as Evan mentioned the physics approach was overkill and required a little more code.

Here is the correct code to open and close a door using tweening if anyone is interested.

[code]
– main.lua

– uses scarnie’s extended easing library
http://developer.anscamobile.com/code/more-easing
local easingx = require(“easingx”)

local test = display.newText(“touch the door”, 75, 40, “Courier”, 20)
test:setTextColor(255, 255, 255, 255)

– globals
frame1 = {}
frame2 = {}

local door = {}
local doorHeight = 10
local frameWidth = 20
local frameHeight = 10
local frame1X = 100
local frame1Y = 150
local frame2X = 210
local frame2Y = 150
local doorX
local doorY
local doorResetTimer = {}
function doorClose( event )
local function enableTouch( even )
door:addEventListener( “touch”, openDoor )
door.open = false
end

transition.to( door, { time=500, delay=500, rotation=0, transition=easingx.easeOut, onComplete=enableTouch } )
end
function openDoor( event )
local t = event.target
local phase = event.phase

if ( t.open == false ) then

if “began” == phase then
– nothing to do here
elseif “ended” == phase then
door.open = true

door:removeEventListener( “touch”, openDoor )

door:setReferencePoint( display.CenterLeftReferencePoint )
transition.to( door, { time=1200, rotation=90, transition=easingx.easeOutBounce, onComplete=doorClose } )

end

end
end
local frame1 = display.newRect(0, 0, frameWidth, frameHeight)
frame1:setFillColor(0, 0, 200, 255)
frame1.x = frame1X; frame1.y = frame1Y

local frame2 = display.newRect(0, 0, frameWidth, frameHeight)
frame2:setFillColor(0, 0, 200, 255)
frame2.x = frame2X; frame2.y = frame2Y

door = display.newRect( frame1X, frame1Y - doorHeight/2, frame2X - frame1X, doorHeight )
door:setFillColor(0,255,0,255)
doorX = door.x; doorY = door.y
door.open = false

door:addEventListener( “touch”, openDoor )
[/code] [import]uid: 8194 topic_id: 1923 reply_id: 5892[/import]