-- Vehicles, second kind: a tank on six wheels that drives, pivots on the spot and climbs a slope, -- and a motorcycle that leans through a turn, both from primitives, side by side. 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 ground = materialNew() materialSetColor(ground, 90, 110, 70) materialSetRoughness(ground, 0.95) local armour = materialNew() materialSetColor(armour, 80, 90, 70) local rubber = materialNew() materialSetColor(rubber, 30, 30, 30) local chrome = materialNew() materialSetColor(chrome, 200, 200, 210) materialSetMetallic(chrome, 0.8) materialSetRoughness(chrome, 0.2) local floor = nodeNew() nodeSetMesh(floor, meshBox(160, 0.2, 160), ground) nodeSetPosition(floor, 0, -0.1, -30) bodyNew(floor, BODY_STATIC, SHAPE_BOX, 160, 0.2, 160) local slope = nodeNew() nodeSetMesh(slope, meshBox(8, 0.2, 8), ground) nodeSetPosition(slope, -6, 0.7, -24) nodeSetRotation(slope, 20, 0, 0) bodyNew(slope, BODY_STATIC, SHAPE_BOX, 8, 0.2, 8) local function wheel(parent, x, y, z, radius, width) local node = nodeNew() nodeSetParent(node, parent) nodeSetPosition(node, x, y, z) local tyre = nodeNew() nodeSetParent(tyre, node) nodeSetMesh(tyre, meshCylinder(radius, width, 12), rubber) nodeSetRotation(tyre, 0, 0, 90) return node end -- The tank: a heavy hull, three road wheels a side. local tank = nodeNew() nodeSetMesh(tank, meshBox(3, 1, 5), armour) nodeSetPosition(tank, -6, 1.2, 0) bodyNew(tank, BODY_DYNAMIC, SHAPE_BOX, 3, 1, 5) bodySetMass(tank, 8000) vehicleNew(tank, VEHICLE_TANK) for _, z in ipairs({ -1.8, 0, 1.8 }) do vehicleAddWheel(tank, wheel(tank, -1.7, -0.4, z, 0.5, 0.4), 0.5, 0.4, 0.5) vehicleAddWheel(tank, wheel(tank, 1.7, -0.4, z, 0.5, 0.4), 0.5, 0.4, 0.5) end vehicleSetEngine(tank, 1500, 4000, 800) -- The motorcycle: a slim frame, one wheel each end, the rear driven. local bike = nodeNew() nodeSetMesh(bike, meshBox(0.3, 0.6, 1.6), chrome) nodeSetPosition(bike, 4, 0.9, 0) bodyNew(bike, BODY_DYNAMIC, SHAPE_BOX, 0.3, 0.6, 1.6) bodySetMass(bike, 250) vehicleNew(bike, VEHICLE_MOTORCYCLE) vehicleAddWheel(bike, wheel(bike, 0, -0.3, -0.8, 0.35, 0.12), 0.35, 0.12, 0.3) vehicleAddWheel(bike, wheel(bike, 0, -0.3, 0.8, 0.35, 0.12), 0.35, 0.12, 0.3) vehicleSetEngine(bike, 150, 9000, 1200) local sun = lightNew(LIGHT_DIRECTIONAL) nodeSetPosition(sun, -5, 12, 6) nodeLookAt(sun, 0, 0, -15) lightSetIntensity(sun, 1.5) lightSetShadow(sun, true) local camera = nodeNew() cameraSet(camera) cameraSetPerspective(60, 0.1, 200) function onOverlayUpdate() local tx, ty, tz = nodeGetPosition(tank) local bx, by, bz = nodeGetPosition(bike) local t = frames / 60 frames = frames + 1 -- Tank: forward, then pivot, then on toward the slope. Bike: accelerate, then lean into a turn. if tz > -12 and frames < 100 then vehicleDrive(tank, 1, 0, 0, 0) elseif frames < 130 then vehicleDrive(tank, 0, 1, 0, 0) else vehicleDrive(tank, 1, 0, 0, 0) end if bz > -15 then vehicleDrive(bike, 1, 0, 0, 0) else vehicleDrive(bike, 0.4, 0.35, 0, 0) end -- The camera watches the tank for the first two thirds, then chases the bike. if frames < 125 then nodeSetPosition(camera, tx + 8, ty + 5, tz + 10) nodeLookAt(camera, tx, ty, tz) else nodeSetPosition(camera, bx + 6, by + 3, bz + 8) nodeLookAt(camera, bx, by, bz) end overlayClear() fontPrint(20, 20, string.format("Tank %.1f m/s bike %.1f m/s frame %d", vehicleGetSpeed(tank), vehicleGetSpeed(bike), frames)) if frames % 30 == 0 then local _, ry = nodeGetRotation(tank) local _, _, roll = nodeGetRotation(bike) debugPrint(string.format("frame %d tank %.1f %.2f %.1f yaw %.0f speed %.1f | bike %.1f %.2f %.1f roll %.0f speed %.1f", frames, tx, ty, tz, ry, vehicleGetSpeed(tank), bx, by, bz, roll, vehicleGetSpeed(bike))) end if frames == 60 or frames == 120 or frames == 170 then singeScreenshot() end if frames == 180 then singeQuit() end end