-- Physics stage 4: the Duck as a convex hull rolling down a ramp, a torus as a static mesh shape -- the ball rolls around, a swinging door on a hinge with limits, a pendulum on a ball joint, and -- a crate on a slider. local font = fontLoad("Singe/FreeSansBold.ttf", 28) local frames = 0 fontSelect(font) discPlay() sceneEnable(true) sceneSetBackground(18, 18, 30, 255) sceneSetAmbient(70, 70, 85) local floorLook = materialNew() materialSetColor(floorLook, 120, 110, 100) materialSetRoughness(floorLook, 0.9) local rampLook = materialNew() materialSetColor(rampLook, 90, 100, 130) local doorLook = materialNew() materialSetColor(doorLook, 160, 90, 40) local ballLook = materialNew() materialSetColor(ballLook, 60, 140, 230) local ringLook = materialNew() materialSetColor(ringLook, 220, 200, 60) materialSetMetallic(ringLook, 0.8) materialSetRoughness(ringLook, 0.35) local frameLook = materialNew() materialSetColor(frameLook, 40, 40, 50) local crateLook = materialNew() materialSetColor(crateLook, 200, 140, 60) local floor = nodeNew() nodeSetMesh(floor, meshBox(16, 0.2, 16), floorLook) nodeSetPosition(floor, 0, -1.9, 0) bodyNew(floor, BODY_STATIC, SHAPE_BOX, 16, 0.2, 16) -- A ramp, and the Duck as a convex hull rolling down it. local ramp = nodeNew() nodeSetMesh(ramp, meshBox(3.0, 0.2, 2.2), rampLook) nodeSetPosition(ramp, -3.4, -1.0, -1.0) nodeSetRotation(ramp, 0, 0, -28) bodyNew(ramp, BODY_STATIC, SHAPE_BOX, 3.0, 0.2, 2.2) local duck = modelInstance(modelLoad("testScripts/Models/Duck.glb")) nodeSetPosition(duck, -4.4, 0.6, -1.0) nodeSetRotation(duck, 0, 90, 0) nodeSetScale(duck, 0.6) bodyNew(duck, BODY_DYNAMIC, SHAPE_HULL) bodySetFriction(duck, 0.4) -- A torus lying on the floor as a static triangle mesh; the ball rolls around inside it. local ring = nodeNew() nodeSetMesh(ring, meshTorus(1.2, 0.25, 40), ringLook) nodeSetPosition(ring, 2.6, -1.55, 0.6) bodyNew(ring, BODY_STATIC, SHAPE_MESH) local ball = nodeNew() nodeSetMesh(ball, meshSphere(0.3, 32), ballLook) nodeSetPosition(ball, 2.6, 1.2, 0.6) bodyNew(ball, BODY_DYNAMIC, SHAPE_SPHERE, 0.3) bodySetBounce(ball, 0.4) -- A door hinged to the world along its left edge, limited to swing 100 degrees one way. local post = nodeNew() nodeSetMesh(post, meshBox(0.15, 2.4, 0.15), frameLook) nodeSetPosition(post, -1.0, -0.6, 1.4) bodyNew(post, BODY_STATIC, SHAPE_BOX, 0.15, 2.4, 0.15) local door = nodeNew() nodeSetMesh(door, meshBox(1.4, 2.2, 0.1), doorLook) nodeSetPosition(door, -0.1, -0.62, 1.4) bodyNew(door, BODY_DYNAMIC, SHAPE_BOX, 1.4, 2.2, 0.1) bodySetMass(door, 8) local hinge = jointHinge(door, -1, -0.85, -0.62, 1.4, 0, 1, 0) jointSetLimits(hinge, 0, 100) -- A pendulum: a ball hanging from a point in the air. local bob = nodeNew() nodeSetMesh(bob, meshSphere(0.25, 24), ballLook) nodeSetPosition(bob, 1.4, 1.6, -1.6) bodyNew(bob, BODY_DYNAMIC, SHAPE_SPHERE, 0.25) jointBall(bob, -1, 0.2, 2.6, -1.6) -- A crate on a slider along X, pushed sideways at the start. local rail = nodeNew() nodeSetMesh(rail, meshBox(3.0, 0.08, 0.08), frameLook) nodeSetPosition(rail, 0.6, 0.9, -3.0) local crate = nodeNew() nodeSetMesh(crate, meshBox(0.5, 0.5, 0.5), crateLook) nodeSetPosition(crate, -0.6, 0.9, -3.0) bodyNew(crate, BODY_DYNAMIC, SHAPE_BOX, 0.5, 0.5, 0.5) local slider = jointSlider(crate, -1, -0.6, 0.9, -3.0, 1, 0, 0) jointSetLimits(slider, 0, 2.4) bodySetVelocity(crate, 3, 0, 0) local sun = lightNew(LIGHT_DIRECTIONAL) nodeSetPosition(sun, -3, 6, 4) nodeLookAt(sun, 0, 0, 0) lightSetIntensity(sun, 1.2) lightSetShadow(sun, true) local camera = nodeNew() nodeSetPosition(camera, 0.8, 2.4, 7.5) nodeLookAt(camera, 0, -0.4, -0.5) cameraSet(camera) cameraSetPerspective(52, 0.1, 100) function onOverlayUpdate() frames = frames + 1 overlayClear() fontPrint(20, 20, "Physics joints and hulls, frame " .. frames) if frames == 40 then -- Kick the door and the pendulum. bodyApplyImpulse(door, 0, 0, -60, 0.5, -0.62, 1.45) bodyApplyImpulse(bob, 6, 0, 0) end if frames == 30 or frames == 90 or frames == 180 then singeScreenshot() end if frames == 200 then local dx, dy, dz = nodeGetWorldPosition(duck) local cx = nodeGetWorldPosition(crate) debugPrint(string.format("RESULT duck %.2f %.2f %.2f crate x %.2f", dx, dy, dz, cx)) singeQuit() end end