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 ?
You could try setting the body’s linearVelocity.x property to 0 each draw. Might work but without code I can’t test
@LightDye - if your objects are simple enough, you could roll your own physics code. I have a series of posts on this.
There’s no need to roll your own physics, I believe a PRISMATIC joint should do the trick.
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
@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
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.
@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.
@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
@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)
debugDraw:addJoint(joint)
local circle2 = createCircle(WIDTH/2, HEIGHT/2 - 125, 25)
local distJoint = physics.joint(DISTANCE, box, circle2, box.position, circle2.position)
debugDraw:addJoint(distJoint)
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
debugDraw:addJoint(sliderJoint)
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.
@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.
@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
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
@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))
@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.