Unity. how can I get Touch by fingerID? - c#

We have the index of the touches and method Input.GetTouch(int index) which returns Touch. Also we have fingerID property of Touch structure. How can we get a Touch by fingerID?

For getting a specific touch by ID you have to search for it in the existing touches.
private static bool TryGetTouch(int fingerID, out Touch touch)
{
foreach(var t in Input.touches)
{
if(t.fingerID == fingerID)
{
touch = t;
return true;
}
}
// No touch with given ID exists
touch = default;
return false;
}
You can also use linq and do e.g.
using System.Linq;
...
private static bool TryGetTouch(int fingerID, out Touch touch)
{
try
{
touch = Input.touches.First(t => t.fingerID == fingerID);
return true;
}
catch
{
// No touch with given ID exists
touch = default;
return false;
}
}
and use it like
if(TryGetTouch (someFingerID, out var touch))
{
// use touch here
}
else
{
// probably use a new touch and store its fingerID
}

Related

How to spawn player correctly in the correct position?

I don't know what else to do. I've done everything from disabling the character controller, then changing the position, then re-enabling the character controller. I have Auto Sync Transforms turned on. I've tried changing transform.position, I've tried changing the character controller position, I've tried everything and nothing works. I'm at my wits end here just trying to move my character from one point to another. Why is this the hardest thing I've done?
The code instantiates my characters correctly when it wants to. Sometimes they spawn off the map or in some random position way off from my spawn point.
public string spawnPointName;
public GameObject malePlayerSystems;
public GameObject femalePlayerSystems;
public GameObject playerInScene;
public Transform spawnPoint;
private Transform playerObject;
public Vector3 spawnPointPosition;
public bool inGame = false;
public bool maleKnight = false;
public bool femaleKnight = false;
public bool spawnRunning;
public bool moveRunning;
public IEnumerator SpawnPlayer()
{
spawnRunning = true;
yield return new WaitForSecondsRealtime(0.5f);
if (spawnRunning)
{
spawnPoint = GameObject.Find(spawnPointName).transform;
//playerInScene = GameObject.FindGameObjectWithTag("Gameplay Systems");
if (playerInScene != null)
{
spawnRunning = false;
yield return null;
}
else
{
if (maleKnight && !femaleKnight)
{
Instantiate(malePlayerSystems, spawnPoint.position, Quaternion.identity);
playerInScene = malePlayerSystems;
playerObject = malePlayerSystems.transform.Find("Player1/Player Base");
playerObjectCC = playerObject.GetComponent<CharacterController>();
}
if (femaleKnight && !maleKnight)
{
Instantiate(femalePlayerSystems, spawnPoint.position, Quaternion.identity);
playerInScene = femalePlayerSystems;
playerObject = femalePlayerSystems.transform.Find("Player1/Player Base");
playerObjectCC = playerObject.GetComponent<CharacterController>();
}
if (maleKnight && femaleKnight)
{
Debug.LogError("Error: Both gender switches active. Choose one gender to play as.");
}
}
spawnRunning = false;
}
}
public void DestroyPlayer()
{
playerInScene = GameObject.FindGameObjectWithTag("Gameplay Systems");
if (playerInScene != null)
{
Destroy(playerInScene);
} else
{
Debug.LogError("Error: Cannot find player to delete");
}
}
public IEnumerator movePlayer(){
moveRunning = true;
yield return new WaitForSecondsRealtime(0.5f);
if (moveRunning){
spawnPoint = GameObject.Find(spawnPointName).transform;
spawnPointPosition = spawnPoint.transform.position;
playerObjectCC.enabled = false;
Debug.Log("Disabled CC");
yield return new WaitForSecondsRealtime(0.5f);
playerObject.transform.position = new Vector3(spawnPointPosition.x, spawnPointPosition.y, spawnPointPosition.z);
Debug.Log("New Position is " + playerObject.transform.position);
yield return new WaitForSecondsRealtime(0.5f);
playerObjectCC.enabled = true;
Debug.Log("Re enabled CC");
}
moveRunning = false;
}

How to fix in-game double-click issue in Unity?

I have this issue with double clicking in-game. I wrote this code that checks for input and returns the type of input it received.
In editor it works just fine, but when I export the game it always returns double click type. Even if I click just once. Not sure what's causing this issue..
Below is the mouse input script and other is how I use it in other scripts.
Mouse Input script:
using System.Collections;
using UnityEngine.EventSystems;
public class MouseInput : MonoBehaviour
{
#region Variables
private enum ClickType { None, Single, Double }
private static ClickType currentClick = ClickType.None;
readonly float clickdelay = 0.25f;
#endregion
void OnEnable()
{
StartCoroutine(InputListener());
}
void OnDisable()
{
StopAllCoroutines();
}
public static bool SingleMouseClick()
{
if (currentClick == ClickType.Single)
{
currentClick = ClickType.None;
return true;
}
return false;
}
public static bool DoubleMouseClick()
{
if (currentClick == ClickType.Double)
{
currentClick = ClickType.None;
return true;
}
return false;
}
private IEnumerator InputListener()
{
while (enabled)
{
if (Input.GetMouseButtonDown(0))
{ yield return ClickEvent(); }
yield return null;
}
}
private IEnumerator ClickEvent()
{
if (EventSystem.current.IsPointerOverGameObject()) yield break;
yield return new WaitForEndOfFrame();
currentClick = ClickType.Single;
float count = 0f;
while (count < clickdelay)
{
if (Input.GetMouseButtonDown(0))
{
currentClick = ClickType.Double;
yield break;
}
count += Time.deltaTime;
yield return null;
}
}
}
Usage:
if (MouseInput.SingleMouseClick())
{
Debug.Log("Single click");
Select(true);
}
else if (MouseInput.DoubleMouseClick())
{
Debug.Log("Double click");
Select(false);
}
So on the frame Input.GetMouseButtonDown(0) evaluates to true you call into ClickEvent() which then yields on WaitForEndOfFrame(); then eventually gets back to another Input.GetMouseButtonDown(0)).
You problem is that WaitForEndOfFrame() waits until the end of the current frame:
Waits until the end of the frame after all cameras and GUI is
rendered, just before displaying the frame on screen.
It doesn't wait until the next frame. Because of this, all values returned by the Input API are still going to be the same. You want a yield return null instead of WaitForEndOfFrame().

Unity3D using OnTriggerStay

I'm using the event OnTriggerStay2D to destroy an object, the reason i'm using this instead of OnTriggerEnter2D is because i'm dragging the object using the touchscreen, and i want to destroy it after it is released, the problem i have is that OntriggerStay2D is not always called, so sometimes the object is not destroyed after it is released and it has to be moved again to work, i've read the docummentation from Unity
OnTriggerStay is called almost all the frames for every Collider other that is touching the trigger.
public void OnTriggerStay2D(Collider2D other)
{
if (gameObject.tag == other.tag) {
Destroy (other.gameObject);
}
}
I would like to know if there's any way to call OntriggerStay2D everytime i release the object.
Thanks.
Edit
Dragging code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Drag : MonoBehaviour {
private bool draggingItem = false;
private GameObject draggedObject;
private Vector2 touchOffset;
void Update ()
{
if (HasInput)
{
DragOrPickUp();
}
else
{
if (draggingItem)
DropItem();
}
}
Vector2 CurrentTouchPosition
{
get
{
Vector2 inputPos;
inputPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
return inputPos;
}
}
private void DragOrPickUp()
{
var inputPosition = CurrentTouchPosition;
if (draggingItem)
{
draggedObject.transform.position = inputPosition + touchOffset;
}
else
{
RaycastHit2D[] touches = Physics2D.RaycastAll(inputPosition, inputPosition, 0.5f);
if (touches.Length > 0)
{
var hit = touches[0];
if (hit.transform != null && hit.rigidbody != null)
{
draggingItem = true;
draggedObject = hit.transform.gameObject;
touchOffset = (Vector2)hit.transform.position - inputPosition;
}
}
}
}
private bool HasInput
{
get
{
return Input.GetMouseButton(0);
}
}
public void DropItem()
{
draggingItem = false;
}
}
Avoid using OnTriggerStay2D for this. You can use a boolean variable that you set to true and false in the OnTriggerEnter2D and OnTriggerExit2D function.
bool isTouching = false;
void OnTriggerEnter2D(Collider2D collision)
{
Debug.Log("Entered");
if (collision.gameObject.CompareTag("YourOtherObject"))
{
isTouching = true;
}
}
void OnTriggerExit2D(Collider2D collision)
{
Debug.Log("Exited");
if (collision.gameObject.CompareTag("YourOtherObject"))
{
isTouching = false;
}
}
You can now check the isTouching variable when the object is released.
if(isTouching){
....
}
Note that I suggest you abandon your current code that uses Raycast and Input.GetMouseButton(0); since you are using this on mobile devices too. You should be using Unity's new EventSystem for this since it is made to be mobile friendly too.
Since you are using 2D collider, see #7 from this answer.
Here is a complete example of how to drag a Sprite with the new EventSystem. Combine that with the answer above and you get a much more better solution.

The collision work but I don't know how know the collsiion direction

I have do a collision with my map the collision work but when my player have a collision I stop the movement of the player and he don't walk because I don't know how stop the player for one direction
its my code collision under the player and the map
public bool IsCollisionTile(Rectangle player)
{
foreach(Rectangle rect in this._collisionObject)
{
if (rect.Intersects(player))
{
return true;
}
}
return false;
}
Its the code for the player don't move is in the Game1 class
if (mapLoader.IsCollisionTile(player.getDestinationRect()))
{
player.setCantWalk(true);
}
Its the function update and setCantWalk in the class Player.cs
private bool _cantWalk;
public void Update()
{
this._destinationRectangle.X = (int)_position.X;
this._destinationRectangle.Y = (int)_position.Y;
this._destinationRectangle.Width = _texture.Width;
this._destinationRectangle.Height = _texture.Height;
if(Keyboard.GetState().IsKeyDown(Keys.Up))
{
if (_cantWalk == false)
{
_position.Y--;
}
}
else if (Keyboard.GetState().IsKeyDown(Keys.Down))
{
if (_cantWalk == false)
{
_position.Y++;
}
}
else if (Keyboard.GetState().IsKeyDown(Keys.Right))
{
if (_cantWalk == false)
{
_position.X++;
}
}
else if (Keyboard.GetState().IsKeyDown(Keys.Left))
{
if (_cantWalk == false)
{
_position.X--;
}
}
}
public void setCantWalk(bool walk)
{
_cantWalk = walk;
}
Thinks to help me
For the simpler approach, you need to keep the record of the movements of your objects. So, when checking for overlaps, you know what movement in a direction caused the overlap. Then, set the variable cantWalkX or cantWalkY for that object.
A better solution would be checking for collision surfaces to determine obstacles. This requires you to change your intersect routine to return the intersecting objects, and depending on their relative position, prevent movement in that direction. For example, if the colliding object is to the right of your object, Set cantWalkXPositive. If there is another on the left, set cantWalkXNegative to true etc...

Assignment referring to wrong object

I'm making a game using monogame and trying to use a controller manager to manage user input.
I've created a class ControllerManager to do this. Because I'm trying to take input from 2 controllers, I create three instances of ControllerManager: controllerManager, controller1Manager and controller2Manager.
Now, in my player object I have a local variable, localManager to which I need to assign to either controller1Manager or controller2Manager depending on which player it is.
I've been trying to assign it like:
this.localManager = Controller1Manager;
This results in the localManager variable being set to controllerManager.
So does anyone see what I'm doing wrong? I have no idea other than maybe it has something to do with pointers/references/singleton but I've checked the component list and each individual manager is in there.
Edit:
As requested, here are the constructor, class creation and where I'm trying to change values
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using GDApp;
namespace GDLibrary
{
public class ControllerManager : GameComponent, IService
{
public GamePadState newState, oldState;
public PlayerIndex player;
public ControllerManager(Main game, PlayerIndex index)
: base(game)
{
this.player = index;
}
public override void Update(GameTime gameTime)
{
oldState = newState;
newState = GamePad.GetState(player);
base.Update(gameTime);
}
public bool IsFirstButtonPress(Buttons button)
{
if (oldState.IsButtonUp(button) && newState.IsButtonDown(button))
return true;
return false;
}
public bool IsButtonDown(Buttons button)
{
return newState.IsButtonDown(button);
}
public bool IsButtonUp(Buttons button)
{
return newState.IsButtonUp(button);
}
#region Thumbsticks
//Right
//Magnitude of right stick in right direction
public float RightStickRight()
{
if (newState.ThumbSticks.Right.X <= 0)
return 0;
else
return newState.ThumbSticks.Right.X;
}
//Magnitude of right stick in left direction
public float RightStickLeft()
{
if (newState.ThumbSticks.Right.X >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Right.X);
}
//Magnitude of right stick in upward direction
public float RightStickUp()
{
if (newState.ThumbSticks.Right.Y >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Right.Y);
}
//Magnitude or right stick in downward direction
public float RightStickDown()
{
if (newState.ThumbSticks.Right.Y <= 0)
return 0;
else
return newState.ThumbSticks.Right.Y;
}
//Left
//Magnitude of left stick in right direction
public float LeftStickRight()
{
if (newState.ThumbSticks.Left.X <= 0)
return 0;
else
return newState.ThumbSticks.Left.X;
}
//Magnitude of left stick in left direction
public float LeftStickLeft()
{
if (newState.ThumbSticks.Left.X >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Left.X);
}
//Magnitude of left stick in upward direction
public float LeftStickUp()
{
if (newState.ThumbSticks.Left.Y >= 0)
return 0;
else
return System.Math.Abs(newState.ThumbSticks.Left.Y);
}
//Magnitude or right stick in downward direction
public float LeftStickDown()
{
if (newState.ThumbSticks.Left.Y <= 0)
return 0;
else
return newState.ThumbSticks.Left.Y;
}
#endregion
public bool RightStickCentered()
{
if (newState.ThumbSticks.Right.X.Equals(0) && newState.ThumbSticks.Right.Y.Equals(0))
{
return true;
}
return false;
}
public bool LeftStickCentered()
{
if (newState.ThumbSticks.Left.X.Equals(0) && newState.ThumbSticks.Left.Y.Equals(0))
{
return true;
}
return false;
}
public Vector2 RightStick()
{
return this.newState.ThumbSticks.Right;
}
public Vector2 LeftStick()
{
return this.newState.ThumbSticks.Left;
}
public bool LeftStickMoved()
{
if (!oldState.ThumbSticks.Left.X.Equals(newState.ThumbSticks.Left.X) || !oldState.ThumbSticks.Left.Y.Equals(newState.ThumbSticks.Left.Y))
{
return true;
}
return false;
}
public bool RightStickMoved()
{
if (!oldState.ThumbSticks.Right.X.Equals(newState.ThumbSticks.Right.X) || !oldState.ThumbSticks.Right.Y.Equals(newState.ThumbSticks.Right.Y))
{
return true;
}
return false;
}
}
}
Creating managers:
this.controller1Manager = new ControllerManager(this, PlayerIndex.One);
Components.Add(controller1Manager);
IServiceContainer.AddService(typeof(ControllerManager), controller1Manager);
this.controller2Manager = new ControllerManager(this, PlayerIndex.Two);
Components.Add(controller2Manager);
IServiceContainer.AddService(typeof(ControllerManager), controller2Manager);
Changing values:
if (this.index.Equals(PlayerIndex.One))
{
this.localManager = Controller1Manager;
}
else if (this.index.Equals(PlayerIndex.Two))
{
this.localManager = Controller2Manager;
Controller2Manager.player = index;
}
This issue has been resolved by passing a ControllerManager into the PlayerObject in place of a PlayerIndex. The reason all of the controllerManagers seemed to have their variables changed at once was their inclusion in the IServiceContainer shown in the edits above. IServiceContainer stores only one instance of a given type (It's a Dictionary) so only the most recent addition was being saved.

Categories