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