I am creating a 3d image gallery with virtual buttons. Presently using the virtual button example from vuforia site, I am able to implement each button for a single image.
I want to create only two buttons to navigate with virtual button. How Can i go with this.
The Below code is not tested, but should be simple to drop in to a C# script and the editor will point out what warnings you might get and suggest an easy fix.
List<Texture> MyImageList = new List<Texture>();
int imageIndex = 0;
void OnGUI() {
GUI.DrawTexture(new Rect(0,0,Screen.width, Screen.height), MyImageList[imageIndex]);
if(GUI.Button(new Rect(10,10,80,10), "Prev")) {
Prev();
}
if(GUI.Button(new Rect(200,10,80,10), "Next")) {
Next();
}
}
void Next() {
if(imageIndex < MyImageList.Count)
imageIndex++; else imageIndex = 0;
}
void Prev() {
if(imageIndex > MyImageList.Count)
imageIndex--; else imageIndex = MyImageList.Count;
}
its not a virtual button as such, but using a global list indexer is the best option, as the above demonstrates .
Related
I am developing a VR game in Unity (2020.3.15f2) using the XR Interaction Toolkit package (1.0.0-pre.5) for my Oculus Quest 2. At this stage in my development, I am trying to recognize presses to the trigger and grip buttons on the controllers respectively in order to animate some 3D hand models. Here's the script I've written to accomplish this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
public class HandPresence : MonoBehaviour {
public InputDeviceCharacteristics controllerCharacteristics;
public GameObject handModelPrefab;
private InputDevice targetDevice;
private GameObject spawnedHandModel;
private Animator handAnimator;
void Start() {
TryInitialize();
}
void TryInitialize() {
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevicesWithCharacteristics(controllerCharacteristics, devices);
if (devices.Count > 0) {
targetDevice = devices[0];
spawnedHandModel = Instantiate(handModelPrefab, transform);
handAnimator = spawnedHandModel.GetComponent<Animator>();
}
}
void UpdateHandAnimation() {
if (targetDevice.TryGetFeatureValue(CommonUsages.trigger, out float triggerValue)) {
handAnimator.SetFloat("Trigger", triggerValue);
} else {
handAnimator.SetFloat("Trigger", 0);
}
if (targetDevice.TryGetFeatureValue(CommonUsages.grip, out float gripValue)) {
handAnimator.SetFloat("Grip", gripValue);
} else {
handAnimator.SetFloat("Grip", 0);
}
}
void Update()
{
if (!targetDevice.isValid) {
TryInitialize();
} else {
spawnedHandModel.SetActive(true);
UpdateHandAnimation();
}
}
}
The issue I'm experiencing is that the values of both triggerValue and gripValue are always 0. The value of targetDevice looks fine. I also tried using triggerButton, gripButton, primaryButton, etc. and they are always 0/false as well. The hand models show up just fine and their movement is in sync with the movement of the controllers, but they just don't seem to want to register any button presses.
I've been stuck on this one for hours and would very much appreciate any insight, thank you!
Is your project setup with the (new) Input System? I have no problem detecting there trigger and grip values.
Also make sure the targetDevice actually uses trigger and grip features, maybe it is another device such as the HMD.
I have a multiplayer 2D game made in Unity and I wanted to put some onscreen buttons to be able to control it on the telephone. The problem is that when I put the Event Trigger on the button it uses the function from the script that has to use, but it can't open other functions called in the main one. In my code, I try to open the function TryFireBullet() whenever I am pressing the button and Debug.Log shows me that TryFireBullet() is opened, but the functions inside it are not opened at all. (when I press the button, Debug.Log() shows me "works", "works2" and no "works3"..)
Any ideas why it does not work and how to fix it?
Here is the problem part of the code:
public void TryFireBullet()
{
Debug.Log("works");
//if (ultimul_glont == 0 || Time.time > ultimul_glont + Delay_Bullet)
//{
ultimul_glont = Time.time;
Debug.Log("works2");
CmdFireBullet();
//}
}
[Command]
public void CmdFireBullet()
{
Debug.Log("works3");
GameObject bullet = Instantiate(bulletPrefab, gunTip.position, Quaternion.identity) as GameObject;
NetworkServer.Spawn(bullet);
RpcAdaugaViteza(bullet);
}
Here is the full code:
https://pastebin.com/WaWbQvTw
p.s. I can not use just a main function for my button because I need Server Commands
Game View- Camera Display
When I click the Space Bar for the player to jump, the Display drop down menu pops up and the player doesn't jump. However, the player can move upon all key presses.
Here's the information that I have:
1) Everything worked and functioned properly.
2) I added a health bar to my boss.
3) I created a second canvas (First canvas was for my Player's HP).
4) I made the Boss HP bar render mode: World Space.
5) I attached the canvas to the boss controller in the hierarchy as a child.
6) The code I use for Player Jump is Input.GetKeyDown(KeyCode.Space).
7) The mouse curser is inside the Game View whilst testing the SpaceBar Jump.
8) I'm developing in Unity 2018 5.3 2D mode.
Official Question('s):
1) Why does the Spacebar causing the camera display drop menu to appear?
2) How do I fix this?
Edit / Additional Content:
Here's my Jump script
public float jump1 = 5.0f;
private bool onGround;
//private bool dblJump; //Not implemented yet
public Rigidbody player;
void Start () {
player = GetComponent<Rigidbody>();
onGround = true;
}
// Update is called once per frame
void Update () {
if (onGround == true) {
if (Input.GetKeyDown(KeyCode.LeftShift))// KeyCode.Space
{
player.velocity = new Vector3(0, jump1, 0);
onGround = false;
// Debug.Log("The onGround is False");
}
}
}
Keep in mind that I have temporarily changed my jump to LeftShift. However, my problem persist with the space bar, even when I click it with left shift as my jump. SpaceBar seems to summon the drop down menu for the camera display. (I can't seem to catch the drop down menu with a screen shot because it goes away upon a click)
Also Note - I'm inside a class called PlayerJump : MonoBehavior.
It seems like it's a known issue with some versions of Unity 5.3, I have a few solutions you can try :
Drag you game window somewhere else in the editor
Enable the "Maximise on play" button
Attach this script to your drop-down element :
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class DropdownScript : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
void Start()
{
dropDown = GetComponent<Dropdown>();
dropDown.interactable = false;
}
public void OnPointerEnter(PointerEventData ped)
{
dropDown.interactable = true;
}
public void OnPointerExit(PointerEventData ped)
{
dropDown.interactable = false;
}
}
Otherwise update you Unity version if it's not the latest release? I am not experiencing this issue but many other users are apparently.
Question asked just to give solution :)
Main idea is to recognize QR-code on Unity without ANY additional action like tapping on the screen or sth like this.
(For me it's not necessary that "vuforia free" have watermark, so here is my solution)
(Also Vuforia works with camera much faster and no need to realize manually autofocus)
Continious QR code recognition using Vuforia as webcam source and ZXing Library as QR recognizer
using UnityEngine;
using Vuforia;
using ZXing;
public class QRCodeReader : MonoBehaviour {
private bool _isFrameFormatSet;
IBarcodeReader _barcodeReader = new BarcodeReader();
void Start () {
InvokeRepeating("Autofocus", 2f, 2f);
}
void Autofocus () {
CameraDevice.Instance.SetFocusMode(CameraDevice.FocusMode.FOCUS_MODE_TRIGGERAUTO);
RegognizeQR();
}
private Vuforia.Image GetCurrFrame()
{
return CameraDevice.Instance.GetCameraImage(Vuforia.Image.PIXEL_FORMAT.GRAYSCALE);
}
void RegognizeQR()
{
if (!_isFrameFormatSet == _isFrameFormatSet)
{
_isFrameFormatSet = CameraDevice.Instance.SetFrameFormat(Vuforia.Image.PIXEL_FORMAT.GRAYSCALE, true);
}
var currFrame = GetCurrFrame();
if (currFrame == null)
{
Debug.Log("Camera image capture failure;");
}
else
{
var imgSource = new RGBLuminanceSource(currFrame.Pixels, currFrame.BufferWidth, currFrame.BufferHeight, true);
var result = _barcodeReader.Decode(imgSource);
if (result != null)
{
Debug.Log("RECOGNIZED: " + result.Text);
}
}
}
}
Its possible to realize also without Vuforia, ofc. Unity provides the possibility to get a camera and show it’s input on a webcamtexture. It's possible to find more documentation here.
ZXing lib you can find here, or build it by your own hands using sourse code located on github.
Both libs is cross-platform, so must be no issues on different devices.
I have a simple touch/mouseclick script attached to a GameObject as a sort of "Master Script" i.e. the GameObject is invisible and doesn't do anything but hold this Touch script when the game is running.
How do I tell other named GameObjects that are generated at runtime to do things e.g. highlight when touched/clicked from this Master Script?
The script for highlighting seems to be: renderer.material.color= colorRed;
But I'm not sure how to tell the GameObject clicked on to become highlighted from the Master Script.
Please help! (am programming in C#)
Thanks!
Alright so you'll want to use a ray cast if you're not doing it in GUI. Check out Unity Ray Casting and then use
hit.transform.gameObject.renderer.material.color = red;
You can have a switch that is like:
if (hit.transform.gameObject.CompareTag("tag")) {
// turn to red;
} else {
// turn to white;
}
Use the ScreenPointToRay or ScreenPointToWorld depending on what you're doing.
For touch, should look like:
void Update () {
foreach (Touch touch in Input.touches)
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 1000.0f))
{
if (hit.collider.gameObject.CompareTag("tag"))
{
hit.collider.gameObject.renderer.material.color = red;
}
}
}
// You can also add in a "go back" feature in the update but this will "go back" then when the touch ends or moves off
// Also not so good to search for Objects in the update function but that's at your discretion.
GameObject[] gObjs = GameObject.FindGameObjectsWithTag("tag");
foreach (GameObject go in gObjs) {
go.renderer.material.color = white;
}
}
To answer your question about pinging the 'manager'
I would do one of two options.
Either:
// Drop the object containing YourManager into the box in the inspector where it says "manage"
public YourManager manage;
// In the update and in the Ray Cast function (right next to your color change line):
manager.yourCall ();
// and
manager.yourString = "cool";
OR
private YourManager manage;
void Awake () {
manager = GameObject.FindObjectWithTag("manager").GetComponent<YourManager> ();
}
// In the update and in the Ray Cast function (right next to your color change line):
// In your manager file have "public bool selected;" at the top so you can access that bool from this file like:
manager.selected = true;
I detail this a little in another one of my answers HERE
For mouse clicks, I would check out the MonoDevelop functions they have in store such as:
// This file would be on the game object in the scene
// When the mouse is hovering the GameObject
void OnMouseEnter () {
selected = true;
renderer.material.color = red;
}
// When the mouse moved out
void OnMouseExit () {
selected = false;
renderer.material.color = white;
}
// Or you can use the same system as above with the:
Input.GetMouseButtonDown(0))
Resolution:
Use a bool in your manager file true is selected, false isn't. Have all the objects you instantiate have a tag, use the ray cast from the master file to the game object. When it his the game object with that tag, swap colors and sap the bool from the master file. Probably better to do it internally from the master file.
(All depends on what you're doing)
If you know what the name of the GameObjects will be at runtime, you can use GameObject.Find("") and store that in a GameObject variable. You can then set the renderer of that GameObject to whatever you like (assuming a renderer is linked to that GameObject).
The most obvious way of doing this would be to use prefabs and layers or tags.
You can add a tag to your prefab (say "Selectable") or move the prefab to some "Selectable" layer and then write your code around this, knowing that all selectable items are on this layer/have this tag.
Another way of doing this (And in my opinion is also a better way) is implementing your custom 'Selectable' component. You would search for this component on a clicked item and then perform the selection, if you have found that component. This way is better because you can add some additional selection logic in this component which would otherwise reside in your selection master script (image the size of your script after you've added a couple of selectables).
You can do it by implementing a SelectableItem script (name is arbitrary) and a couple of it's derivatives:
public class SelectableItem : MonoBehavior {
public virtual void OnSelected() {
renderer.material.color = red;
}
}
public class SpecificSelectable : SelectableItem {
public override void OnSelected() {
//You can do whatever you want in here
renderer.material.color = green;
}
}
//Adding new selectables is easy and doesn't require adding more code to your master script.
public class AnotherSpecificSelectable : SelectableItem {
public override void OnSelected() {
renderer.material.color = yellow;
}
}
And in your master script:
// Somewhere in your master selection script
// These values are arbitrary and this whole mask thing is optional, but would improve your performance when you click around a lot.
var selectablesLayer = 8;
var selectablesMask = 1 << selectablesLayer;
//Use layers and layer masks to only raycast agains selectable objects.
//And avoid unnecessary GetComponent() calls.
if (Physics.Raycast(ray, out hit, 1000.0f, selectablesMask))
{
var selectable = hit.collider.gameObject.GetComponent<SelectableItem>();
if (selectable) {
// This one would turn item red or green or yellow depending on which type of SelectableItem this is (which is controlled by which component this GameObject has)
// This is called polymorphic dispatch and is one of the reasons we love Object Oriented design so much.
selectable.OnSelected();
}
}
So say you have a couple of different selectables and you want them to do different things upon selection. This is the way you would do this. Some of your selectables would have one of the selection components and others would have another one. The logic that performs the selection resides in the Master script while the actions that have to be performed are in those specific scripts that are attached to game objects.
You can go further and add OnUnselect() action in those Selectables:
public class SelectableItem : MonoBehaviour {
public virtual void OnSelected() {
renderer.material.color = red;
}
public virtual void OnUnselected() {
renderer.material.color = white;
}
}
and then even do something like this:
//In your master script:
private SelectableItem currentSelection;
var selectable = hit.collider.gameObject.GetComponent<SelectableItem>();
if (selectable) {
if (currentSelection) currentSelection.OnUnselected();
selectable.OnSelected();
CurrentSelection = selectable;
}
And we've just added deselection logic.
DISCLAIMER: These are just a bunch of snippets. If you just copy and paste those they probably wouldn't work right away.