-- Physics stage 2: a stack of crates and a ball dropped onto the floor in front of the cabinet, -- then a kinematic paddle sweeps through the stack. 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 crateLook = materialNew() materialSetColor(crateLook, 200, 140, 60) materialSetRoughness(crateLook, 0.7) local ballLook = materialNew() materialSetColor(ballLook, 60, 140, 230) materialSetRoughness(ballLook, 0.3) local paddleLook = materialNew() materialSetColor(paddleLook, 230, 60, 40) local screen = materialNew() materialSetVideo(screen) materialSetUnlit(screen, true) local black = materialNew() materialSetColor(black, 25, 25, 28) local floor = nodeNew() nodeSetMesh(floor, meshBox(14, 0.2, 14), floorLook) nodeSetPosition(floor, 0, -1.9, 0) bodyNew(floor, BODY_STATIC, SHAPE_BOX, 14, 0.2, 14) -- A slab of a cabinet at the back with the disc on it, as a static body. local cabinet = nodeNew() nodeSetMesh(cabinet, meshBox(2.2, 3.0, 0.8), black) nodeSetPosition(cabinet, 0, -0.3, -2.5) bodyNew(cabinet, BODY_STATIC, SHAPE_BOX, 2.2, 3.0, 0.8) local tv = nodeNew(cabinet) nodeSetMesh(tv, meshPlane(1.8, 1.35), screen) nodeSetPosition(tv, 0, 0.5, 0.41) nodeSetRotation(tv, 90, 0, 0) local crates = {} for i = 1, 6 do local crate = nodeNew() nodeSetMesh(crate, meshBox(0.6, 0.6, 0.6), crateLook) nodeSetPosition(crate, -0.6 + (i % 2) * 0.05, -1.5 + (i - 1) * 0.62, 0.2) nodeSetRotation(crate, 0, (i - 1) * 7, 0) bodyNew(crate, BODY_DYNAMIC, SHAPE_BOX, 0.6, 0.6, 0.6) bodySetFriction(crate, 0.6) crates[i] = crate end local ball = nodeNew() nodeSetMesh(ball, meshSphere(0.35, 32), ballLook) nodeSetPosition(ball, 1.2, 3.0, 0.6) bodyNew(ball, BODY_DYNAMIC, SHAPE_SPHERE, 0.35) bodySetBounce(ball, 0.6) bodySetMass(ball, 2) local paddle = nodeNew() nodeSetMesh(paddle, meshBox(0.3, 1.2, 1.6), paddleLook) nodeSetPosition(paddle, -4.5, -1.2, 0.2) bodyNew(paddle, BODY_KINEMATIC, SHAPE_BOX, 0.3, 1.2, 1.6) 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, 3.5, 1.8, 6.5) nodeLookAt(camera, 0, -0.4, 0) cameraSet(camera) cameraSetPerspective(50, 0.1, 100) function onOverlayUpdate() frames = frames + 1 overlayClear() local bx, by, bz = nodeGetWorldPosition(ball) fontPrint(20, 20, string.format("Physics %d ball y=%.1f %s", frames, by, bodyIsResting(ball) and "resting" or "moving")) if frames >= 70 and frames < 160 then -- The paddle sweeps through the stack from the left. nodeMove(paddle, 0.07, 0, 0) end if frames == 40 or frames == 120 or frames == 200 then singeScreenshot() end if frames == 210 then singeQuit() end end