Hi, I was wondering if there was a simple way to raycast to a hotspot from a point in worldspace, then trigger the interaction UI to appear (or just the interaction itself if context sensitive).
Use case - I'm using tracked controllers with a VR rig, so want to point the controller at the hotspot, raycast at it, then trigger interaction/UI. I've got raycast to UI using OnPointerSubmit, now just need hotspot triggers. If you like I can share codebase when done as a VR port of adventure creator. Adventure games + VR is awesome.
Comments
To trigger a Hotspot's interaction manually, you can call the Hotspot script's RunUseInteraction function.
To turn on the Interaction menus, you call the PlayerMenus script's SetInteractionMenus function:
AC.KickStarter.playerMenus.SetInteractionMenus (true);
That will turn on the Interaction menu for the selected Hotspot. However, there is a private function of the same name in the script that allows to to choose which Hotspot specifically it is turned on for. I will see if this can be made public (or a variant of it) in the next update, but you can change it to public to use it yourself if you wish in the meantime.
So I'm able to raycast and get the hotspot, and send Select() to it (highlighting it succesfully), however when I run EnableInteractionMenus with the hotspot found by raycast, it doesn't open the interaction menu. not sure if I'm missing steps or conditions that need to be met? I've also tried SetInteractionMenus set to public and set a bunch of debugs throughout it, and process seems to be same for mouseover compared to triggering the function via code so i'm a bit stumped why the interaction menu isn't appear.
For it to work, you need a Menu with an Appear type of On Interaction. Try it with the default interface by setting your Menu Manager asset file to Demo_MenuManager, and let us know if it works - the result will help us work out the next step.
I've also tried a vanilla version (new project, newest AC, raycasting at hotspot sending "Select" and "EnableInteractionMenus") and getting same results. I've definitely got appear type to on interaction,
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class VRCursor : MonoBehaviour {
//Reticle Management
public Camera CameraFacing;
private Vector3 originalScale;
public GameObject LeftController;
public bool mouseInput;
public GameObject interactionMenu;
public SteamVR_TrackedController thisController;
public bool selectedSent = false;
//Hotspot ray
AC.Hotspot selectedHotspot;
AC.Hotspot previousHotspot;
//UI Ray
int UIMask = 1 << 5;
RaycastHit rayHit;
public float rayThickness;
public bool displayDebugRay;
GameObject rayHitDelta;
// Use this for initialization
void Start () {
originalScale = transform.localScale;
thisController = LeftController.GetComponent<SteamVR_TrackedController>();
}
void Update () {
HotspotRay();
}
// Update is called once per frame
public void HotspotRay(){
RaycastHit hit;
float distance;
if (Physics.Raycast (new Ray (LeftController.transform.position,
LeftController.transform.rotation * Vector3.forward),
out hit)) {
distance = hit.distance;
Debug.Log("hit");
Debug.Log(hit.collider.gameObject);
if(hit.collider.tag=="Hotspot"){
selectedHotspot = hit.collider.GetComponent(); //gets hotspot component
if(!selectedSent){//makes sure select only sent once
selectedHotspot.Select();
selectedSent = true; //one hitter
AC.KickStarter.playerMenus.EnableInteractionMenus(selectedHotspot);
previousHotspot = selectedHotspot; //record this as last rays to another hotspot
}
if(selectedSent){
if(thisController.triggerPressed){
selectedHotspot.RunUseInteraction();
}
}
}
if (hit.collider.tag!="Hotspot"&&selectedSent){ //if hotspot selected and stops hitting a hotspot
selectedHotspot.Deselect();//sends deselect because no longer hitting hotspot
selectedSent = false;//allows for select to be sent again on next collision
AC.KickStarter.playerMenus.CloseInteractionMenus();//closes menus hypothetically
}
if (selectedHotspot != previousHotspot ){//sends deselect because hitting another hotspot
selectedHotspot.Deselect();
AC.KickStarter.playerMenus.CloseInteractionMenus();
selectedSent = false;
}
} else {
distance = CameraFacing.farClipPlane* 0.1f;
if(selectedSent){
selectedHotspot.Deselect();
selectedSent = false;
AC.KickStarter.playerMenus.CloseInteractionMenus();
}
}
//Reticle position/management
transform.position = LeftController.transform.position +
LeftController.transform.rotation * Vector3.forward * distance;
transform.LookAt (CameraFacing.transform.position);
transform.Rotate (0.0f,180.0f, 0.0f);
transform.localScale = originalScale * distance;
if(mouseInput){
Vector3 temp = Input.mousePosition;
temp.z = distance; // Set this to be the distance you want the object to be placed in front of the camera.
this.transform.position = Camera.main.ScreenToWorldPoint(temp);
}
}
}
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class VRCursor : MonoBehaviour {
//Reticle Management
public Camera CameraFacing;
private Vector3 originalScale;
public GameObject LeftController;
public bool mouseInput;
public GameObject interactionMenu;
public bool selectedSent = false;
//Hotspot ray
AC.Hotspot selectedHotspot;
AC.Hotspot previousHotspot;
//UI Ray
int UIMask = 1 << 5;
RaycastHit rayHit;
public float rayThickness;
public bool displayDebugRay;
GameObject rayHitDelta;
// Use this for initialization
void Start () {
originalScale = transform.localScale;
}
void Update () {
HotspotRay();
}
// Update is called once per frame
public void HotspotRay(){
RaycastHit hit;
float distance;
if (Physics.Raycast (new Ray (LeftController.transform.position,
LeftController.transform.rotation * Vector3.forward),
out hit)) {
distance = hit.distance;
Debug.Log("hit");
Debug.Log(hit.collider.gameObject);
if(hit.collider.tag=="Hotspot"){
selectedHotspot = hit.collider.GetComponent(); //gets hotspot component
if(!selectedSent){//makes sure select only sent once
selectedHotspot.Select();
selectedSent = true; //one hitter
AC.KickStarter.playerMenus.EnableInteractionMenus(selectedHotspot);
previousHotspot = selectedHotspot; //record this as last rays to another hotspot
}
}
if (hit.collider.tag!="Hotspot"&&selectedSent){ //if hotspot selected and stops hitting a hotspot
selectedHotspot.Deselect();//sends deselect because no longer hitting hotspot
selectedSent = false;//allows for select to be sent again on next collision
AC.KickStarter.playerMenus.CloseInteractionMenus();//closes menus hypothetically
}
if (selectedHotspot != previousHotspot ){//sends deselect because hitting another hotspot
selectedHotspot.Deselect();
AC.KickStarter.playerMenus.CloseInteractionMenus();
selectedSent = false;
}
} else {
distance = CameraFacing.farClipPlane* 0.1f;
if(selectedSent){
selectedHotspot.Deselect();
selectedSent = false;
AC.KickStarter.playerMenus.CloseInteractionMenus();
}
}
//Reticle position/management
transform.position = LeftController.transform.position +
LeftController.transform.rotation * Vector3.forward * distance;
transform.LookAt (CameraFacing.transform.position);
transform.Rotate (0.0f,180.0f, 0.0f);
transform.localScale = originalScale * distance;
if(mouseInput){
Vector3 temp = Input.mousePosition;
temp.z = distance; // Set this to be the distance you want the object to be placed in front of the camera.
this.transform.position = Camera.main.ScreenToWorldPoint(temp);
}
}
}
Look for the Close interactions with option in the Settings Manager and set it to Click Off Menu. I think the issue was that AC was closing it instantly as the conditions to keep it open were not being met.
I would also recommend you take a look at the "World Space Cursor Example" script included with AC, as it shows how you can manipulate the AC cursor to take the position of a real-world object.