Jump to content
danidomen

[Solved] HOW VR Controller collision test and call "Use" of entity collided?

Recommended Posts

Hi,

I have some switches and doors (SwingingDoors) that have Use function and calls to open or light up the rooms. But now I want that when my VR controller collide with the door or the light, first detect that I can "interact" with it (atm painting a Sphere...) and when I click on controller trigger, call to "Use" function of the collided entity (door or switch). Now, I replicated the code from FPSPlayer to interact with the E Key, and is "working" but is very awful :(

I'm trying to write what I'm doing (very very very bad) on VRPlayer

function Script:UpdateWorld()

		local pickInfo = PickInfo()
		--Usable object with Trigger Button: DANI
		if VR:GetControllerButtonDown(VR.Right,VR.TriggerButton)==true then
			
			
			local p0 = controller:GetPosition(true)
			local p1 = Transform:Point(0,0,self.useDistance,controller,nil)
			if self.entity.world:Pick(p0,p1, pickInfo, self.pickradius, true) then 
				
				--Looks for any entity in the hierarchy that has a "Use" function
				local usableentity = self:FindUsableEntity(pickInfo.entity)
				
				if usableentity~=nil then
					
					--Use the object, whatever it may be
					usableentity.script:Use(self)
				end
			end
		end
		self.canUse = false
		pickInfo = PickInfo()

		local p0 = controller:GetPosition()
		local p1 = Transform:Point(self.useDistance,self.useDistance,self.useDistance,controller,nil)
		if self.entity.world:Pick(p0,p1, pickInfo, self.pickradius, true) then 
			if self:FindUsableEntity(pickInfo.entity)~=nil then
				self.picksphere:SetPosition(pickInfo.position);
				self.canUse=true
			else
				local mass = pickInfo.entity:GetMass()
				if mass>0 and mass<=self.maxcarryweight then
					self.canUse = true
				end
			end
		else
			self.picksphere:SetPosition(0,0,0)
		end

 

Edited by danidomen
solved

Share this post


Link to post
15 hours ago, danidomen said:

But now I want that when my VR controller collide with the door or the light,

You want your character controller to collide with the door in order to open it? Your code suggest that you use a pick function to interact with objects.

15 hours ago, danidomen said:

Now, I replicated the code from FPSPlayer to interact with the E Key, and is "working" but is very awful

Can you clarify what is working and what is not working. Do see anything that shouldn't happen. Error log? Perhaps a video recording?  

Share this post


Link to post

Hi @AggrorJorn,

Sure, here is the video. One half is with VR with the strange "pick" function to "use" the objects, and the other half of the video is with FPSPlayer and nice pick/use of switches and doors.

Yes, I know that "pick" is not the way to do this on VR (the switch directly not detect nothing, also the ball is "printed" always on what is like the mass center of the controller and not when "collision" happens), but I don't find info explaining how the collision system works, :( or how detect collision at the controller with another object and "callback" to the Use function of the object.

 

 

  • Like 1

Share this post


Link to post

If you look in the VR player script I set it up so you can pick up objects. I think I used the entity distance command to detect intersections between a point on the controller and the object.

Share this post


Link to post

Yep, you can find the code that does this in VRPlayer.lua:

	local mass = entity:GetMass()
	if mass>0 and mass<10 then
		local pos = self.currentcontroller:GetPosition(true)
		local d = entity:GetDistance(pos,true)
		if d <= self.grippadding then
			self.heldobject[self.currentcontrollerindex] = entity

 

Share this post


Link to post

Hi @Josh

Fine, I created the functions understanding a bit more how you used to "grab" the objects. So I have writed this, and is a bit better, but the ball is stuck on the air on front of the "Use" entity, although the controller not touched when I move away the controller from the "Use" entity. I tried with a two "else" clausules but with not sucess because then the ball is never "positioned" (I supposed that is positioned but as fast that they never appear on screen because of the "else")

function VRPlayer_TouchingItems(entity,extra)
	if entity==extra then return end
	local self = tolua.cast(extra,"Entity").script
	local mass = entity:GetMass()
    local pos = self.currentcontroller:GetPosition(true)
    local d = entity:GetDistance(pos,true)
    if d <= self.grippadding then
      local usableentity = self:FindUsableEntity(entity)
      if usableentity~=nil then
        if VR:GetControllerButtonHit(VR.Right,VR.TriggerButton)==true then
          usableentity.script:Use(self)
        else
          self.picksphere:SetPosition(pos);
        end
      else
      	--With this next line, the ball never is "positioned" because this seems to be continuosly updated at ms frequency, so the above SetPosition is like nothing
      	--self.picksphere:SetPosition(0,0,0);
      end
    else
    	--Same with this next line, the ball never is "positioned" because this seems to be continuosly updated at ms frequency, so the above SetPosition is like nothing
      	--self.picksphere:SetPosition(0,0,0);
    end

	if entity:CountVisibleChildren()>0 then
		local n
		for n=0,entity:CountChildren()-1 do
			VRPlayer_TouchingItems(entity:GetChild(n),extra)
		end
	end
end

function VRPlayer_IntersectingController(controller,extra)
	if controller~=nil then
		local aabb = AABB()	
		aabb.min = controller:GetPosition(true)
		aabb.max = aabb.min
		aabb.min = aabb.min - Vec3(extra.grippadding)
		aabb.max = aabb.max + Vec3(extra.grippadding)
		aabb:Update()
		extra.currentcontroller = controller
		extra.currentcontrollerindex = n
		world:ForEachEntityInAABBDo(aabb,"VRPlayer_TouchingItems",extra.entity)
	end
end

function Script:UpdateWorld()
	local n
	for n=0,1 do
		local controller = VR:GetControllerModel(VR.Left+n)
		VRPlayer_IntersectingController(controller,self)
	end
   A LOT OF OTHER STUFF

 

Share this post


Link to post

Hi all!

Well! I think that is the best "approach" I can do, and is near the perfect expected result, so I share with all the community how I made it (really is possible to write better code, but is my first try with Lua and with Leadwerks haha)

On VRPlayer I made the following modifications:

On the script variables declaration at the top:

Script.pickradius=0.05
Script.hitBallTime=0
Script.hitBallDelay=50
Script.clickUsed=false
Script.clickUseTime=0
Script.clickUseDelay=500

On the "Script:Start()" function, before the "--Create teleporter beam" comment add this

function Script:Start()
  blablabla
  
  self.picksphere=Model:Sphere()
  self.picksphere:SetColor(1.0,0.0,0.0) 
  self.picksphere:SetPickMode(0) 
  self.picksphere:SetScale(self.pickradius*2.0)
  
  --Create teleporter beam
  blablabla

Add this new function VRPlayer_TouchingItems

function VRPlayer_TouchingItems(entity,extra)
	if entity==extra then return end
	local self = tolua.cast(extra,"Entity").script
	local mass = entity:GetMass()
	local time = Time:GetCurrent()
	if self.clickUsed == true and time-self.clickUseTime>self.clickUseDelay then
		self.clickUseTime = 0
		self.clickUsed = false
		--This is needed to have control on not to make click so quickly (open/close/open/close the door because ButtonDown). Reason explained below
	end
		local pos = self.currentcontroller:GetPosition(true)
		local d = entity:GetDistance(pos,true)
		local usableentity = self:FindUsableEntity(entity)
		if d <= self.grippadding and usableentity~=nil then
			if VR:GetControllerButtonDown(VR.Right,VR.TriggerButton)==true then
      			--Why use ButtonDown and not hit, is because a lot of times Hit is not reachable, so to "stop" on continuos clicking, i make this control
				if self.clickUsed == false then
					self.clickUsed = true
					self.clickUseTime = time
					usableentity.script:Use(self)
				end
			else
				self.hitBallTime = time
				self.picksphere:SetPosition(pos);
			end
		else
			if time-self.hitBallTime>self.hitBallDelay then
				self.picksphere:SetPosition(0,0,0);
			end
		end
end

Add this new function VRPlayer_IntersectingController

function VRPlayer_IntersectingController(controller,extra)
	if controller~=nil then
		local aabb = AABB()	
		aabb.min = controller:GetPosition(true)
		aabb.max = aabb.min
		aabb.min = aabb.min - Vec3(extra.grippadding)
		aabb.max = aabb.max + Vec3(extra.grippadding)
		aabb:Update()
		extra.currentcontroller = controller
		extra.currentcontrollerindex = n
		world:ForEachEntityInAABBDo(aabb,"VRPlayer_TouchingItems",extra.entity)
	end
end

On the "Script:UpdateWorld()" function, before the "----Check if teleporter is active and the button was released" comment add this

function Script:UpdateWorld()
	local n
	for n=0,1 do
		local controller = VR:GetControllerModel(VR.Left+n)
		VRPlayer_IntersectingController(controller,self)
	end

And last, taked from FPSPlayer, add this new function to VRPlayer script

function Script:FindUsableEntity(entity)
	while entity~=nil do
		if entity.script then
			if type(entity.script.Use)=="function" then
				--If "enable" has not been set, it still won't be "false" so this will pass:
				if entity.script.enabled~=false then
					return entity
				else
					return nil
				end
			end
		end
		entity = entity:GetParent()
	end
	return nil
end
  • Upvote 1

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...