Know How many Buttons of the Joystick Are pressed in unity input unity system - unity3d

I recently asked a similar question with keyboard, and was able to solve it, now I'm using input unity system to do the same thing but with joystick control.
With this code it detects 1, but when I press a second button it appears as if the first one had stopped pressing it. I would like that if I press 1 it increases to 1 and if I press two it increases to two and so on.
public class JoystickInput : MonoBehaviour
{
ControlOfInputs ControlOfInputsScript;
private InputAction test;
private InputActionReference Actionreference;
public float[] Contadores;
public int BotonesPresionados;
void Awake()
{
ControlOfInputsScript = new ControlOfInputs();
// ControlOfInputsScript.Gameplay.Arriba. += ctx => Fire();
}
private void OnEnable()
{
ControlOfInputsScript.Enable();
}
private void OnDisable()
{
ControlOfInputsScript.Disable();
}
// Update is called once per frame
private void Update()
{
//Boton Arriba
if (ControlOfInputsScript.Gameplay.Arriba.WasPerformedThisFrame())
{
Debug.Log("Presionado");
BotonesPresionados++;
}
if (ControlOfInputsScript.Gameplay.Arriba.WasReleasedThisFrame())
{
Debug.Log("DejoDePresionar");
BotonesPresionados--;
}
//Boton Abajo
if (ControlOfInputsScript.Gameplay.abajo.WasPerformedThisFrame())
{
Debug.Log("Presionado");
BotonesPresionados++;
}
if (ControlOfInputsScript.Gameplay.abajo.WasReleasedThisFrame())
{
Debug.Log("DejoDePresionar");
BotonesPresionados--;
}

Related

How to set the position of a gameobject into initial position after grabbing ended using hand in SteamVR using Unity?

Pretty new to VR.I took a gameobject from an intial position by grabbing.When I grab a helmet and touch my body collider it hides the helmet.So next I may pick glasses and apply it to my body(Hides the GameObject).Next when I put the Incorrect Helmet the first helmet should go back to its initial position and should be seen in the scene.Similarily there are many GameObjects in the scene
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Helmet")
{
HideGameObject();
}
if (other.gameObject.tag == "Glasses")
{
HideGameObject();
}
if (other.gameObject.tag == "EarMuff")
{
HideGameObject();
}
if (other.gameObject.tag == "IncorrectHelmet")
{
HideGameObject();
}
if (other.gameObject.tag == "IncorrectGlasses")
{
HideGameObject();
}
if (other.gameObject.tag == "IncorrectEarMuff")
{
HideGameObject();
sendPickValues.Invoke(2, 0);
}
}
//Another script to set the GameObjects position
public class BackToPosition : MonoBehaviour
{
private Vector3 initialPosition;
private Quaternion initialRotation;
GameObject prevObject;
GameObject currObject;
// Start is called before the first frame update
void Start()
{
initialPosition = transform.position;
initialRotation = transform.rotation;
}
// Update is called once per frame
void Update()
{
}
public void BackToInitialPosition()
{
Debug.Log("Entered");
transform.position = initialPosition;
transform.rotation = initialRotation;
}
}
I am not trying to set the previous grabbed object to initial position.I may select wrong helmet first and pick many other matching gameobjects and later change to correct helmet.At that time first helmet should go to initial position.
This is a script that I use in SteamVR to grab and release a boat's rudder handle but it should be usable for you too:
[RequireComponent(typeof(Interactable))]
public class HandAttacher : MonoBehaviour
{
public UnityEvent OnGrab;
public UnityEvent OnRelease;
public UnityEvent OnHandEnter;
public UnityEvent OnHandLeave;
private Interactable interactable;
void Awake()
{
interactable = GetComponent<Interactable>();
}
/// this magic method is called by hand while hovering
protected virtual void HandHoverUpdate(Hand hand)
{
GrabTypes startingGrabType = hand.GetGrabStarting();
if (interactable.attachedToHand == null && startingGrabType != GrabTypes.None)
{
hand.AttachObject(gameObject, startingGrabType, Hand.AttachmentFlags.DetachFromOtherHand | Hand.AttachmentFlags.ParentToHand);
OnGrab?.Invoke();
}
}
protected virtual void OnHandHoverBegin(Hand hand)
{
OnHandEnter?.Invoke();
}
protected virtual void OnHandHoverEnd(Hand hand)
{
OnHandLeave?.Invoke();
}
protected virtual void HandAttachedUpdate(Hand hand)
{
if (hand.IsGrabEnding(gameObject))
{
hand.DetachObject(gameObject);
OnRelease?.Invoke();
}
}
}
Basically it creates Unity Events that you can add Listeners to in the Editor's Inspector window, or in code.
So in your use case, I would add a listener to OnRelease, and reset the GameObject's position and rotation to whatever it was before.
I tried using BackToPosition or something similar in Update comparing the original position to its current to reset the object's position, and the object keeps resetting on a loop instead of resetting to its original position and stopping.

Unity - Problem with Holding Mouse Button Multiple times

A little background: I am making a small bit of game that involves clicking and dragging a clock hand to add time to a bank. The issue I'm having is with the clicking and dragging process. After an amount of time or multiple clicks, clicking on the clock face no longer works to make the variable "isActive" true. I've confirmed that it stops working somewhere in the code below and not in the code that checks isActive. Thanks for the help.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ClockFace : MonoBehaviour
{
public bool isActive = false;
public bool isAble = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (isActive)
{
if (Input.GetButtonUp("Fire1"))
{
isActive = false;
}
}
if (Input.GetButtonDown("Fire1"))
{
if (isAble)
{
isActive = true;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Mouse"))
{
isAble = true;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Mouse"))
{
isAble = false;
}
}
}
Unitys old imput system is't very good now that the new imput system is out. It comes in the unity 2019.3 update, but you can install it from the package manager in earlier versions. I recomend to use that.

Using a timer in conjunction with 2 push buttons from arduino

So I am using two push buttons (connected to an Arduino Uno) as an input to my game. The player has to push down both buttons at the same time for the character to move in the game. I want the player to hold down the buttons for a different amount of time in each level. I have a working Arduino and a working Unity timer and player script, but am not able to get the code to do what I want. What I basically want is that only when the player presses the buttons down, does the timer start counting down. Right now, the timer starts as soon as the scene begins. I know that I somehow have to reference the timer script to the button object, I have tried this but it still doesn't work. Note that the timer UI does have a Timer tag on it. I have also referenced the Player Controller script in the Timer script. Right now, Its giving me a range of errors. I have attached an image depicting these errors.error image
The Timer script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class Timer : MonoBehaviour
{
//int startTime = 0;
public bool buttonPressed = false;
public int timeLeft;
public Text countdownText;
GameObject Character;
void Awake()
{
Character = GameObject.FindWithTag("Player");
}
public void Start()
{
//StartCoroutine("LoseTime");
BeginTimer();
}
void Update()
{
countdownText.text = ("Time Left = " + timeLeft);
if (timeLeft <= 0)
{
//StopCoroutine("LoseTime");
//countdownText.text = "Times Up!";
Invoke("ChangeLevel", 0.1f);
}
}
public void BeginTimer()
{
Character.GetComponent<PlayerController>().Update();
//gameObject.GetComponent<MyScript2>().MyFunction();
if (buttonPressed == true )
{
StartCoroutine("LoseTime");
}
else if (buttonPressed == false)
{
StopCoroutine("LoseTime");
}
}
IEnumerator LoseTime()
{
while (true)
{
yield return new WaitForSeconds(1);
timeLeft--;
}
}
void ChangeLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
The Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO.Ports;
public class PlayerController : MonoBehaviour
{
SerialPort sp = new SerialPort("\\\\.\\COM4", 9600);
//player == GameObject.FindWithTag("Player").GetComponent<>();
public float Speed;
public Vector2 height;
public float xMin, xMax, yMin, yMax;
public bool buttonPressed = false;
GameObject Character;
public void Awake()
{
Character = GameObject.FindWithTag("Player");
}
public void Start()
{
if (!sp.IsOpen)
{ // If the erial port is not open
sp.Open(); // Open
}
sp.ReadTimeout = 1; // Timeout for reading
}
public void Update()
{
if (sp.IsOpen)
{ // Check to see if the serial port is open
try
{
string value = sp.ReadLine();//To("Button"); //Read the information
int button = int.Parse(value);
//float amount = float.Parse(value);
//transform.Translate(Speed * Time.deltaTime, 0f, 0f); //walk
if (button == 0) //*Input.GetKeyDown(KeyCode.Space*/) //jump
{
buttonPressed = true;
Character.GetComponent<Rigidbody2D>().AddForce(height, ForceMode2D.Impulse);
Character.GetComponent<Rigidbody2D>().position = new Vector3
(
Mathf.Clamp(GetComponent<Rigidbody2D>().position.x, xMin, xMax),
Mathf.Clamp(GetComponent<Rigidbody2D>().position.y, yMin, yMax)
);
Timer tmr = GameObject.Find("Timer").GetComponent<Timer>();
tmr.BeginTimer();
}
}
catch (System.Exception)
{
}
}
void ApplicationQuit()
{
if (sp != null)
{
{
sp.Close();
}
}
}
}
}
I think the problem may be with how I am referencing the scripts in each other.
In your timer you have a quite strange mixup of Update and Coroutine. Also note that BeginTimer is called exactly once! You also shouldn't "manually" call Update of another component.
I wouldn't use Update at all here. Simply start and stop a Coroutine.
The Timer script should only do the countdown. It doesn't have to know more:
public class Timer : MonoBehaviour
{
public int timeLeft;
public Text countdownText;
private bool timerStarted;
public void BeginTimer(int seconds)
{
// Here you have to decide whether you want to restart a timer
timeLeft = seconds;
// or if you rather want to continue counting down
//if(!timerStarted) timeLeft = seconds;
StartCoroutine(LoseTime());
}
public void StopTimer()
{
StopAllCoroutines();
}
private IEnumerator LoseTime()
{
timerStarted = true;
while (timeLeft > 0)
{
yield return new WaitForSeconds(1);
timeLeft --;
countdownText.text = $"Time Left = {timeLeft}";
}
// Only reached after the timer finished and wasn't interrupted meanwhile
// Using Invoke here is a very good idea since we don't want to interrupt anymore
// if the user lets go of the button(s) now
Invoke(nameof(ChangeLevel), 0.1f);
}
void ChangeLevel()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
}
}
In general avoid to use Find at all. If anyhow possible already reference things in the Inspector! If needed you can use Find but only once! What you never want to do is use any of the Find and GetComponent variants repeatedly - rather store the reference the first time and re-use it - and especially not in Update no a per frame basis. They are very expensive calls!
public class PlayerController : MonoBehaviour
{
public float Speed;
public Vector2 height;
// I prefer to use Vector2 for such things
public Vector2 Min;
public Vector2 Max;
public bool buttonPressed = false;
// Already reference these via the Inspector if possible!
public Rigidbody2D Character;
public Timer timer;
public Rigidbody2D _rigidbody;
private SerialPort sp = new SerialPort("\\\\.\\COM4", 9600);
private void Awake()
{
FetchReferences();
}
// This is my "secret" tip for you! Go to the component in the Inspector
// open the ContextMenu and hit FetchReferences
// This already stores the references in the according fields ;)
[ContextMenu("FetchReferences")]
private void FetchReferences()
{
if(!Character)Character = GameObject.FindWithTag("Player"). GetComponent<Rigidbody2D>();
if(!timer) timer = GameObject.Find("Timer").GetComponent<Timer>();
}
private void Start()
{
if (!sp.IsOpen)
{
sp.Open(); // Open
}
sp.ReadTimeout = 1;
}
private void Update()
{
// I wouldn't do the serialport open check here
// your if block simply silently hides the fact that your application
// doesn't work correctly! Rather throw an error!
try
{
string value = sp.ReadLine(); //Read the information
int button = int.Parse(value);
//TODO: Since it isn't clear in your question how you get TWO buttons
//TODO: You will have to change this condition in order to only fire if both
//TODO: buttons are currently pressed!
buttonPressed = button == 0;
if (buttonPressed)
{
Character.AddForce(height, ForceMode2D.Impulse);
// The clamping of a rigidbody should always be done ine FixedUpdate!
// Pass in how many seconds as parameter or make the method
// parameterless and configure a fixed duration via the Inspector of the Timer
timer.BeginTimer(3.0f);
}
else
{
// Maybe stop the timer if condition is not fulfilled ?
timer.StopTimer();
}
}
catch (System.Exception)
{
// You should do something here! At least a Log ...
}
}
private void FixedUpdate()
{
// Here I wasn't sure: Are there actually two different
// Rigidbody2D involved? I would assume you rather wanted to use the Character rigidbody again!
Character.position = new Vector3(Mathf.Clamp(Character.position.x, Min.x, Max.x), Mathf.Clamp(Character.position.y, Min.y, Max.y));
}
// Did you mean OnApplicationQuit here?
private void ApplicationQuit()
{
if (sp != null)
{
{
sp.Close();
}
}
}
}
Typed on smartphone but I hope the idea gets clear

Wait for some time in between onMouseDown() function in unity2D

I have built this 2D project in unity where you tap on blocks and they destroy using the onMouseDown() function. My problem is after tapping a block and it destroys, how can I make the player wait for a certain amount of time before he can tap on another block in the game. I have tried using PlayerPrefs and subtracting Time.deltaTime from a certain float variable but it did not work.
Note: all the blocks share the same destroy script!!!
float waitTime = 1.5f;
static float lastClickTime = float.NegativeInfinity;
void OnMouseDown ()
{
float time = Time.time;
if( time > ( lastClickTime + waitTime ) )
{
lastClickTime = time;
DestroyThisBlock();
}
}
If they all share the same script, you can start with defining a static bool variable and a static event, say:
public static bool isLockedDown = false;
public static event Action onBlockDestroyed;
Then, on destruction function, first keep a check about this locked down. If this is false, then destroy, turn the lock to true, and invoke the static listener that'll be read by another script, which in turn will start a coroutine that'll turn this static lock to false after given set of seconds.
public class Block : MonoBehaviour {
void DestroyBlock()
{
if(isLockedDown)
return;
isLockedDown = true;
onBlockDestroyed.Invoke();
////destroy block///
}
}
public classBlockManager : MonoBehaviour {
void Awake()
{
Block.onBlockDestroyed += BeginUnlocking
}
void BeginUnlocking()
{
StartCoroutine(UnlockTimer);
}
IEnumerator UnlockTimer()
{
yield return new WaitForSeconds(1f);
BLock.isLockedDown = false;
}
}

How to calculate sensitivity based on the width/height of the screen?

Here's my idea: I wanted to have a scrollview where the user could both scroll the component in it, and click on it.
After hours of testing/search, I've finally managed to make this working with the following code.
My problem is in the comparison Math.Abs(eventData.delta.x) > 1.0f. I consider that if the mouse "moves more than 1.0f" then it's dragging, else I consider this as a click.
The value 1.0f works perfectly on all the devices with a mouse = it's easy not to move, and big screen (tablets), when you click. But on smartphones, ie my Galaxy S6 or the 3 other ones I've tried, it's very sensitive and almost impossible to make a click.
How could you programmatically handle this? Is there a DPI or something to take in account and based on this, multiply my 1.0f by the resolution?
public class BoardHandler : EventTrigger
{
private static GameObject _itemDragged;
private static bool _isDragging;
private static ScrollRect _scrollRect;
public override void OnPointerClick(PointerEventData data)
{
if (_isDragging) {
return;
}
Debug.Log("Click");
}
public override void OnBeginDrag(PointerEventData eventData)
{
if (Math.Abs(eventData.delta.x) > 1.0f ||
Math.Abs(eventData.delta.y) > 1.0f) {
_scrollRect.OnBeginDrag(eventData);
_isDragging = true;
}
}
public override void OnDrag(PointerEventData eventData)
{
if (_isDragging) {
_scrollRect.OnDrag(eventData);
}
}
public override void OnEndDrag(PointerEventData eventData)
{
if (!_isDragging) {
return;
}
_scrollRect.OnEndDrag(eventData);
_isDragging = false;
}
private void Start()
{
_scrollRect = GetComponentInParent<ScrollRect>();
}
}
I've used TouchScript in the past to cover multiple devices within one project, like from 9 screens 6k screen array to tablets. They have a set of utilities to handle multiple resolution and dpi.
Check out the the UpdateResolution method in TouchManagerInstance.
hth.