Creating a VR Teleporter: Part 2
The next step is to put our scene into VR and look at everything. I'm about six feet tall and the player model seems the same height, so that all looks right. The controllers, as you can see below, are all working with full articulation of all controls. The teleport indicator looks good too.
Now we're going to start our VR player script. We start with a new script and initialize the VR environment in the Start() function. A camera is also created in code, and I deleted the camera from the scene.
function Script:Start() if VR:Enable()~=true then Print("Error: Failed to initialize VR environment.") end self.camera = Camera:Create() end
I wanted to look at the controller models and see if there was a child that indicated where the tip of the controller was, for aiming a beam. The code below will wait until a controller model is loaded and then print out the names of all its children.
function Script:Start() if VR:Enable()~=true then Print("Error: Failed to initialize VR environment.") end self.camera = Camera:Create() self.partslisted=false end function Script:UpdateWorld() if self.partslisted==false then local model = VR:GetControllerModel(VR.Left) if model==nil then model = VR:GetControllerModel(VR.Right) end if model~=nil then self.partslisted = true local n for n=0,model:CountChildren()-1 do local subobject = model:GetChild(n) local name = subobject:GetKeyValue("name") System:Print(name) end end end end
The result is below. Three blank lines mean that three subobjects in there have no names. You can tell what some of the subobjects are, but none of them look like what I am looking for.
body button led lgrip rgrip scroll_wheel status sys_button trackpad trackpad_scroll_cut trackpad_touch trigger
None of those look like what I am looking for, so I am just going to use the controller model itself and hope for the best. The code below creates a box sticking out of the controller.
function Script:Start() if VR:Enable()==false then Print("Error: Failed to initialize VR environment.") end self.camera = Camera:Create() end function Script:UpdateWorld() local controller = VR:GetControllerModel(VR.Right) if controller~=nil then if self.beam==nil then self.beam = Model:Box(0.05,0.05,4) end if self.beam:GetParent()~=controller then self.beam:SetPosition(0,0,0) self.beam:SetRotation(0,0,0) self.beam:SetParent(controller,false) self.beam:Move(0,0,-2) end end end
As a result, we've got this funny light saber-looking thing:
Now let's replace the box with a sprite and apply our third teleport material to it. We'll make the sprite rotate around its own Z axis to face the camera using the SetViewMode() command.
function Script:Start() if VR:Enable()==false then Print("Error: Failed to initialize VR environment.") end self.camera = Camera:Create() end function Script:UpdateWorld() local controller = VR:GetControllerModel(VR.Right) if controller~=nil then if self.beam==nil then self.beam = Sprite:Create() self.beam:SetViewMode(6) self.beam:SetSize(0.05,4) self.beam:SetColor(1,2,2) local mtl = Material:Load("Models/VR/teleport3.mat") if mtl~=nil then self.beam:SetMaterial(mtl) mtl:Release() mtl = nil end end if self.beam:GetParent()~=controller then self.beam:SetPosition(0,0,0) self.beam:SetRotation(0,0,0) self.beam:SetParent(controller,false) self.beam:Move(0,0,-2) end end end
Now it really looks like a light saber!
The next step is to add picking so we can use the beam to place the teleporter. I deleted the teleport indicator prefab from the map and loaded a copy of the prefab up in the Start() function:
function Script:Start() if VR:Enable()==false then Print("Error: Failed to initialize VR environment.") end --Create the player camera self.camera = Camera:Create() --Load the teleport indicator prefab self.teleportindicator = Prefab:Load("Models/VR/teleport.pfb") self.teleportindicator:Hide() end function Script:UpdateWorld() local controller = VR:GetControllerModel(VR.Right) if controller~=nil then --Create the teleporter beam if self.beam==nil then self.beam = Sprite:Create() self.beam:SetViewMode(6) self.beam:SetSize(0.05,4) self.beam:SetColor(1,2,2) local mtl = Material:Load("Models/VR/teleport3.mat") if mtl~=nil then self.beam:SetMaterial(mtl) mtl:Release() mtl = nil end end --Reparent the beam, if needed if self.beam:GetParent()~=controller then self.beam:SetPosition(0,0,0) self.beam:SetRotation(0,0,0) self.beam:SetParent(controller,false) self.beam:Move(0,0,-2) end if VR:GetControllerButtonDown(VR.Right,VR.TouchpadButton)==true then local world = self.entity.world local pickinfo = PickInfo() local p0 = controller:GetPosition(true) local p1 = Transform:Point(0,0,-4,controller,nil) if world:Pick(p0, p1, pickinfo, 0, true)==true then self.teleportindicator:SetPosition(pickinfo.position) self.teleportindicator:Translate(0,0.05,0) self.teleportindicator:Show() end end end end
We can move the teleporter indicator around. It climbs straight up walls and there are lots of problems, but you can see the beginnings of a teleporter:
The next thing we want to do is add a normal check to prevent the teleporter from working if the picked slope is too high. You can get the slope in degrees of any normal with the following bit of code:
local slope = 90 - Math:ASin(pickinfo.normal.y)
We're also going to hide the indicator when a valid teleportation destination isn't picked. Here's the complete code:
function Script:Start() if VR:Enable()==false then Print("Error: Failed to initialize VR environment.") end --Create the player camera self.camera = Camera:Create() --Create teleporter beam self.beam = Sprite:Create() self.beam:SetViewMode(6) self.beam:SetSize(0.05,20) self.beam:SetColor(1,2,2) local mtl = Material:Load("Models/VR/teleport3.mat") if mtl~=nil then self.beam:SetMaterial(mtl) mtl:Release() mtl = nil end self.beam:Hide() --Load the teleport indicator prefab self.teleportindicator = Prefab:Load("Models/VR/teleport.pfb") self.teleportindicator:Hide() end function Script:UpdateWorld() self.teleportindicator:Hide() self.beam:Hide() local controller = VR:GetControllerModel(VR.Right) if controller~=nil then --Reparent the beam, if needed if self.beam:GetParent()~=controller then self.beam:SetPosition(0,0,0) self.beam:SetRotation(0,0,0) self.beam:SetParent(controller,false) self.beam:Move(0,0,-10) end --Activate teleporter if VR:GetControllerButtonDown(VR.Right,VR.TouchpadButton)==true then local world = self.entity.world local pickinfo = PickInfo() local p0 = controller:GetPosition(true) local p1 = Transform:Point(0,0,-20,controller,nil) if world:Pick(p0, p1, pickinfo, 0, true)==true then local slope = 90 - Math:ASin(pickinfo.normal.y) if slope<35 then self.teleportindicator:SetPosition(pickinfo.position) self.teleportindicator:Translate(0,0.05,0) self.teleportindicator:Show() self.beam:Show() end end end end end
And now we will add the actual teleport mechanic. We take the picked position, subtract the camera's current XZ position, and add to the existing VR offset. This took a little trial and error, but it works perfectly:
--Check if teleporter is active and the button was released if self.beam:Hidden()==false then if VR:GetControllerButtonDown(VR.Right,VR.TouchpadButton)==false then local offset = VR:GetOffset() local pos = self.teleportindicator:GetPosition() local campos = self.camera:GetPosition(true) pos.x = pos.x - campos.x + offset.x pos.y = pos.y - 0.05 pos.z = pos.z - campos.z + offset.z VR:SetOffset(pos) end end
Here it is in action. We can not yet teleport up to the highest blocks, but we can freely move around the map.
Next we will make the beam arc so we can climb up to platforms above us.
- 1
5 Comments
Recommended Comments