Touch buttons in XNA (with pressed, released, moved states) - c#

I am trying to make touch buttons in WP8 with all the states (Pressed, Released, Moved), but the TouchLocationState.Released is not working.
Here's my code:
Class variables:
bool touching = false;
int touchID;
Button tempButton;
Button is a separate class with a method to switch states when touched.
The Update method contains the following code:
TouchCollection touchCollection = TouchPanel.GetState();
if (!touching && touchCollection.Count > 0)
{
touching = true;
foreach (TouchLocation location in touchCollection)
{
for (int i = 0; i < menuButtons.Count; i++)
{
touchID = location.Id; // store the ID of current touch
Point touchLocation = new Point((int)location.Position.X, (int)location.Position.Y); // create a point
Button button = menuButtons[i];
if (GetMenuEntryHitBounds(button).Contains(touchLocation)) // a method which returns a rectangle.
{
button.SwitchState(true); // change the button state
tempButton = button; // store the pressed button for accessing later
}
}
}
}
else if (touchCollection.Count == 0) // clears the state of all buttons if no touch is detected
{
touching = false;
for (int i = 0; i < menuButtons.Count; i++)
{
Button button = menuButtons[i];
button.SwitchState(false);
}
}
menuButtons is a list of buttons on the menu.
A separate loop (within the Update method) after the touched variable is true
if (touching)
{
TouchLocation location;
TouchLocation prevLocation;
if (touchCollection.FindById(touchID, out location))
{
if (location.TryGetPreviousLocation(out prevLocation))
{
Point point = new Point((int)location.Position.X, (int)location.Position.Y);
if (prevLocation.State == TouchLocationState.Pressed && location.State == TouchLocationState.Released)
{
if (GetMenuEntryHitBounds(tempButton).Contains(point))
// Execute the button action. I removed the excess
}
}
}
}
The code for switching the button state is working fine but the code where I want to trigger the action is not.
location.State == TouchLocationState.Released mostly ends up being false.
(Even after I release the touch, it has a value of TouchLocationState.Moved)
And what is more irritating that it sometimes works!
I am really confused and stuck for days now. Is this the right way? If yes then where am I going wrong? Or is there some other more effective way to do this?

I finally found the solution myself. It does not need the released state of the TouchLocationState
Posting it here. Hopefully it'll help others.
Thanks if anyone was trying.
The class variables are renamed:
private Point _touchPoint;
private TouchLocation _touchLocation;
private int _touchID;
private Button _selectedButton;
private bool _touched;
private bool _launchEvent;
The update method now has the following code
TouchCollection touchCollection = TouchPanel.GetState();
if (!_touched && touchCollection.Count > 0)
{
_touched = false;
_launchEvent = false;
foreach (TouchLocation location in touchCollection)
{
for (int i = 0; i < menuButtons.Count; i++)
{
Button button = menuButtons[i];
_touchID = location.Id;
_touchPoint = new Point((int)location.Position.X, (int)location.Position.Y);
if (GetButtonHitBounds(button).Contains(_touchPoint))
{
button.SwitchState(true);
_selectedButton = button;
}
}
}
}
else if (touchCollection.Count == 0)
{
_touched = false;
for (int i = 0; i < menuButtons.Count; i++)
{
Button button = menuButtons[i];
button.SwitchState(false);
if (GetButtonHitBounds(button).Contains(_touchPoint) && _launchEvent)
{
OnReleased(i, PlayerIndex.One);
_launchEvent = false;
}
}
}
///
// This if statement checks whether the touch is still inside the button area.
// Then assigns a value of true to the _launchEvent variable.
//
// The 'try' block is used because if the first touch is not on button, then the
// value of the _selectedButton is null and it will throw an exception.
///
if (touchCollection.FindById(_touchID, out _touchLocation))
{
if (_touchLocation.State == TouchLocationState.Moved)
{
try
{
if (GetButtonHitBounds(_selectedButton).Contains((int)_touchLocation.Position.X, (int)_touchLocation.Position.Y))
_launchEvent = true;
else
_launchEvent = false;
}
catch { }
}
}

Related

UI detections working on PC but not on Android

im creating an android map game and i cant solve a problem, i have a map and i also have a menu that pops up once i press on a gameobject with a collider. I had a problem that if i would press on that UI menu it would go throught it and it would turn the menu off, because i coded that if i press on another gameobject with a collider it would turn off. I fixed that by making a UI detection script (found it on google), where it draws a raycast from my cursor and detects a gameobject with a specific layer and returns a true or false value.
THE PROBLEM: Right now everything works fine on pc, since i am hovering with my cursor, but if i go on my unity remote once i press on the menu, it still turns off, because i guess its not quick enough to detect that its a UI element?
SOME CODE:
This is a UI Detection code:
public bool isOverUI;
private void Start()
{
UILayer = LayerMask.NameToLayer("MAINMENUCOMPONENTS");
}
private void Update()
{
print(IsPointerOverUIElement() ? "Over UI" : "Not over UI");
}
//Returns 'true' if we touched or hovering on Unity UI element.
public bool IsPointerOverUIElement()
{
return IsPointerOverUIElement(GetEventSystemRaycastResults());
}
//Returns 'true' if we touched or hovering on Unity UI element.
private bool IsPointerOverUIElement(List<RaycastResult> eventSystemRaysastResults)
{
for (int index = 0; index < eventSystemRaysastResults.Count; index++)
{
RaycastResult curRaysastResult = eventSystemRaysastResults[index];
if (curRaysastResult.gameObject.layer == UILayer)
{
isOverUI = true;
return true;
}
}
isOverUI = false;
return false;
}
//Gets all event system raycast results of current mouse or touch position.
static List<RaycastResult> GetEventSystemRaycastResults()
{
PointerEventData eventData = new PointerEventData(EventSystem.current);
eventData.position = Input.mousePosition;
List<RaycastResult> raysastResults = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, raysastResults);
return raysastResults;
}
This is the menu code:
public UIDETECTIONS UID;
if (UID.isOverUI == true)
{
}
else if (UID.isOverUI == false)
{
if (infoMenuOn == false)
{
if (isCountryClicked == false)
{
isCountryClicked = true;
infoMenuOn = true;
Debug.Log("MENU ON");
}
else if (isCountryClicked == true)
{
isCountryClicked = false;
}
}
else if (infoMenuOn == true && isCountryClicked == true)
{
infoMenuOn = false;
isCountryClicked = false;
Debug.Log("MENU OFF");
}
}
I Should have done more research :D, derHugo gave me a hint, which was kind of an answer.
I found this piece of code which works for android. Works quite the same.
private bool IsPointerOverUIObject() {
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
return results.Count > 0;
}
With this code you can check if youre clicking over ui elements:
if (IsPointerOverUIObject() == true) // true or false

Unity IsPointerOverGameObject Issue

I know it's a common problem but none worked. Maybe the button setup is wrong. I have a Panel with no image, and inside a settings button on the top left that once clicked opens another scene. I tried using those 3 methods but none works. It always detects it as a Game object.
The bool isGameStarted is checking if the player should move or no.
Please guide me through
Have tried
if (Swipe.Instance.Tap && !isGameStarted)
{
if (EventSystem.current.IsPointerOverGameObject() )
{
isGameStarted = false;
}
else
{
isGameStarted = true;
motor.StartRunning();
gameCanvas.SetTrigger("Show");
}
}
Also tried using trigger but it goes through the UI.
This is the original code.
if (Swipe.Instance.Tap && !isGameStarted)
{
isGameStarted = true;
motor.StartRunning();
gameCanvas.SetTrigger("Show");
}
Once you tap on the screen the player starts moving. I need it NOT to move or start the game if clicked on the settings button.
I had the same problem until I figured out that IsPointerOverGameObject seems to return true for any GameObject (possibly with a collider) and not only UI objects.
So I wrote a custom static class to check for UI objects only. You will need to set the layer of each panel, image, button, etc. to UI for it to work.
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public static class MouseOverUILayerObject
{
public static bool IsPointerOverUIObject()
{
PointerEventData eventDataCurrentPosition = new PointerEventData(EventSystem.current);
eventDataCurrentPosition.position = new Vector2(Input.mousePosition.x, Input.mousePosition.y);
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventDataCurrentPosition, results);
for (int i = 0; i < results.Count; i++)
{
if (results[i].gameObject.layer == 5) //5 = UI layer
{
return true;
}
}
return false;
}
}
Use it like this:
private void OnMouseDown()
{
if (!MouseOverUILayerObject.IsPointerOverUIObject())
HandleClick();
}
The overload of IsPointerOverGameObject takes a parameter
int pointerId Pointer (touch / mouse) ID.
and
If you use IsPointerOverGameObject() without a parameter, it points to the "left mouse button" (pointerId = -1);
therefore when you use IsPointerOverGameObject for touch, you should consider passing a pointerId to it.
So from the example
if (Swipe.Instance.Tap && !isGameStarted)
{
if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))
{
isGameStarted = false;
return;
}
isGameStarted = true;
motor.StartRunning();
gameCanvas.SetTrigger("Show");
}
otherwise if you have multiple possible touches you could also do the check for all of them like
if (Swipe.Instance.Tap && !isGameStarted)
{
foreach(var touch in Input.touches)
{
if (EventSystem.current.IsPointerOverGameObject(touch.fingerId))
{
isGameStarted = false;
return;
}
}
isGameStarted = true;
motor.StartRunning();
gameCanvas.SetTrigger("Show");
}
also look at this thread

Check if a UI button is pressed or an alternative option Unity

I need a way to check if A UI button is pressed the on click event isn’t really helpful because the Input method (called etch time its the player’s turn) has to return a value back to the main function while loop will completely stop the game and the input should only be accepted when it’s the players turn (when players turn Method is waiting for input) , for these reasons the Unity Event Trigger doesn’t seem like a useable option .all I need is a way to check the state of the button .
Note: that im useing Start() method of an object as my Main method
if there should be any problems with that let me know
ALSO NOTE : I’m transferring the game to Unity so I want to change the input+output methods with minimal changes to the code
//TurnInput is an array of bools tracking witch buttons are being pressed
//(9 buttons)
private Block[] PlayerTurn(Block[] grid )
{
TurnNotDone = false;
while (!TurnNotDone)
{
//gets stuck unity crash
//needs to wait until player click on one of the buttons
//(when player click on a button is turn is over and the turn is
//passed to the AI)
}
for (int i = 0; i < 9; i++)
{
if (TurnInput[i]) grid[i] = SetBlock("O");
}
return grid;
}
//trigger by event trigger on button gets an int for the button Index
public void PointerDown (int i)
{
TurnInput[i] = true;
}
//trigger by event trigger on button gets an int for the button Index
public void PointerUp(int i)
{
TurnInput[i] = false;
}
Perhaps you could use coroutines instead of while loop:
gameloop coroutine "stops" to wait user input while playerTurn is true
ButtonClicked event handled set playerTurn to false (add ButtonClicked method to OnClick event handler of UI button)
AI's turn
set playerTurn to true again
goto 1
minimal example:
public class MinimalExample : MonoBehaviour {
public struct Block {
public bool isOBlock;
}
bool playerTurn;
Block[] grid;
bool[] TurnInput;
// Use this for initialization
void Start () {
grid = new Block[9];
TurnInput = new bool[9];
StartCoroutine (GameLoop());
}
// GameLoop
IEnumerator GameLoop () {
while (true) {
yield return new WaitWhile (() => playerTurn == true);
for (int i = 0; i < 9; i++) {
if (TurnInput[i]) grid[i] = SetBlock("O");
}
Debug.Log ("AI here");
playerTurn = true;
}
}
Block SetBlock(string s) {
var r = new Block ();
r.isOBlock = (s == "O");
return r;
}
//trigger by event trigger on button gets an int for the button Index
public void ButtonClicked (int i) {
TurnInput[i] = true;
playerTurn = false;
}
}

Disable a group of buttons' Interactable state by Tag

I have two groups of buttons on my play area that I'd like to toggle between. I currently have each group tagged differently in the editor and I have another button that I intend to use as the toggle to swap which buttons can be interacted with. Here's what I've got so far, but no luck. I'm getting the error on the IsInteractable line: No overload for method IsInteractable' takes1' arguments.
Where am I going wrong?
if(keySet == true)
{
// turn ON Interactable for Alpha buttons
for(int i = 0; i > GameSetup.alphaKeys.Length; i++)
{
GameObject alphaButton = GameObject.FindGameObjectWithTag("AlphaKey");
alphaButton.GetComponent<UnityEngine.UI.Button>().IsInteractable(true);
}
// turn OFF Interactable for Shape buttons
for(int i = 0; i > GameSetup.symbolKeys.Length; i++)
{
GameObject alphaButton = GameObject.FindGameObjectWithTag("SymbolKey");
alphaButton.GetComponent<UnityEngine.UI.Button>().IsInteractable(false);
}
}
else
{
// Do the reverse if false
}
Got it! I added a Canvas Group component to each group of buttons and it made it super easy to control all of the properties I needed to access.
public void HandleActiveKeySet (bool keySet)
{
if(keySet == true)
{
GameObject alphaGroup = GameObject.FindGameObjectWithTag("AlphaGroup");
alphaGroup.GetComponent<CanvasGroup>().interactable = true;
alphaGroup.GetComponent<CanvasGroup>().blocksRaycasts = true;
GameObject symbolGroup = GameObject.FindGameObjectWithTag("SymbolGroup");
symbolGroup.GetComponent<CanvasGroup>().interactable = false;
symbolGroup.GetComponent<CanvasGroup>().blocksRaycasts = false;
}
else
{
GameObject alphaGroup = GameObject.FindGameObjectWithTag("AlphaGroup");
alphaGroup.GetComponent<CanvasGroup>().interactable = false;
alphaGroup.GetComponent<CanvasGroup>().blocksRaycasts = false;
GameObject symbolGroup = GameObject.FindGameObjectWithTag("SymbolGroup");
symbolGroup.GetComponent<CanvasGroup>().interactable = true;
symbolGroup.GetComponent<CanvasGroup>().blocksRaycasts = true;
}
}

How to search for two similar images (memory game)

i try to search for 2 similar images (like in a memory game)
i know how to do it, but it for sure is not the best way i guess...
anyone has a better solution?
here is the code how i have done it
private void first_button (object sender, System.Windows.Input.GestureEventArgs e) //so button get pressed
{
field_one = true;
StoryboardBack11.Begin();
StoryboardBack11.Completed += new EventHandler(AfterAnimation);
i = i + 1;
}
// same for the other buttons
private void AfterAnimation(object sender, EventArgs e) //check here after storyboard completed
{if (i == 2) // check after 2 clicks
{
i = 0;
if (field_one == true && field_two == true)
{
if (imageUri_one.Equals(imageUri_two))
{
Fade_one.Begin(); //Storyboard starts
Fade_two.Begin();
field_one = false;
field_two = false;
}
}
//and this for every possible combination
//-> here is my problem because it is a lot to copy paste and thus not optimal i guess
if (field_one == true && field_three == true)
{
if (imageUri_one.Equals(imageUri_three))
{
Fade_one.Begin();
Fade_three.Begin();
field_one = false;
field_three = false;
}
}
// here is the shuffeling of the images
private void test1(object sender, System.Windows.Input.GestureEventArgs e)
{
List<string> Test = new List<string>(); //list of the images
Test.Add("Art1.png");
Test.Add("Art1.png");
Test.Add("Art2.png");
Test.Add("Art2.png");
Test.Add("Art3.png");
Test.Add("Art3.png");
Test.Shuffle(); //they get randomly shuffled here and then realigned
imageUri_one = Test[0];
imageUri_two = Test[1];
imageUri_three = Test[2];
// ..... and so on
// put the new image Uri to a button -> the same 6 time for everey button
BitmapImage bm_one = new BitmapImage(new Uri(#imageUri_one, UriKind.RelativeOrAbsolute));
image11.Source = bm_one; //but it in xaml Source
}
so the thing is that i want to make the Uri flexible, so that i can shuffle different Uri when using another list and this should already work. but is there a more elegant way to check for similar images?
hope the question is clear :)
Pseudo-code:
public class MyElement
{
public bool IsPressed { get; set; }
public string Uri { get; set; }
... anything else you want to know about that one tile
}
then build the logical board
MyElement[,] tiles = new MyElement[8, 8];
for(int i = 0; i < 8; i++)
{
for(j = 0; j < 8; j++)
{
tiles[i, j] = new MyElement { IsPressed = false; Uri = whatever; ... };
}
}
Now create the "physical" board with the buttons and assign a custom value for all buttons which contains it's coordinates.
Create one click handler where you check the tiles array for that coordinate and check it's MyElement object. Assign this click handler to all button click event.

Categories

Resources