3D Physics Problem

Below is my code for a punching bag that I created with an artificial revolute constraint. However, I find that if I change the x or z position of the bag and the hinge point (the point that the bag pivots around, a.k.a the constraint), the rotation and movement of the bag suddenly gets really haywire. Like it doesn’t rotate on the z axis anymore, and it starts spinning really, REALLY fast. Can someone please explain to me why this is happening and how I can fix it?

Kind regards,
Creator27 :slight_smile:

Main:

-- 3D Car

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    ragdoll = Ragdoll(vec3(0, 1.5, 0), vec3(0, 2.5, 0), vec3(1, 2, 0.5))
    -- ground
    ground = scene:entity()
    ground.model = craft.model.plane(vec2(100, 100))
    ground.material = craft.material(asset.builtin.Materials.Standard)
    ground.material.diffuse = color(128)
    ground.position = vec3(0, 0, 0)
    ground:add(craft.rigidbody, STATIC, 1)
    ground:add(craft.shape.model, ground.model)
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
    local cameraTargetDist = vec3(0, 0, -8.5)
    local newPoint = ragdoll.body:transformPoint(cameraTargetDist)
    scene.camera.position = lerp(scene.camera.position, vec3(0, 1, -8), 0.1)
    ragdoll:update(dt)
    local dir = (ragdoll.body.position - scene.camera.position)
    local rot = quat.lookRotation(dir, vec3(0, 1, 0))
    
end

function lerp(a, b, t)
    return vec3(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t)
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
    ragdoll:draw()
end

function touched(touch)
    ragdoll:touched(touch)
end

Ragdoll:

Ragdoll = class()

function Ragdoll:init(pos, anchorPos, size)
    -- Initialize the body of the punching bag
    self.body = scene:entity()
    self.body.model = craft.model.cube(size)
    self.body.material = craft.material(asset.builtin.Materials.Standard)
    self.body.material.diffuse = color(255, 50, 0)
    self.body.position = pos
    -- Physics
    self.rb = self.body:add(craft.rigidbody, DYNAMIC, 1)
    self.rb.sleepingAllowed = false
    self.rb.linearDamping = 1
    self.rb.angularDamping = .5
    self.body:add(craft.shape.box, size)
    -- Create an anchor point
    self.anchor = self.body:transformPoint(vec3(0, size.y / 2, 0))
    self.rbSize = size
    -- Restoring force parameters
    self.uprightTorqueMagnitude = 10
    self.damping = 0.5
end

function Ragdoll:inverse(quaternion)
    -- Helper function that calculates the inverse of a quaternion
    local con = quaternion:conjugate()
    local len = con:lenSqr()
    return quat.eulerAngles(con.x / len, con.y / len, con.z / len)
end

function Ragdoll:update(dt)
    -- Create a torque that attempts to keep the bag upright
    local delta = self:inverse(self.body.rotation) * quat.eulerAngles(0, 0, 0)
    local deltaAngles = delta:angles()
    local worldAngles = self.body:transformDirection(deltaAngles)
    self.rb:applyTorque(25 * worldAngles - 0.01 * self.rb.angularVelocity)
    -- Calculate the offset from the bag to the hinge, and subtract it from the bag's position
    local offset = self.body:transformPoint(vec3(0, self.rbSize.y / 2, 0)) - self.anchor
    self.body.position = self.body.position - offset
    -- Apply damping to simulate air resistance
    
end

function Ragdoll:draw()
    -- Codea does not automatically call this method
    local pos1 = scene.camera:get(craft.camera):worldToScreen(self.body.position)
    local pos2 = scene.camera:get(craft.camera):worldToScreen(self.anchor)
    stroke(128, 75, 0)
    strokeWidth(5)
    line(pos1.x, pos1.y, pos2.x, pos2.y)
end

function Ragdoll:touched(touch)
    -- Codea does not automatically call this method
     -- Apply force to simulate hitting the punching bag
     if touch.state == BEGAN then
        local origin, dir = scene.camera:get(craft.camera):screenToRay(touch.pos)
        local hit = scene.physics:raycast(origin, dir, 1000)
        if hit and hit.entity ~= ground then
            local dir = (self.body.position - hit.point):normalize()
            self.rb:applyForce(hit.normal * 100, hit.point)
        end
    end
end

@creator - not sure what you mean about changing your position. Changed a few parameter x positions in ragdoll but tapping it on screen always gives similar response.

The only other parameter I can see to change are the camera and the lerp.

Could you explain the purpose of the lerps function. I have only used lerps in graphical functions to introduce colour gradients etc.