#### 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: 791

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

• Mod
Posts: 8,622

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

• Mod
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[1]
local p2 = edge.points[2]
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[1]
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[1]
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
``````
• Mod
Posts: 8,622

@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.

• Mod
Posts: 8,622

@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.

• Mod
Posts: 8,622

@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.

• Mod
Posts: 8,622

@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
``````
• Mod
Posts: 8,622

@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.

• Mod
Posts: 8,622

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