Pulling Physics Objects Towards Another Physics Object??

Is there any possible way to somehow pull a physics body towards another body if they are in a certain radius from the other physics body? Trying to make it as a challenge for my game.

Thanks :slight_smile:

Instead of pulling, try pushing. You can use physics.applyForce to the opposite side of the body.

yes it’s possible, but first allow me to break down the workflow

every update loop the physics world will make bodies react to each other based on their positions and velocities (and other properties, gravity etc)

so every update() a physics body will report its current state based on the world of the physics interactions

you can override most of these properties, for example you can set the x and y position of the body directly, but this means you will not be accounting for complex interactions so that’s why most guides say stay away from direct manipulation, but there’s nothing stopping you

so if you wanted to create an attractor object, you would just adjust the x,y position of a body that is attracted by an amount appropriate for the attraction strength, so if my attractor was at position x = 100, y = 100 and my object was at 0,0 i would add say 10 and 10 to the x and y so that next update it is 10 pixels closer to the attractor on each axis

@skar is there a “rubber band” joint that can pull bodies together?

@UberGoober not that i can see, i would just use direct x,y manipulation for this, it’s not much to add, you can make a Body class and wrap the physics.body in custom functions and identifiers, it’s how i have my own Hitboxes and GravityBox classes in my game project

@skar sure, but like you said, doing it the brute-force way robs the physics simulation of its ability to react realistically to lots of different forces at once. I’m honestly surprised there’s no rubber-band style connector, it seems like it’d be a very common request.

i’m not sure why either, maybe an over sight because “gravity” had already been considered done and part of the physics world,

but that’s really what we’re talking about, adding an unseen force every frame that slightly moves that physics body, it’s not too far out of scope i think, that’s all the physics engine does in the back end anyway, just processes the bodies and sets their new x,y, velocity values, if you know what you’re doing you can manipulate anything

@skar, I’m still not quite sure how to do that. Is it possible for you to make an example so that I can fully understand what you’re trying to say??

Wait wait wait—in @John’s Physics Lab built-in example, all the objects can be dragged around with a touch, and they lag a little bit behind the touch as if they’re being pulled around by a rubber band.

Go dig in thar, son! :wink:

I’ve poked at it a little myself and I can maybe give you a pointer or two: what John does is that when a touch starts on a physics body, he makes a table with the touch and the body in it and puts that table into debugDraw’s touchMap table, and then in the debugDraw.draw() function he looks at each touch/body pair in the touchMap table, and then applies forces to the body to make it head towards the position of the touch.

here’s a simple example that just adds 10 to the x position, you can make it much more complex by passing custom update functions and parameters

function setup()
  myBody = Body()
end
function draw()
  myBody:update(100, 100)
end

Body = class()
function Body:init()
  self.body = physics.body()
  self.body.x = 0
  self.body.y = 0
  self.prevX = 0
  self.prevY = 0
end

function Body:update()
  self.prevX = self.body.x
  self.body.x = self.prevX + 10

end




Here’s an example using distance joint.

viewer.mode=STANDARD

function setup() 
    c1 = physics.body(CIRCLE,50)
    c1.x=WIDTH/2
    c1.y=200
    c1.sleepingAllowed=false
    
    c2 = physics.body(CIRCLE,50)
    c2.x=WIDTH/2
    c2.y=800
    c2.type=STATIC
    c2.sleepingAllowed=false
    
    j1=physics.joint(DISTANCE,c1,c2,c1.position,c2.position)    
    d=j1.length
    
    stroke(255)
    strokeWidth(1)
    noFill()   
end

function draw()
    background(30, 30, 30, 25)    
    ellipse(c1.x,c1.y,100)    
    ellipse(c2.x,c2.y,100)
    text(j1.length,WIDTH/2,HEIGHT/2)
    if d>=0 then
        d=d-1
    end
    j1.length=d
end

Here’s another example.

viewer.mode=FULLSCREEN

function setup() 
    c1 = physics.body(CIRCLE,50)
    c1.x=WIDTH/2
    c1.y=HEIGHT-100
    c1.sleepingAllowed=false
    
    c2 = physics.body(CIRCLE,50)
    c2.x=WIDTH/2
    c2.y=HEIGHT-50
    c2.type=STATIC 
       
    d=0
    stroke(255)
    strokeWidth(1)
    fill(255)   
end

function draw()
    background(30, 30, 30, 25)    
    ellipse(c1.x,c1.y,100)    
    ellipse(c2.x,c2.y,100)
    if d>=0 and j1~=nil then
        d=d-1
        j1.length=d       
    end
    text("tap screen to cause pull",WIDTH/2,HEIGHT/2)
end

function touched(t)
    if t.state==BEGAN then
        j1=physics.joint(DISTANCE,c1,c2,c1.position,c2.position)    
        d=j1.length        
    end
end

@dave1707 this is very odd: on my iPhone 8, running your first example, I only see one circle, and I don’t see the text that should print in the middle of the screen at all. Your second example works fine though.

@UberGoober Change the c2.y from 800 to HEIGHT-50. Change the noFill to fill(255) . I code on my iPad Air 3 in portrait orientation and forget that others use different orientations and devices.