Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

How to constraint physics to 1 dimension?

edited March 2014 in General Posts: 57

Is there any way to constraint the physics of a body to 1 dimension, for example the Y axis, without setting its position artificially? What I'd like to have is an object that only moves vertically while interacting with other objects that move freely in 2D. Is this possible without incurring in the teleporting problem described here: http://twolivesleft.com/Codea/Talk/discussion/1731/draggable-physics-objects/p1 ?

Tagged:

• Posts: 738

You could try setting the body's linearVelocity.x property to 0 each draw. Might work but without code I can't test

• Posts: 7,809

@West I tried that already and it didn't work.

• Posts: 5,396

@LightDye - if your objects are simple enough, you could roll your own physics code. I have a series of posts on this.

• edited March 2014 Posts: 580

There's no need to roll your own physics, I believe a PRISMATIC joint should do the trick.

• Posts: 57

Thank you all for replying. @toadkick could you please elaborate further? I'm experimenting with the code below. A ball will be created at touch point. I'd like to keep the ball at the same X position while it is pushed upwards by the weaves

function setup() parameter.number("speed", 0, 50, 5) parameter.integer("segments", 1, 100, 5) parameter.number("fraction", 0.1, 1, 1) parameter.number("height", 0, HEIGHT, HEIGHT/2) parameter.boolean("debug", false) parameter.watch("a") r = 20 end function draw() background(40, 40, 50) strokeWidth(2) stroke(255, 255, 255, 255) fontSize(15) if ball ~= nil then ellipse(ball.x, ball.y, 2*r) end calculate() doEdges() for _,edge in ipairs(edges) do local p1 = edge.points local p2 = edge.points line(p1.x, p1.y, p2.x, p2.y) end if debug then debugDraw() end end function debugDraw() pushStyle() stroke(255, 0, 0, 255) p1 = points for i = 2,#points do p2 = points[i] line(p1.x, p1.y, p2.x, p2.y) fill(255, 0, 0, 255) ellipse(p1.x, p1.y, 30) fill(255, 255, 255, 255) text(i-1, p1.x, p1.y) p1 = p2 end popStyle() end function calculate() deltaX = WIDTH / segments deltaA = 2 * math.pi / segments * fraction points = {} a = math.fmod(ElapsedTime * speed / math.pi, 180) for x = 0,WIDTH*2,deltaX do local y = math.sin(a) * height / 2 + height / 2 table.insert(points, vec2(x,y)) a = a + deltaA end end function doEdges() destroyEdges() physics.pause() edges = {} p1 = points for i = 2,#points do p2 = points[i] table.insert(edges, doEdge(p1, p2)) p1 = p2 end physics.resume() end function doEdge(p1, p2) local edge = physics.body(EDGE, p1, p2) edge.type = STATIC return edge end function destroyEdges() if edges ~= nil then physics.pause() for _,edge in ipairs(edges) do edge:destroy() end edges = nil collectgarbage() physics.resume() end end function touched(touch) if touch.state == ENDED then ball = physics.body(CIRCLE, r) ball.x = touch.x ball.y = touch.y ball.gravityScale = 1 ball.restitution = 0 end end
• Posts: 7,809

@LightDye I tried using PRISMATIC as suggested by@toadkick, but I couldn't get it to work right. So I tried using EDGE. Try the touched function I have below.

function touched(touch) if touch.state == ENDED then ball = physics.body(CIRCLE, r) ball.x = touch.x ball.y = touch.y ball.gravityScale = 1 ball.restitution = 0 e1=physics.body(EDGE,vec2(touch.x-20,0),vec2(touch.x-20,HEIGHT)) e2=physics.body(EDGE,vec2(touch.x+20,0),vec2(touch.x+20,HEIGHT)) end end
• edited March 2014 Posts: 1,595

I use prismatic for the slider joint in my builder game, it is exactly what you are looking for, it works like this, physics.joint(PRISMATIC,bodyA,bodyB,position,direction) the direction you specify determines which way the body constrained can travel (in all cases of physics.joint bodyB is affected) directly. This can create the piston effect and many other fixed direction travel possibilities.

• Posts: 7,809

@Luatee That's exactly what I tried doing and the ball just got pushed off the screen by the wave. Maybe I wasn't doing something right, there wasn't any documentation on how the direction was supposed to be used.

• Posts: 1,595

@dave1707 it isn't covered that well in codea reference so I checked the box2d reference for how it worked, it's very versatile and bug free from my experience, allowing you to set a lower limit and an upper limit to constrict its movement along the 1d axis

• edited March 2014 Posts: 580

@LightDye @dave1707 @Luatee: "Test2" in the "Physics Lab" example project shows how to set up a prismatic joint.

Here's the setup() function for instant gratification:

function Test2:setup()
createGround()

local circle = createCircle(WIDTH/2, HEIGHT/2, 25)
circle.type = STATIC

local box = createBox(WIDTH/2, HEIGHT/2 - 75, 25, 150)

local joint = physics.joint(REVOLUTE, circle, box, circle.position)

local circle2 = createCircle(WIDTH/2, HEIGHT/2 - 125, 25)
local distJoint = physics.joint(DISTANCE, box, circle2, box.position, circle2.position)

local box2 = createBox(WIDTH/2 + 100, HEIGHT/2, 50, 50)
local sliderJoint = physics.joint(PRISMATIC, circle, box2, box2.position, vec2(1,0))
sliderJoint.enableLimit = true
sliderJoint.upperLimit = 50
end

The prismatic joint sliderJoint is set up so that it connects the dynamic body box2 to the static body circle, anchored at box2's initial position, and constrained to the x axis (vec2(1,0)). Additionally, it is set up to limit the translation to 50 pixels along the positive axis direction.

• Posts: 7,809

@toadkick Were you able to get that to work in the above program. I had the prismatic joint set up similar to that, but the ball was still pushed off the screen by the wave. In a test program, I had a joint set up that kept a bouncing ball going at a 45 degree angle. So the joint was done correctly, but when I tried something similar but only going up/down, it didn't work with the wave.

• Posts: 7,809

@LightDye @toadkick Change the touched() function to look like this. This uses the prismatic joint which I used in my test program that worked. When I originally added it to this program, I left out the STATIC line of code which didn't work. This one seems to work.

function touched(touch) if touch.state == ENDED then ball = physics.body(CIRCLE, r) ball.x = touch.x ball.y = touch.y ball.gravityScale = 1 ball.restitution = 0 b=physics.body(CIRCLE,10) b.x=touch.x b.y=HEIGHT b.type=STATIC j=physics.joint(PRISMATIC,b,ball,b.position,vec2(0,1)) end end
• edited March 2014 Posts: 57

Thanks @dave1707 and @toadkick, based on your lines I added the ones below. That keeps the ball in the screen but the joint acts as a rubber band stretching until the waves let the the joint pull the ball back to its original position. Still not the desired effect, but certainly an improvement.

anchor = physics.body(CIRCLE, 1)
anchor.position = vec2(touch.x, touch.y)
anchor.type = STATIC
constraint = physics.joint(PRISMATIC, anchor, ball, ball.position, vec2(0,1))
constraint.enableLimit = true
constraint.lowerLimit = 0
constraint.upperLimit = 10

• Posts: 7,809

@LightDye In your PRISMATIC line of code, you have the anchor parameter set to the ball position. The anchor point should be anchor.position. Try the code below.

constraint = physics.joint(PRISMATIC, anchor, ball, anchor.position, vec2(0,1))
• Posts: 57

@dave1707, thanks for keeping giving me ideas. I set the joint position to the anchor position but it didn't make any difference because it was exactly the same initial position of the ball. Then, as per your example, I changed the anchor position to be at HEIGHT but it didn't make much difference, except that when I debug-draw the joint it doesn't move for a while until the ball is taken out of the screen by the wave and from there it was acting as a rubber band hanging from the anchor point at the top of the screen.

• Posts: 7,809

@LightDye Comment out the 3 Limit lines of code and try again.