main.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. -- right trigger: teleport-jump to targeted location
  2. -- right thumbstick: rotate the view horizontally
  3. local motion = {
  4. pose = lovr.math.newMat4(), -- Transformation in VR initialized to origin (0,0,0) looking down -Z
  5. thumbstickDeadzone = 0.4, -- Smaller thumbstick displacements are ignored (too much noise)
  6. -- Snap motion parameters
  7. snapTurnAngle = 2 * math.pi / 12,
  8. thumbstickCooldownTime = 0.3,
  9. thumbstickCooldown = 0,
  10. -- Teleport motion parameters
  11. teleportDistance = 12,
  12. blinkTime = 0.5,
  13. blinkStopwatch = math.huge,
  14. teleportValid = false,
  15. targetPosition = lovr.math.newVec3(),
  16. teleportCurve = lovr.math.newCurve(3),
  17. }
  18. lovr.graphics.setBackgroundColor(0.1, 0.1, 0.1)
  19. function motion.teleport(dt)
  20. -- Teleportation determining target position and executing jump when triggered
  21. local handPose = mat4(motion.pose):mul(mat4(lovr.headset.getPose('hand/right/point')))
  22. local handPosition = vec3(handPose)
  23. local handDirection = quat(handPose):direction()
  24. -- Intersect with ground plane
  25. local ratio = vec3(handPose).y / handDirection.y
  26. local intersectionDistance = math.sqrt(handPosition.y^2 + (handDirection.x * ratio)^2 + (handDirection.z * ratio)^2)
  27. motion.targetPosition:set(handPose:translate(0, 0, -intersectionDistance))
  28. -- Check if target position is a valid teleport target
  29. motion.teleportValid = motion.targetPosition.y < handPosition.y and
  30. (handPosition - motion.targetPosition):length() < motion.teleportDistance
  31. -- Construct teleporter visualization curve
  32. local midPoint = vec3(handPosition):lerp(motion.targetPosition, 0.3)
  33. if motion.teleportValid then
  34. midPoint:add(vec3(0, 0.1 * intersectionDistance, 0)) -- Fake a parabola
  35. end
  36. motion.teleportCurve:setPoint(1, handPosition)
  37. motion.teleportCurve:setPoint(2, midPoint)
  38. motion.teleportCurve:setPoint(3, motion.targetPosition)
  39. -- Start timer when jump is triggered, preform jump on half-blink
  40. if lovr.headset.wasPressed('right', 'trigger') and motion.teleportValid then
  41. motion.blinkStopwatch = -motion.blinkTime / 2
  42. end
  43. -- Preform jump with VR pose offset by relative distance between here and there
  44. if motion.blinkStopwatch < 0 and
  45. motion.blinkStopwatch + dt >= 0 then
  46. local headsetXZ = vec3(lovr.headset.getPosition())
  47. headsetXZ.y = 0
  48. local newPosition = motion.targetPosition - headsetXZ
  49. motion.pose:set(newPosition, vec3(1,1,1), quat(motion.pose)) -- ZAAPP
  50. end
  51. -- Snap horizontal turning (often combined with teleport mechanics)
  52. if lovr.headset.isTracked('right') then
  53. local x, y = lovr.headset.getAxis('right', 'thumbstick')
  54. if math.abs(x) > motion.thumbstickDeadzone and motion.thumbstickCooldown < 0 then
  55. local angle = -x / math.abs(x) * motion.snapTurnAngle
  56. motion.pose:rotate(angle, 0, 1, 0)
  57. motion.thumbstickCooldown = motion.thumbstickCooldownTime
  58. end
  59. end
  60. motion.blinkStopwatch = motion.blinkStopwatch + dt
  61. motion.thumbstickCooldown = motion.thumbstickCooldown - dt
  62. end
  63. function motion.drawTeleport(pass)
  64. -- Teleport target and curve
  65. pass:setColor(1, 1, 1, 0.1)
  66. if motion.teleportValid then
  67. pass:setColor(1, 1, 0)
  68. pass:cylinder(motion.targetPosition, 0.4,0.05, math.pi/2, 1,0,0)
  69. pass:setColor(1, 1, 1)
  70. end
  71. --lovr.graphics.setLineWidth(4)
  72. pass:line(motion.teleportCurve:render(30))
  73. -- Teleport blink, modeled as gaussian function
  74. local blinkAlpha = math.exp(-(motion.blinkStopwatch/ 0.25 / motion.blinkTime)^2)
  75. pass:setColor(0,0,0, blinkAlpha)
  76. pass:fill()
  77. end
  78. function lovr.update(dt)
  79. motion.teleport(dt)
  80. end
  81. function lovr.draw(pass)
  82. pass:transform(mat4(motion.pose):invert())
  83. -- Render hands
  84. pass:setColor(1,1,1)
  85. local radius = 0.04
  86. for _, hand in ipairs(lovr.headset.getHands()) do
  87. -- Whenever pose of hand or head is used, need to account for VR movement
  88. local poseRW = mat4(lovr.headset.getPose(hand))
  89. local poseVR = mat4(motion.pose):mul(poseRW)
  90. poseVR:scale(radius)
  91. pass:sphere(poseVR)
  92. end
  93. -- Some scenery
  94. lovr.math.setRandomSeed(0)
  95. local goldenRatio = (math.sqrt(5) + 1) / 2
  96. local goldenAngle = (2 - goldenRatio) * (2 * math.pi)
  97. local k = 1.8
  98. for i = 1, 500 do
  99. local r = math.sqrt(i) * k
  100. local x = math.cos(goldenAngle * i) * r
  101. local y = math.sin(goldenAngle * i) * r
  102. if lovr.math.random() < 0.05 then
  103. pass:setColor(0.8, 0.5, 0)
  104. else
  105. local shade = 0.1 + 0.3 * lovr.math.random()
  106. pass:setColor(shade, shade, shade)
  107. end
  108. pass:cylinder(x, -0.01, y, 1,0.02, math.pi / 2, 1,0,0)
  109. end
  110. motion.drawTeleport(pass)
  111. end