-- Ragdolls: one Fox runs at a wall and collapses on impact; another is dropped onto a flight of -- stairs limp; a third lies on the floor and gets up again under motor strength. local font = fontLoad("Singe/FreeSansBold.ttf", 28) local frames = 0 fontSelect(font) discPlay() sceneEnable(true) sceneSetBackground(0, 0, 0, 0) sceneSetAmbient(70, 70, 80) local stone = materialNew() materialSetColor(stone, 120, 120, 130) materialSetRoughness(stone, 0.9) local steel = materialNew() materialSetColor(steel, 90, 110, 150) local function block(x, y, z, w, h, d, material) local node = nodeNew() nodeSetMesh(node, meshBox(w, h, d), material) nodeSetPosition(node, x, y, z) bodyNew(node, BODY_STATIC, SHAPE_BOX, w, h, d) return node end block(0, -0.1, 0, 20, 0.2, 14, stone) block(4, 0.75, -1, 0.3, 1.5, 3, steel) -- The wall the runner hits for i = 1, 5 do block(-4 - i * 0.5, i * 0.15, 3, 0.5, i * 0.3, 3, stone) -- Stairs going up to the left end local foxModel = modelLoad("testScripts/Models/Fox.glb") -- The runner: a player carrying the Fox; the ragdoll is made now and switched on at the crash. local runner = nodeNew() nodeSetPosition(runner, -1, 0.05, -1) playerNew(runner, 0.3, 0.9) local runnerFox = modelInstance(foxModel) nodeSetParent(runnerFox, runner) nodeSetScale(runnerFox, 0.01) nodeSetRotation(runnerFox, 0, 90, 0) animationPlay(runnerFox, "Run", true) ragdollNew(runnerFox) -- The faller: dropped limp from above the stairs. local faller = modelInstance(foxModel) nodeSetPosition(faller, -6.5, 2.5, 3) nodeSetScale(faller, 0.01) nodeSetRotation(faller, 30, 40, 0) animationPlay(faller, "Survey", true) ragdollNew(faller) ragdollActivate(faller) -- The riser: lying limp on the floor, then pulled back toward its standing pose. local riser = modelInstance(foxModel) nodeSetPosition(riser, 3, 0, 3.5) nodeSetScale(riser, 0.01) nodeSetRotation(riser, 0, -30, 0) animationPlay(riser, "Survey", true) ragdollNew(riser) ragdollActivate(riser) local sun = lightNew(LIGHT_DIRECTIONAL) nodeSetPosition(sun, -4, 8, 6) nodeLookAt(sun, 0, 0, 0) lightSetIntensity(sun, 1.5) lightSetShadow(sun, true) local camera = nodeNew() nodeSetPosition(camera, 0, 4, 9) nodeLookAt(camera, -1, 0.5, 0) cameraSet(camera) local crashed = false function onCollision(a, b, x, y, z, speed) if not crashed and (a == runner or b == runner) and speed > 1.5 then crashed = true playerSetEnabled(runner, false) ragdollActivate(runnerFox) ragdollApplyImpulse(runnerFox, "b_Spine02_03", 40, 30, 0) end end function onOverlayUpdate() frames = frames + 1 if not crashed then playerMove(runner, 4, 0) end if frames == 100 then ragdollSetStrength(riser, 60) end overlayClear() fontPrint(20, 20, string.format("Ragdolls, frame %d %s faller %s riser %s", frames, crashed and "crashed" or "running", ragdollIsResting(faller) and "resting" or "moving", ragdollIsResting(riser) and "resting" or "moving")) if frames % 30 == 0 then local rx, ry, rz = nodeGetPosition(runner) local fx, fy, fz = nodeGetWorldPosition(faller) debugPrint(string.format("frame %d runner %.2f %.2f crashed %s | faller %.2f %.2f %.2f resting %s | riser resting %s", frames, rx, ry, tostring(crashed), fx, fy, fz, tostring(ragdollIsResting(faller)), tostring(ragdollIsResting(riser)))) end if frames == 50 or frames == 110 or frames == 170 then singeScreenshot() end if frames == 180 then singeQuit() end end