I have this script which i created to detect UP and DOWN swipes. All it needs to do is change the UI text..
The script is below:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class TouchControls : MonoBehaviour
{
private Vector2 startPos;
Text instruction;
void start() {
instruction = GetComponent<Text>();
}
float swipeValue = 0.0f;
void Update()
{
#if UNITY_ANDROID
if (Input.touchCount > 0){
Touch touch = Input.touches[0];
if(touch.phase == TouchPhase.Began){
startPos = touch.position;
}
else if(touch.phase == TouchPhase.Ended){
swipeValue = Mathf.Sign(touch.position.y - startPos.y);
if (swipeValue > 0){//up swipe
instruction.text="UP";
}
else if (swipeValue < 0){//down swipe
instruction.text="DOWN";
}
}
}
#endif
}
}
It is not working and I cannot understand why? Any help please?
Just to make sure, are you testing for the touch on the actual device or in the editor? The code should work on the device, but will not do so in the Editor to my knowledge.
You will need to check for input by using
Input.GetMouseButtonUp(0); //returns true if the button has been released
Input.GetMouseButtonDown(0); //returns true if the button has been pressed
and
Vector3 touch = Input.mousePosition; //returns the mouse position
instead.
This is the solution to the problem I had managed on Unity version 5.1.1
void Update () {
#if UNITY_IOS || UNITY_ANDROID
//iOS Controls (same as Android because they both deal with screen touches)
//if the touch count on the screen is higher than 0, then we allow stuff to happen to control the player.
if(Input.touchCount > 0){
foreach(Touch touch1 in Input.touches) {
if (touch1.phase == TouchPhase.Began) {
firstPosition = touch1.position;
lastPosition = touch1.position;
}
if (touch1.phase == TouchPhase.Moved) {
lastPosition = touch1.position;
}
if (touch1.phase == TouchPhase.Ended) {
if (firstPosition.y - lastPosition.y < -80) {
//Up
} else {
//Down
}
}
}
#endif
Related
I want to get an image like in the picture with code. I stacked boxes because i must add joint with code. I want to make the boxes look like this as the character slides left and right smoothly. And how can i smooth swerving control in unity for touch or mouse button?
I tried this codes for movement:
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
firstPos = touch.position;
if (touch.phase == TouchPhase.Stationary || touch.phase == TouchPhase.Moved)
Swerving(touch.position);
}
private void Swerving(Vector2 touch)
{
endPos = touch;
float diff = endPos.x - firstPos.x;
transform.Translate(diff * Time.deltaTime * swerveSpeed, 0, 0);
}
But not smooth swerving.
I tried hinge joint for image. I tried random values to motor,spring etc. But it didnt work i have never used joints.
In general when dealing with physics you shouldn't use transform this break collision detection and other physics related things like your joints etc.
Try and rather go through the Rigidbody using e.g. Rigidbody.MovePosition (or accordingly Rigidbody2D.MovePosition if your are in 2D) within FixedUpdate like e.g.
// or Rigidbody2D depending on your needs
[SerializeField] private Rigidbody _rigidbody;
private Vector2 startPos;
private float movement;
private void Awake()
{
if(!_rigidbody) rigidbody = GetComponent<Rigidbody>();
}
// get user input in Update in general
private void Update()
{
if (Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
switch(touch.phase)
{
case TouchPhase.Began:
startPos = touch.position;
movement = 0;
break;
case TouchPhase.Stationary:
case TouchPhase.Moved:
movement = touch.position.x - startPos.x;
break;
default:
movement = 0;
}
}
}
// Apply Physics in FixedUpdate!
private void FixedUpdate()
{
_rigidbody.MovePosition(_rigidbody.position + Vector3.right * movement * Time.deltaTime * swerveSpeed);
}
However, in general the touch is a 2D pixel space position which might be quite different on different devices.
I would rather translate it into a 3D world space position and use something like e.g.
[SerializeField] private Rigidbody _rigidbody;
[SerializeField] private Camera _mainCamera;
private float _offset;
private Plane? _hitPlane;
private Vector3 _targetPosition;
private void Awake()
{
if (!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
if (!_mainCamera) _mainCamera = Camera.main;
}
// get user input in Update in general
private void Update()
{
_targetPosition = _rigidbody.position;
if (Input.touchCount <= 0)
{
return;
}
var touch = Input.GetTouch(0);
switch (touch.phase)
{
case TouchPhase.Began:
{
// Check if you are touching the character
var ray = _mainCamera.ScreenPointToRay(touch.position);
if (Physics.Raycast(ray, out var hit) && hit.rigidbody == _rigidbody)
{
// create a virtual plane parallel to the camera view
// passing the hit point
_hitPlane = new Plane(-ray.direction, hit.point);
// also store the offset from pivot to the hit point
// we only care about the X axis
_offset = (_rigidbody.position - hit.point).x;
}
break;
}
case TouchPhase.Stationary:
case TouchPhase.Moved:
{
if (_hitPlane.HasValue)
{
// now instead keep ray casting against that virtual plane
var ray = _mainCamera.ScreenPointToRay(touch.position);
if (_hitPlane.Value.Raycast(ray, out var distance))
{
var hitPoint = ray.GetPoint(distance);
_targetPosition.x = hitPoint.x + _offset;
}
}
break;
}
default:
_hitPlane = null;
break;
}
}
// Apply Physics in FixedUpdate!
private void FixedUpdate()
{
_rigidbody.MovePosition(_targetPosition);
}
this makes sure your character is definitely placed on the X axis where you are dragging it without any delays but still complying with physics
I'm creating an Android game with Unity. There are only three ways to control the movement of the character:
Tap in the right half of the screen: jump to the right
Tap in the left half of the screen: jump to the left
Swipe upwards: character dashes forward
In theory, I know that I can differentiate the touches with the TouchPhases (began, moved, stationary and ended). When only detecting the taps without caring for swipes, I just checked if the phase of the touch began and made the player jump. That felt fast on my device.
However, because I have to consider that a swipe may follow, I can not initiate the jump action until I detected ThouchPhase.Ended. This leads to a very slow responding character, which doesnt jump until the user rises his finger of the screen.
I tried to use ThouchPhase.Moved and ThouchPhase.Stationary instead to simulate a immediate response but my solution is pretty bad in terms of detecting the difference between a tap and a swipe:
Vector2 startTouchPosition;
Vector2 endTouchPosition;
Vector2 currentSwipe;
void Update()
{
if (Input.touches.Length > 0)
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
if (touch.phase == TouchPhase.Began)
{
//save began touch 2d point
startTouchPosition = new Vector2(touch.position.x, touch.position.y);
}
if (touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary)
{
//save ended touch 2d point
endTouchPosition = new Vector2(touch.position.x, touch.position.y);
if (endTouchPosition.y - startTouchPosition.y < 5)
{
if (touch.position.x > (Screen.width / 2))
{
JumpToRight();
}
else if (touch.position.x < (Screen.width / 2))
{
JumpToLeft();
}
}
else
{
//create vector from the two points
currentSwipe = new Vector2(endTouchPosition.x - startTouchPosition.x, endTouchPosition.y - startTouchPosition.y);
//normalize the 2d vector
currentSwipe.Normalize();
//swipe upwards
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
DashForward();
}
}
}
}
}
}
Here is the code I used. I tested and it works but sometimes, I noted a delay. Let me know if it is good enough for you. Basically you dont need to go through all touches if you dont need multi-touch. And you just need Begin and End touch phases.
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class touch : MonoBehaviour {
private Vector2 startTouchPosition;
private Vector2 endTouchPosition;
private Vector2 currentSwipe;
public Text textbox;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.touches.Length > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
//save began touch 2d point
startTouchPosition = new Vector2(touch.position.x, touch.position.y);
}
if (touch.phase == TouchPhase.Ended)
{
//save ended touch 2d point
endTouchPosition = new Vector2(touch.position.x, touch.position.y);
//create vector from the two points
currentSwipe = new Vector2(endTouchPosition.x - startTouchPosition.x, endTouchPosition.y - startTouchPosition.y);
//normalize the 2d vector
currentSwipe.Normalize();
if(Mathf.Abs(currentSwipe.y) < 0.1f && Mathf.Abs(currentSwipe.x) < 0.1f)
{
if (touch.position.x > (Screen.width / 2))
{
textbox.text= "jump right";
}
else if (touch.position.x < (Screen.width / 2))
{
textbox.text= "jump left";
}
}
if (currentSwipe.y > 0 && currentSwipe.x > -0.5f && currentSwipe.x < 0.5f)
{
textbox.text= "Dash forward";
}
}
}
}
}
Right now I've been developing a game which will make the character move up or down if either swipe up or down on the left side of the screen. Then, he can also, shoot projectiles if I tap the right side of the screen. I've succeeded on making it work but the problem is that the swipe function do not works while I tap the the right screen. Both only works if I do one of them. I cannot move the character if I am firing projectiles. Any suggestions? Appreciate it in advanced.
Here's the code:
For the swipe movement function:
void Swipe() {
if (Input.touchCount > 0) {
Touch t = Input.GetTouch(0);
if (t.phase == TouchPhase.Began)
{
lp = t.position;
fp = t.position;
text.text = fp.x.ToString();
}
else if (t.phase == TouchPhase.Ended)
{
lp = t.position;
//Swipe Up
if (fp.y < lp.y && fp.x < 400)
{
currentLane += 1;
}
//Swipe Down
else if (fp.y > lp.y && fp.x < 400)
{
currentLane -= 1;
}
}
}
}
And here's the code for the tap or firing projectiles function:
void FireBullets() {
interval += 2 * Time.deltaTime;
anim.SetBool("Attacking", firing);
if (Input.touchCount > 0 && interval > .75f) {
Vector3 bulletTouchPos;
Touch bulletT = Input.GetTouch(0);
bulletTouchPos = bulletT.position;
if (bulletT.phase == TouchPhase.Began) {
if (bulletTouchPos.x > 400)
{
interval = 0;
firing = true;
//Fire Bullets
Instantiate(bullets, new Vector3(transform.position.x + 1.2f, transform.position.y + .3f, transform.position.z), Quaternion.identity);
}
}
}else
{
firing = false;
}
}
Your lp and fp values don't care which finger is being checked.
If you want to detect multiple touch gestures at once, you need to discriminate your detection based on which finger that is.
You can do this by looking at the Touch.fingerId value, which is unique for each finger. Fingers are just an ID assigned to a given touching point as it moves across the screen in order to identify it from other touching points currently also on the screen.
You'll need to adjust your code to handle how to store the information you need in order to do what you need, but this should get you started.
using UnityEngine;
using System.Collections;
public class PlayerScript : MonoBehaviour {
public static float distanceTraveled;
private Touch curTouch;
public float speed;
public float maxSpeed;
public float maxSpeedConstant;
//Virtual buttons left and right half of the screen
private Rect leftHalf = new Rect(0F,0F,Screen.width/2,Screen.height);
private Rect rightHalf = new Rect(Screen.width/2,0F,Screen.width/2,Screen.height);
public void Update() {
distanceTraveled = transform.localPosition.x;
}
public void FixedUpdate() {
Movement ();
}
public void Movement() {
//Accelerometer Control up/down
Vector3 dirAcc = Vector3.zero;
dirAcc.y = Input.acceleration.y*.5F;
transform.Translate(0F,0F,dirAcc.y);
if(Input.touchCount != 0){
Vector2 curTouch = Input.GetTouch(0).position;
if (leftHalf.Contains (curTouch)){
transform.Translate(-Vector3.right*speed*Time.deltaTime);
}else{
if (rightHalf.Contains(curTouch)){
transform.Translate(Vector3.right*speed*Time.deltaTime);
}
}
}else{
if(Input.touchCount == 0){
transform.Translate(Vector3.right*speed*Time.deltaTime);
}
}
}
}
What I'm trying to achieve is that the play is able to control the up/down movement of the character via accelerometer and right/left movement by touching the right/left side of the screen.
With the above code the touch area does not matter the character will always move backwards and accelerometer input is entirely ignored. What bothers me is that the above code (accelerometer part only) worked with transform.Translate instead of rigidbody.AddForce. But from what I've read on the internet I'm going to need rigidbodies if I want collisions.
So any help or advice regarding code structure/syntax or solution towards my problem is appreciated.
On first look for the up/ down movement you are trying to change the z value which is possibly the forward movement. Another issue could be for your calculation of the touch position. It is better to covert the touch position to the camera's viewport and check for the left or right positions. A simple implementation would be like this. Add this code to any object in the scene.
using UnityEngine;
using System.Collections;
public class PlayerScript: MonoBehaviour {
public void FixedUpdate ( ) {
Movement ( );
}
public void Movement ( ) {
//Accelerometer Control up/down
Vector3 dirAcc = Vector3.zero;
Vector3 mousePosition = Vector3.zero;
#if UNITY_ANDROID
dirAcc.y = Input.acceleration.y * .5F;
if(Input.touchCount > 0) {
mousePosition = Camera.main.ScreenToViewportPoint ( Input.touches[0].position );
}
#elif UNITY_EDITOR
if( Input.GetKey ( KeyCode.W ) ) {
dirAcc = Vector3.up * Time.deltaTime;
}
else if(Input.GetKey(KeyCode.S)) {
dirAcc = Vector3.down * Time.deltaTime;
}
if(Input.GetMouseButton(0)) {
mousePosition = Camera.main.ScreenToViewportPoint ( Input.mousePosition );
}
#endif
if( mousePosition.x > 0 ) {
if( mousePosition.x > 0.5f ) { // right side of the screen
dirAcc += Vector3.right * Time.deltaTime;
}
else {
dirAcc += Vector3.left * Time.deltaTime;
}
}
transform.Translate ( dirAcc );
}
}
I have not tested this on a device.
I'm trying to get unity to recognize that I am swiping left to right, I have solved that but my issue is that it doesn't understand this till I lift my finger off the screen.
My question is how would i make it so that it knows i went right and then left and then right again all without ever taking my finger of the screen
Here is the code I have so far
using UnityEngine;
using System.Collections;
public class Gestures : MonoBehaviour {
private Vector2 fingerStart;
private Vector2 fingerEnd;
public int leftRight = 0;
public int upDown = 0;
void Update () {
foreach(Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fingerStart = touch.position;
fingerEnd = touch.position;
}
if (touch.phase == TouchPhase.Moved )
{
fingerEnd = touch.position;
}
if(touch.phase == TouchPhase.Ended)
{
if((fingerStart.x - fingerEnd.x) > 80 || (fingerStart.x - fingerEnd.x) < -80) // Side to side Swipe
{
leftRight ++;
}
else if((fingerStart.y - fingerEnd.y) < -80 || (fingerStart.y - fingerEnd.y) > 80) // top to bottom swipe
{
upDown ++;
}
if(leftRight >= 3){
leftRight = 0;
}
if(upDown >= 4){
upDown = 0;
}
}
}
}
}
The issue you're facing is because you've done your checks in the TouchPhase.Ended. What you want to do is perform your checks in TouchPhase.Moved, with a smaller change in value (you're using 80 in Ended, try something like 10 if you the code doesn't work)
Unity's documentation on TouchPhase http://docs.unity3d.com/ScriptReference/TouchPhase.html
foreach(Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fingerStart = touch.position;
fingerEnd = touch.position;
}
if (touch.phase == TouchPhase.Moved )
{
fingerEnd = touch.position;
if((fingerStart.x - fingerEnd.x) > 80 ||
(fingerStart.x - fingerEnd.x) < -80) // Side to side Swipe
{
leftRight ++;
}
else if((fingerStart.y - fingerEnd.y) < -80 ||
(fingerStart.y - fingerEnd.y) > 80) // top to bottom swipe
{
upDown ++;
}
if(leftRight >= 3){
leftRight = 0;
}
if(upDown >= 4){
upDown = 0;
}
//After the checks are performed, set the fingerStart & fingerEnd to be the same
fingerStart = touch.position;
}
if(touch.phase == TouchPhase.Ended)
{
leftRight = 0;
upDown = 0;
fingerStart = Vector2.zero;
fingerEnd = Vector2.zero;
}
If you want to explicitly check for a pattern (i.e. left -> right -> left), rather than just checking if it's some lateral / vertical movement as the code you have will do, try the below code. Just remember to include System.Collentions.Generic & System.Linq namespaces
private Vector2 fingerStart;
private Vector2 fingerEnd;
public enum Movement
{
Left,
Right,
Up,
Down
};
public List<Movement> movements = new List<Movement>();
void Update () {
foreach(Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began) {
fingerStart = touch.position;
fingerEnd = touch.position;
}
if(touch.phase == TouchPhase.Moved) {
fingerEnd = touch.position;
//There is more movement on the X axis than the Y axis
if(Mathf.Abs(fingerStart.x - fingerEnd.x) > Mathf.Abs(fingerStart.y - fingerEnd.y)) {
//Right Swipe
if((fingerEnd.x - fingerStart.x) > 0)
movements.Add(Movement.Right);
//Left Swipe
else
movements.Add(Movement.Left);
}
//More movement along the Y axis than the X axis
else {
//Upward Swipe
if((fingerEnd.y - fingerStart.y) > 0)
movements.Add(Movement.Up);
//Downward Swipe
else
movements.Add(Movement.Down);
}
//After the checks are performed, set the fingerStart & fingerEnd to be the same
fingerStart = touch.position;
//Now let's check if the Movement pattern is what we want
//In this example, I'm checking whether the pattern is Left, then Right, then Left again
Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left } ));
}
if(touch.phase == TouchPhase.Ended)
{
fingerStart = Vector2.zero;
fingerEnd = Vector2.zero;
movements.Clear();
}
}
}
private bool CheckForPatternMove (int startIndex, int lengthOfPattern, List<Movement> movementToCheck) {
//If the currently stored movements are fewer than the length of the pattern to be detected
//it can never match the pattern. So, let's get out
if(lengthOfPattern > movements.Count)
return false;
//In case the start index for the check plus the length of the pattern
//exceeds the movement list's count, it'll throw an exception, so lets get out
if(startIndex + lengthOfPattern > movements.Count)
return false;
//Populate a temporary list with the respective elements
//from the movement list
List<Movement> tMovements = new List<Movement>();
for(int i = startIndex; i < startIndex + lengthOfPattern; i++)
tMovements.Add(movements[i]);
//Now check whether the sequence of movements is the same as the pattern you want to check for
//The SequenceEqual method is in the System.Linq namespace
return tMovements.SequenceEqual(movementToCheck);
}
EDIT Added some more code as a sample
//The idea of a pattern match is to check for the exact same set of swipe gesture.
//This requires the following conditions to be met
// (a) The List of movements that need to be checked must be at least as long as the List of movements to check against.
// (b) The correct indices should be used for the startIndex. In this case I'm just using 0 as the startIndex.
// (c) Remember to clear the List right after you get a true return from the method, otherwise the next return will most likely be a false.
//Example - Training set is Left -> Right -> Left (This is what we want to check)
// Step 1 - User swipes LEFT, method returns false because there are too few Movements to check
// Step 2 - User swipes RIGHT, method returns false (same reason as above)
// Step 3a - User swipes RIGHT (L, R, R now) - false, incorrect pattern (L, R, R instead of L, R, L)
// Step 3b - User swipes LEFT (L, R, L now) - TRUE, Correct pattern!
//Immediately clear if Step 3b happens otherwise Step 4 will occur
// Step 4 - User swipes L or R (direction is immaterial right now), and method will return FALSE
// if you use the last three indexes!
//Pre-populating the movements List with L, R, L
movements = new List<Movement>()
{
Movement.Left,
Movement.Right,
Movement.Left
};
//Checking a match against an L, R, L training set
//This prints true to the console
Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left } ));
Here's how my Update function looks like. Note the usage of GetMouseButton over Input.touch
void Update () {
//Example usage in Update. Note how I use Input.GetMouseButton instead of Input.touch
//GetMouseButtonDown(0) instead of TouchPhase.Began
if (Input.GetMouseButtonDown(0)) {
fingerStart = Input.mousePosition;
fingerEnd = Input.mousePosition;
}
//GetMouseButton instead of TouchPhase.Moved
//This returns true if the LMB is held down in standalone OR
//there is a single finger touch on a mobile device
if(Input.GetMouseButton(0)) {
fingerEnd = Input.mousePosition;
//There was some movement! The tolerance variable is to detect some useful movement
//i.e. an actual swipe rather than some jitter. This is the same as the value of 80
//you used in your original code.
if(Mathf.Abs(fingerEnd.x - fingerStart.x) > tolerance ||
Mathf.Abs(fingerEnd.y - fingerStart.y) > tolerance) {
//There is more movement on the X axis than the Y axis
if(Mathf.Abs(fingerStart.x - fingerEnd.x) > Mathf.Abs(fingerStart.y - fingerEnd.y)) {
//Right Swipe
if((fingerEnd.x - fingerStart.x) > 0)
movements.Add(Movement.Right);
//Left Swipe
else
movements.Add(Movement.Left);
}
//More movement along the Y axis than the X axis
else {
//Upward Swipe
if((fingerEnd.y - fingerStart.y) > 0)
movements.Add(Movement.Up);
//Downward Swipe
else
movements.Add(Movement.Down);
}
//After the checks are performed, set the fingerStart & fingerEnd to be the same
fingerStart = fingerEnd;
//Now let's check if the Movement pattern is what we want
//In this example, I'm checking whether the pattern is Left, then Right, then Left again
Debug.Log (CheckForPatternMove(0, 3, new List<Movement>() { Movement.Left, Movement.Right, Movement.Left } ));
}
}
//GetMouseButtonUp(0) instead of TouchPhase.Ended
if(Input.GetMouseButtonUp(0)) {
fingerStart = Vector2.zero;
fingerEnd = Vector2.zero;
movements.Clear();
}
}