singe/testScripts/scene102.singe
2026-10-06 16:54:44 -05:00

153 lines
5.6 KiB
Text

-- The 3D calls no other scene exercised, checked against what the Reference says of them: a node
-- found by the name nodeSetName gave it, a crate lifted by bodyApplyForce, the simulation held
-- still by physicsSetEnabled and let go again, a player put somewhere by playerSetPosition, an
-- emitter deleted, navNearest snapping a point onto the floor and finding
-- nothing far off, an agent that navAgentStop halts short of its target and that arrives when sent
-- on (navAgentIsArrived), navAgentDelete, and a ragdoll that ragdollDelete frees for a new one.
-- Each check prints "SCENE3D ok" or "SCENE3D FAIL". No disc: run with -C 720x480.
dofile("Singe/Framework.singe")
local font = fontLoad("Singe/FreeSansBold.ttf", 14)
local stone = materialNew()
local wood = materialNew()
local camera = nodeNew()
local sun = lightNew(LIGHT_DIRECTIONAL)
local floor = nodeNew()
local crate = nodeNew()
local player = nodeNew()
local walker = nodeNew()
local fox = modelInstance(modelLoad("testScripts/Models/Fox.glb"))
local nav = nil
local agent = nil
local frames = 0
local failures = 0
local stage = "lift"
local mark = 0
local heldY = 0
local arrived = 0
local LAST = 900
local function check(name, ok, detail)
if ok then
debugPrint("SCENE3D ok " .. name)
else
failures = failures + 1
debugPrint("SCENE3D FAIL " .. name .. (detail and (" (" .. detail .. ")") or ""))
end
end
function onNavArrived(which)
if which == agent then
arrived = arrived + 1
end
end
fontSelect(font)
overlaySetResolution(720, 480)
sceneEnable(true)
cameraSet(camera)
nodeSetPosition(camera, 0, 9, 14)
nodeLookAt(camera, 0, 0, 0)
nodeLookAt(sun, -1, -2, -1)
materialSetColor(stone, 120, 120, 130)
materialSetColor(wood, 170, 120, 70)
nodeSetMesh(floor, meshBox(20, 0.2, 20), stone)
nodeSetPosition(floor, 0, -0.1, 0)
bodyNew(floor, BODY_STATIC, SHAPE_BOX, 20, 0.2, 20)
nodeSetMesh(crate, meshBox(0.6, 0.6, 0.6), wood)
nodeSetPosition(crate, -3, 0.3, 3)
bodyNew(crate, BODY_DYNAMIC, SHAPE_BOX, 0.6, 0.6, 0.6)
bodySetMass(crate, 1) -- So 40 newtons outweighs gravity
nodeSetName(crate, "theCrate")
check("nodeFind finds what nodeSetName named", nodeFind("theCrate") == crate)
nodeSetMesh(player, meshCylinder(0.3, 1.0, 12), wood)
nodeSetPosition(player, 0, 0.5, 0)
playerNew(player, 0.3, 1.0)
nodeSetMesh(walker, meshBox(0.4, 1.0, 0.4), wood)
nodeSetPosition(walker, -6, 0, -4)
nodeSetPosition(fox, 6, 0, -4)
nodeSetScale(fox, 0.02)
nav = navNew(0.3, 1.0, 45, 0.3)
navAddNode(nav, floor)
navBuild(nav)
do
local x, y, z = navNearest(nav, 1, 1.5, 1)
check("navNearest snaps onto the floor", (x ~= nil) and (math.abs(x - 1) < 0.3) and (math.abs(z - 1) < 0.3) and (math.abs(y) < 0.3), string.format("%s %s %s", tostring(x), tostring(y), tostring(z)))
check("navNearest finds nothing far off", navNearest(nav, 100, 0, 100) == nil)
end
agent = navAgentNew(nav, walker, 0.3, 1.0, 2.0)
navAgentMoveTo(agent, 6, 0, 4)
-- A dead handle ends the script rather than raising an error a pcall could catch, so these are
-- proved by what follows them: a second ragdollNew on a node that still had one would end the run.
emitterDelete(emitterNew())
check("emitterDelete takes the emitter", true)
ragdollNew(fox)
ragdollDelete(fox)
ragdollNew(fox)
check("ragdollDelete frees the node for a new ragdoll", true)
ragdollDelete(fox)
function onOverlayUpdate()
local cx, cy, cz = nodeGetWorldPosition(crate)
local wx, wy, wz = nodeGetWorldPosition(walker)
frames = frames + 1
overlayClear()
fontPrint(8, 6, string.format("frame %d %s crate y %.2f walker %.1f %.1f failures %d", frames, stage, cy, wx, wz, failures))
-- The crate is pushed up for a third of a second, then the simulation is held and let go.
if stage == "lift" then
bodyApplyForce(crate, 0, 40, 0)
if frames == 15 then
stage = "rising"
end
elseif stage == "rising" and frames == 18 then
check("bodyApplyForce lifts the crate", cy > 0.6, string.format("y %.2f", cy))
physicsSetEnabled(false)
stage = "held"
mark = frames
elseif stage == "held" then
if frames == mark + 2 then
heldY = cy
elseif frames == mark + 12 then
check("physicsSetEnabled(false) holds it still", math.abs(cy - heldY) < 0.001, string.format("%.3f then %.3f", heldY, cy))
physicsSetEnabled(true)
stage = "resumed"
mark = frames
end
elseif stage == "resumed" and frames == mark + 12 then
check("physicsSetEnabled(true) lets it go", math.abs(cy - heldY) > 0.01, string.format("%.3f then %.3f", heldY, cy))
playerSetPosition(player, 5, 0.6, 5)
stage = "teleported"
mark = frames
elseif stage == "teleported" and frames == mark + 3 then
local px, _, pz = nodeGetWorldPosition(player)
check("playerSetPosition puts the player there", (math.abs(px - 5) < 0.1) and (math.abs(pz - 5) < 0.1), string.format("%.2f %.2f", px, pz))
navAgentStop(agent)
stage = "stopped"
mark = frames
elseif stage == "stopped" and frames == mark + 60 then
check("navAgentStop halts it short", not navAgentIsArrived(agent) and (arrived == 0) and (math.abs(wx - 6) > 1), string.format("at %.1f %.1f", wx, wz))
navAgentMoveTo(agent, 6, 0, 4)
stage = "sent"
elseif stage == "sent" and arrived > 0 then
check("navAgentIsArrived once it is there", navAgentIsArrived(agent))
navAgentDelete(agent)
check("navAgentDelete leaves the walker where it was", (math.abs(wx - 6) < 1) and (math.abs(wz - 4) < 1), string.format("at %.1f %.1f", wx, wz))
stage = "done"
end
if (stage == "done") or (frames == LAST) then
check("everything ran", stage == "done", stage)
debugPrint(string.format("SCENE3D RESULT failures=%d frames=%d", failures, frames))
singeScreenshot("scene3d")
singeQuit()
end
return OVERLAY_UPDATED
end