main.lua 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. -- Left thumbstick: move and strafe
  2. -- Right thumbstick: rotate the view horizontally
  3. -- Right grip: switch to snap locomotion mode
  4. -- Left grip: enable flying mode
  5. -- Left trigger: switch orientation to left hand controller (can look around while moving)
  6. local motion = {
  7. pose = lovr.math.newMat4(), -- Transformation in VR initialized to origin (0,0,0) looking down -Z
  8. thumbstickDeadzone = 0.4, -- Smaller thumbstick displacements are ignored (too much noise)
  9. directionFrom = 'head', -- Movement can be relative to orientation of head or left controller
  10. flying = false,
  11. -- Snap motion parameters
  12. snapTurnAngle = 2 * math.pi / 12,
  13. dashDistance = 1.5,
  14. thumbstickCooldownTime = 0.3,
  15. thumbstickCooldown = 0,
  16. -- Smooth motion parameters
  17. turningSpeed = 2 * math.pi * 1 / 6,
  18. walkingSpeed = 4,
  19. }
  20. lovr.graphics.setBackgroundColor(0.1, 0.1, 0.1)
  21. function motion.smooth(dt)
  22. if lovr.headset.isTracked('right') then
  23. local x, y = lovr.headset.getAxis('right', 'thumbstick')
  24. -- Smooth horizontal turning
  25. if math.abs(x) > motion.thumbstickDeadzone then
  26. local hx, _, hz = lovr.headset.getPosition()
  27. motion.pose:translate(hx, 0, hz)
  28. motion.pose:rotate(-x * motion.turningSpeed * dt, 0, 1, 0)
  29. motion.pose:translate(-hx, 0, -hz)
  30. end
  31. end
  32. if lovr.headset.isTracked('left') then
  33. local x, y = lovr.headset.getAxis('left', 'thumbstick')
  34. local direction = quat(lovr.headset.getOrientation(motion.directionFrom)):direction()
  35. if not motion.flying then
  36. direction.y = 0
  37. end
  38. -- Smooth strafe movement
  39. if math.abs(x) > motion.thumbstickDeadzone then
  40. local strafeVector = quat(-math.pi / 2, 0,1,0):mul(vec3(direction))
  41. motion.pose:translate(strafeVector * x * motion.walkingSpeed * dt)
  42. end
  43. -- Smooth Forward/backward movement
  44. if math.abs(y) > motion.thumbstickDeadzone then
  45. motion.pose:translate(direction * y * motion.walkingSpeed * dt)
  46. end
  47. end
  48. end
  49. function motion.snap(dt)
  50. -- Snap horizontal turning
  51. if lovr.headset.isTracked('right') then
  52. local x, y = lovr.headset.getAxis('right', 'thumbstick')
  53. if math.abs(x) > motion.thumbstickDeadzone and motion.thumbstickCooldown < 0 then
  54. local angle = -x / math.abs(x) * motion.snapTurnAngle
  55. local hx, _, hz = lovr.headset.getPosition()
  56. motion.pose:translate(hx, 0, hz)
  57. motion.pose:rotate(angle, 0, 1, 0)
  58. motion.pose:translate(-hx, 0, -hz)
  59. motion.thumbstickCooldown = motion.thumbstickCooldownTime
  60. end
  61. end
  62. -- Dashing forward/backward
  63. if lovr.headset.isTracked('left') then
  64. local x, y = lovr.headset.getAxis('left', 'thumbstick')
  65. if math.abs(y) > motion.thumbstickDeadzone and motion.thumbstickCooldown < 0 then
  66. local moveVector = quat(lovr.headset.getOrientation('head')):direction()
  67. if not motion.flying then
  68. moveVector.y = 0
  69. end
  70. moveVector:mul(y / math.abs(y) * motion.dashDistance)
  71. motion.pose:translate(moveVector)
  72. motion.thumbstickCooldown = motion.thumbstickCooldownTime
  73. end
  74. end
  75. motion.thumbstickCooldown = motion.thumbstickCooldown - dt
  76. end
  77. function lovr.update(dt)
  78. motion.directionFrom = lovr.headset.isDown('left', 'trigger') and 'left' or 'head'
  79. if lovr.headset.isDown('left', 'grip') then
  80. motion.flying = true
  81. elseif lovr.headset.wasReleased('left', 'grip') then
  82. motion.flying = false
  83. local height = vec3(motion.pose).y
  84. motion.pose:translate(0, -height, 0)
  85. end
  86. if lovr.headset.isDown('right', 'grip') then
  87. motion.snap(dt)
  88. else
  89. motion.smooth(dt)
  90. end
  91. end
  92. function lovr.draw(pass)
  93. pass:transform(mat4(motion.pose):invert())
  94. -- Render hands
  95. pass:setColor(1,1,1)
  96. local radius = 0.05
  97. for _, hand in ipairs(lovr.headset.getHands()) do
  98. -- Whenever pose of hand or head is used, need to account for VR movement
  99. local poseRW = mat4(lovr.headset.getPose(hand))
  100. local poseVR = mat4(motion.pose):mul(poseRW)
  101. poseVR:scale(radius)
  102. pass:sphere(poseVR)
  103. end
  104. -- Some scenery
  105. lovr.math.setRandomSeed(0)
  106. local goldenRatio = (math.sqrt(5) + 1) / 2
  107. local goldenAngle = (2 - goldenRatio) * (2 * math.pi)
  108. local k = 1.8
  109. for i = 1, 500 do
  110. local r = math.sqrt(i) * k
  111. local x = math.cos(goldenAngle * i) * r
  112. local y = math.sin(goldenAngle * i) * r
  113. if lovr.math.random() < 0.05 then
  114. pass:setColor(0.5, 0, 0)
  115. else
  116. local shade = 0.1 + 0.3 * lovr.math.random()
  117. pass:setColor(shade, shade, shade)
  118. end
  119. pass:cylinder(x, 0, y, 1,0.05, math.pi / 2, 1,0,0)
  120. end
  121. end