Browse Source

Thumbsticks locomotion example

Includes:

- smooth moving / turning / strafing
- snap turning and dashing forward
- free-flying mode (useful for developement)
Josip Miskovic 4 years ago
parent
commit
30c7545df7
1 changed files with 121 additions and 0 deletions
  1. 121 0
      examples/Locomotion/Basic_Thumbsticks/main.lua

+ 121 - 0
examples/Locomotion/Basic_Thumbsticks/main.lua

@@ -0,0 +1,121 @@
+-- Left thumbstick: move and strafe
+-- Right thumbstick: rotate the view horizontally
+
+-- Right grip: switch to snap locomotion mode
+-- Left grip: enable flying mode
+-- Left trigger: switch orientation to left hand controller (can look around while moving)
+
+local motion = {
+  pose = lovr.math.newMat4(), -- Transformation in VR initialized to origin (0,0,0) looking down -Z
+  thumbstickDeadzone = 0.4,   -- Smaller thumbstick displacements are ignored (too much noise)
+  directionFrom = 'head',     -- Movement can be relative to orientation of head or left controller
+  flying = false,
+  -- Snap motion parameters
+  snapTurnAngle = 2 * math.pi / 12,
+  dashDistance = 1.5,
+  thumbstickCooldownTime = 0.3,
+  thumbstickCooldown = 0,
+  -- Smooth motion parameters
+  turningSpeed = 2 * math.pi * 1 / 6,
+  walkingSpeed = 4,
+}
+
+function motion.smooth(dt)
+  if lovr.headset.isTracked('right') then
+    local x, y = lovr.headset.getAxis('right', 'thumbstick')
+    -- Smooth horizontal turning
+    if math.abs(x) > motion.thumbstickDeadzone then
+      motion.pose:rotate(-x * motion.turningSpeed * dt, 0, 1, 0)
+    end
+  end
+  if lovr.headset.isTracked('left') then
+    local x, y = lovr.headset.getAxis('left', 'thumbstick')
+    local direction = quat(lovr.headset.getOrientation(motion.directionFrom)):direction()
+    if not motion.flying then
+      direction.y = 0
+    end
+    -- Smooth strafe movement
+    if math.abs(x) > motion.thumbstickDeadzone then
+      local strafeVector = quat(-math.pi / 2, 0,1,0):mul(vec3(direction))
+      motion.pose:translate(strafeVector * x * motion.walkingSpeed * dt)
+    end
+    -- Smooth Forward/backward movement
+    if math.abs(y) > motion.thumbstickDeadzone then
+      motion.pose:translate(direction * y * motion.walkingSpeed * dt)
+    end
+  end
+end
+
+function motion.snap(dt)
+  -- Snap horizontal turning
+  if lovr.headset.isTracked('right') then
+    local x, y = lovr.headset.getAxis('right', 'thumbstick')
+    if math.abs(x) > motion.thumbstickDeadzone and motion.thumbstickCooldown < 0 then
+      local angle = -x / math.abs(x) * motion.snapTurnAngle
+      motion.pose:rotate(angle, 0, 1, 0)
+      motion.thumbstickCooldown = motion.thumbstickCooldownTime
+    end
+  end
+  -- Dashing forward/backward
+  if lovr.headset.isTracked('left') then
+    local x, y = lovr.headset.getAxis('left', 'thumbstick')
+    if math.abs(y) > motion.thumbstickDeadzone and motion.thumbstickCooldown < 0 then
+      local moveVector = quat(lovr.headset.getOrientation('head')):direction()
+      if not motion.flying then
+        moveVector.y = 0
+      end
+      moveVector:mul(y / math.abs(y) * motion.dashDistance)
+      motion.pose:translate(moveVector)
+      motion.thumbstickCooldown = motion.thumbstickCooldownTime
+    end
+  end
+  motion.thumbstickCooldown = motion.thumbstickCooldown - dt
+end
+
+function lovr.update(dt)
+  motion.directionFrom = lovr.headset.isDown('left', 'trigger') and 'left' or 'head'
+  if lovr.headset.isDown('left', 'grip') then
+    motion.flying = true
+  elseif lovr.headset.wasReleased('left', 'grip') then
+    motion.flying = false
+    local height = vec3(motion.pose).y
+    motion.pose:translate(0, -height, 0)
+  end
+  if lovr.headset.isDown('right', 'grip') then
+    motion.snap(dt)
+  else
+    motion.smooth(dt)
+  end
+end
+
+function lovr.draw()
+  lovr.graphics.setBackgroundColor(0.1, 0.1, 0.1)
+  lovr.graphics.transform(mat4(motion.pose):invert())
+  -- Render hands
+  lovr.graphics.setColor(1,1,1)
+  local radius = 0.05
+  for _, hand in ipairs(lovr.headset.getHands()) do
+    -- Whenever pose of hand or head is used, need to account for VR movement
+    local poseRW = mat4(lovr.headset.getPose(hand))
+    local poseVR = mat4(motion.pose):mul(poseRW)
+    poseVR:scale(radius)
+    lovr.graphics.sphere(poseVR)
+  end
+  -- Some scenery
+  lovr.math.setRandomSeed(0)
+  local goldenRatio = (math.sqrt(5) + 1) / 2
+  local goldenAngle = (2 - goldenRatio) * (2 * math.pi)
+  local k = 1.8
+  for i = 1, 500 do
+    local r = math.sqrt(i) * k
+    local x = math.cos(goldenAngle * i) * r
+    local y = math.sin(goldenAngle * i) * r
+    if lovr.math.random() < 0.05 then
+      lovr.graphics.setColor(0.5, 0, 0)
+    else
+      local shade = 0.1 + 0.3 * lovr.math.random()
+      lovr.graphics.setColor(shade, shade, shade)
+    end
+    lovr.graphics.cylinder(x, 0, y,  0.05, math.pi / 2, 1,0,0, 1, 1)
+  end
+end