Howdy, Stranger!

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

Draggable physics objects.

edited September 2012 in General Posts: 3

How do I write a physics body that can be dragged with touch. Like the hockey pucks in touch hockey.

Tagged:

Comments

  • Have a look at the Physics Lab example that comes with Codea. Test 1 allows you to drag physics bodies.

  • Yes, I saw the physics lab example but when I drag the objects, they don't follow my finger it’s as if there was a rubber band between them and my finger. What I want is for the object to be below my finger in real time.

    I could just set the bodies position to by my finger’s position, but that would lead to non-physical behavior because, the speed would be zero or some other value.

  • edited September 2012 Posts: 489

    Hello @kilobyte. You are correct that the PhysicsDebugDraw:draw() function models a 'rubber band' between the anchor and the touch, together with a drag on linear velocity (only, there is no drag on angular velocity).

    Perhaps you need to model different behaviour: (1) a force applied to the centre of mass (to avoid torque) in the same direction as that from the anchor to the touch, that increases rapidly in strength as the distance between the touch and the anchor increases; (2) a damping effect that is strong when the distance between the touch and the anchor is small; and (3) perhaps, the effect of a touch that has ended is considered to be complete only once the anchor reaches the point where the touch was when it ended.

    (Update) Having experimented, the basic problem is this:

    A finger can move very rapidly over the surface of the viewer. A body with mass that follows such a finger closely can have very significant kinetic energy, with corresponding implications for any other bodies that it collides with. Perhaps, given that, in your circumstances, 'non-physical' behaviour is more desirable than physical behaviour.

  • I think the best quote that refers to the problem with setting the position is, “If you manually set the position of a body, then you are teleporting the body.” In other words when I set the position, no collision detection happens.

  • JohnJohn Admin Mod
    Posts: 584

    What you want is a critically dampened spring system. The issues comes with the amount of force you apply to maintain the bodies position. If the force is too low you get oscillation, if it's too high you get overshooting. Getting it right is mainly about tweaking, but as @mpilgrem says you won't get 1:1 movement without some serious amount of kinetic energy, which means you'll likely cause high energy collisions, making things fly away at high speeds. I'd say look at the code in PhysicsLab that applies the force but try tweaking the values to get faster response and less oscillation then use it in your own project.

  • PTNPTN
    Posts: 39

    In addition to @John 's critically dampened spring system:
    This is a well known design issue in many engineering problems.
    There's a real world-parameter (the position of an object) that needs to follow a target value (the touch position). This requires a control system, one which a system- and controlsengineer could design. See: http://en.wikipedia.org/wiki/Control_engineering

    The basics is this:
    The difference between the actual, current value and the wanted, target value is called the Errorsignal. The bigger this number, the farther off your object is.
    This number is then used to compute a Force that aims to decrease the Errorsignal. If the errorsignal is zero, the object is in place.
    The trick is designing an algorithm that computes this Force. The physics example uses a simple lineair gain (Force = Error * constant) and includes a dampening force.
    A PID controller may improve the response a lot.

  • The above said is absolutelay true for dynamic objects. Maybe you sometimes want to drag static objects like obstacles too. in that case you also cant move the object directly, but you can simply delete the object at the old position and recreate it at the new position. but you should also be careful dragging it not too,fast to not move dynamic objects into your static objects. for my project it was no problem as i only had thin lines and it was ok, if the ball goes through the line when i move the line fast over the ball. This would not work for dynamic objects e.g. for a racket, as you would loose the kinetic energy.

  • edited September 2012 Posts: 371

    Is this what you are looking for?

    function setup()
        watch("CurrentTouch.deltaX")
        ball = physics.body(CIRCLE, 50)
        ball.x = WIDTH / 2
        ball.y = HEIGHT / 2
        physics.gravity(0,0)
        walls = { 
            physics.body(EDGE, vec2(0, 0), vec2(WIDTH, 0)),
            physics.body(EDGE, vec2(0, 0), vec2(0, HEIGHT)),
            physics.body(EDGE, vec2(WIDTH, HEIGHT), vec2(WIDTH, 0)),
            physics.body(EDGE, vec2(WIDTH, HEIGHT), vec2(0, HEIGHT)),
        }
        for k, v in ipairs(walls) do
            v.restitution = 1
        end
        bodies = {}
        for i = 1, 100 do
            bodies[i] = physics.body(CIRCLE, 10)
            bodies[i].position = vec2(math.random(WIDTH), math.random(HEIGHT))
        end
    end
    
    function draw()
        background(0, 0, 0, 255)
        fill(255, 255, 0, 255)
        ellipse(ball.x, ball.y, 100)
        ball.linearVelocity = vec2(0,0)
        fill(255, 0, 0, 255)
        for k, v in ipairs(bodies) do
            ellipse(v.x, v.y, 20)
        end
    end
    
    function touched(touch)
        if touch.state == MOVING then
            ball.linearVelocity = vec2(touch.deltaX, touch.deltaY) / DeltaTime
        end
    end
    
  • PTNPTN
    Posts: 39

    Here's a really, really, really, crude simulation of a PID controller.
    You can experiment with the different parameters.

    -- PID Controller
    function setup()
        radius = 50
        Body = physics.body(CIRCLE, radius) 
        Body.type = DYNAMIC
        Body.position = vec2(WIDTH/2,HEIGHT/2)
        Body.gravityScale = 0 
        
        target = vec2(0,0)
        touching = false
        E = vec2(0,0)
        D = vec2(0,0)
        Force = vec2(0,0)
        integral = vec2(0,0)
        olderr = vec2(0,0)
         
        parameter("DGain",0,2,1) -- strength of the friction
        parameter("EGain",0,2,1) -- overall strength of the control
        parameter("EP",0,2,1) -- strength of the lineair component
        parameter("EI",0,2,1) -- strength of the integral component
        parameter("EIt",0,2,1) -- speed of the integral component
        parameter("ED",0,100,1) -- strength of the differential component
        parameter("EDt",0,2,1) -- sensitivity of the differential component
    end
    
    function draw()
        background(0, 0, 0)
        stroke(255,255,255,255)
        strokeWidth(2)
        fill(125,125,125,255)
        ellipse(Body.x,Body.y,radius)
        
        updatebody()
    end
    
    function touched(touch)
        if touch.state == ENDED then 
            touching = false
            integral = vec2(0,0)
        else
            touching = true
            target.x = touch.x
            target.y = touch.y
        end
    end
    
    function updatebody()
        if touching == true then 
            -- compute E
            local Error = target - Body.position 
            E = Errorsignal(Error)
        else
            -- no E - force
            E = vec2(0,0)
        end
        D = Friction()
        Force = E + D
        Body:applyForce(Force)
    end
    
    -- computes a force dependant on the Error (difference between target and actual position)
    function Errorsignal(Err)
        return (Err * EP + EI*Icontroller(Err) + ED*Dcontroller(Err) ) * EGain
    end
    
    -- computes the friction force
    function Friction()
        local anchor  = Body.position
        local velocity = Body:getLinearVelocityFromWorldPoint(anchor)
        local friction = -1 * velocity * DGain
        return friction
    end
    
    -- simulates an integral controller. the longer object is off-target, the bigger the steering.
    -- good for eliminating static offsets, bad for stability
    function Icontroller(Err)
        integral = integral + Err * EIt * DeltaTime
        return integral
    end
    
    -- simulates a differential controller. reacts on the speed with which Err changes.
    -- good for tracking fast changes & stability. Not so good at static offsets
    function Dcontroller(Err)
        local diff = (Err - olderr) * EDt * DeltaTime
        olderr = Err
        return diff
    end
    
Sign In or Register to comment.