Logic for detecting swipe direction - c#

Basically what I am trying to do is create some code that will register when a touch has swiped across the screen, so I can move my character by touch controls.
What I have written only seems to work sometimes, and when it does it makes the character move multiple times.
Here is my code :
if (Input.touches [0].phase == TouchPhase.Ended) {
Debug.Log (Input.touches [0].deltaPosition);
if (Input.touches[0].deltaPosition.y > Input.touches[0].deltaPosition.x || Input.touches[0].deltaPosition.y > (-Input.touches[0].deltaPosition.x))
movePlayer ("Up");
if ((-Input.touches[0].deltaPosition.y) > Input.touches[0].deltaPosition.x || (-Input.touches[0].deltaPosition.y) > (-Input.touches[0].deltaPosition.x))
movePlayer ("Down");
if ((-Input.touches[0].deltaPosition.x) > Input.touches[0].deltaPosition.y || (-Input.touches[0].deltaPosition.x) > (-Input.touches[0].deltaPosition.y))
movePlayer ("Left");
if (Input.touches[0].deltaPosition.x > Input.touches[0].deltaPosition.y || Input.touches[0].deltaPosition.x > (-Input.touches[0].deltaPosition.y))
movePlayer ("Right");
}
Any advice would be really helpful

Once you've made a decision, you don't need to run anymore tests, so this would be an ideal time for using else if and else
if()
{
}
else if()
{
}
else
{
}
to ensure that only a single case could execute.
However... I think your testing is flawed. Wouldn't the following be more appropriate?
var dp = Input.touches[0].deltaPosition;
if(Math.Abs(dp.x) > Math.Abs(dp.y))
{
//gesture had more horizonal movement
if(dp.x < 0)
{
//left
}
else
{
//right
}
}
else
{
//gesture had more vertical movement
if(dp.y < 0)
{
//up
}
else
{
//down
}
}

I wrote this simple tutorial wich is basically 7 lines of code and works like a charm. Easy and simple.
You just have to use te build in Unity event system instead to write long and useless code.
No need to use an update or fixed update.

Related

Issue with Touch and slide in Unity3D

I have a game where you slide some stuff and when you find the special one. Instead of sliding you need to just tap on it. For this I created the following code, but it's not working as I wanted to:
void Update()
{
if (Input.touchCount > 0)
{
// get the first one
Touch firstTouch = Input.GetTouch(0);
// if it began this frame
if (firstTouch.phase == TouchPhase.Began)
{
if (firstTouch.position.x > screenCenter)
{
Anim.SetBool("Swiper", true);
print("Swipe");
}
}
else if (firstTouch.phase == TouchPhase.Stationary)
{
if (E.FInt == 1)
{
//Sound
print("Debugged");
SceneManager.LoadScene(Beh.SceneArray[Beh.Counter]);
}
}
}
}
The problem here is that it executes the code of when you slide even if you just tap.
Lets look at this section:
// if it began this frame
if (firstTouch.phase == TouchPhase.Began)
{
if (firstTouch.position.x > screenCenter)
{
Anim.SetBool("Swiper", true);
print("Swipe");
}
}
If the touch-phase is Began and the the touch is on the right side of the screen, then CLEARLY it's a swipe.
No, no its not. It's a touch that is just beginning. It hasn't had a chance to be swiped yet.

Why won't Unity SetActive execute within Input.GetButtonDown()?

I'm completely stumped by this one. I have a book in game and when you are looking in its general direction while within a certain distance of it and press the Action button (e or left mouse click), it's supposed to display a UI panel (bookPage). Here's my code for it.
void Update () {
Vector3 direction = player.transform.position - this.transform.position;
angle = Vector3.Angle (direction, player.transform.forward);
distance = direction.magnitude;
if (angle >= 160 && distance <= 2 && !bookPage.activeSelf) {
if(Input.GetButtonDown("Action")) {
bookPage.SetActive (true);
}
}
if (bookPage.activeSelf && Input.GetButtonDown("Action")) {
bookPage.SetActive (false);
}
}
This doesn't work. Specifically, the line to set the page to active doesn't work. If it's open, it will close correctly. If I copy and paste bookPage.SetActive (true);
anywhere within this method besides within if(Input.getButtonDown("Action")){}, it will make the bookPage active. If I put Debug.Log("message"); within that if statement though, it will show up in the console. It's just the one line that sets bookPage to active that isn't working. I have no idea why. I've tried moving it to a different method then calling it and doing the same but using a Coroutine. Neither worked. I also tried using other keys which did work, but I need it to work with the action key. It's also worth noting that the action key works in other usage. I already use it to open doors. Has anyone else run into a problem like this?
When you call SetActive(true), activeSelf will return true for your second condition which will invoke SetActive(false) immediately after.
Change this;
if (angle >= 160 && distance <= 2 && !bookPage.activeSelf)
{
if (Input.GetButtonDown("Action"))
{
bookPage.SetActive(true);
}
}
if (bookPage.activeSelf && Input.GetButtonDown("Action"))
{
bookPage.SetActive(false);
}
To this;
if (angle >= 160 && distance <= 2 && !bookPage.activeSelf)
{
if (Input.GetButtonDown("Action"))
{
bookPage.SetActive(true);
}
}
else if (bookPage.activeSelf && Input.GetButtonDown("Action"))
{
bookPage.SetActive(false);
}

How to start more than one animation with unity animator?

I have an animatormanager able to create run time animation from 1 animation (start frame, end frame and delay then the speed is calculated, will do morphing and more later). My unity version is 5.3.1f1
Everything work fine, some stuff are not done but are optional. The animator can queue requested animation to prevent interupting the current one.
The thing is, I can only start 1 time an animation with an object. The code to launch the next animation is exactly the same but there is just nothing to do.
Event if its 2 time the same animation with the same animation data
All formula are good and tested.
I did intensive debugging with breakpoint to make sure everything is fine at any point
Is there something to prevent me from starting an animation 2 time on an object one after an other?. I have no error or warning at all. The first animation work fine no matter the settings I put in my AnimData struct, but the second time, nothing happen.
Here is the essential:
public int? startAnim(int index)
{
if(index < animIndex.Count)
{
startAnim(animIndex[index]);
}
return null;
}
//private because the struct is internal, this make sure the animator keep control of the list.
private int? startAnim(AnimData animD)
{
if(locked)
{
#if UNITY_EDITOR
Debug.Log("anim locked");
#endif
return null;
}
//current anim (queue anim) not finished
if(endTime > Time.time)
{
if(canQueue)
{
addToQueue(animD);
return animDataQ.Count;
}
else
{
return null;
}
}
else
{
endTime = Time.time + animD.TotalTime;
StartCoroutine(animManager(animD));
return 0;
}
return null;
}
#endregion anim starters
private IEnumerator animManager(AnimData animData)
{
animator.speed = Mathf.Abs(animData.calculateSpeed(animLength, AnimType.main, currentKey).Value);
//animator.Play(0,0, animData.StartKey/animLength);
if(animData.AnimSpeed > 0)
{
animator.Play(0,0, animData.StartKey/animLength/2);
}
else
{
//animator.Play(0,0, (animLength * 2) - (animData.StartKey/animLength));
animator.Play(0,0, (((animLength*2) - animData.StartKey)/(animLength * 2)));
}
//animator.Play(0,0, (animData.AnimSpeed > 0) ? animData.StartKey/animLength : ((animLength * 2) - (animData.StartKey/animLength)));
yield return new WaitForSeconds(animData.Delay);
animator.Stop();
yield return null;
endAnim();
}
private void addToQueue(AnimData animD)
{
animDataQ.Enqueue(animD);
endTime += animD.TotalTime;
queueTime += animD.TotalTime;
}
private void endAnim()
{
if(canQueue && animDataQ.Count > 0)
{
StartCoroutine(animManager(animDataQ.Dequeue()));
}
}
Thanks for your time.
i found a work around.
I dont want to mark it as an accepted solution since its not "clean" in my opinion
there is certainly some kind of problem with the animator for some specific case like mine.
my solution was to use animator.speed = 0 instead of animator.stop();
everything worked instantly with that small change
i will ask my question to the unity forum because there is something strange for sure

Touch Controls Unity2D

Im trying to use touch controls to move my character on a device such as an iPhone. So far I have had limited success. This code works but only with one of the buttons. I have both a left and right button and the left button worked until I added the right button. Now only the right button works. Any help would be appreciated.
foreach (Touch touch in Input.touches)
{
if(leftButton.guiTexture.HitTest(touch.position) && touch.phase != TouchPhase.Ended)
{
move = -1;
anim.SetFloat ("Speed", Mathf.Abs (move));
}
else if(rightButton.guiTexture.HitTest(touch.position) && touch.phase != TouchPhase.Ended)
{
move = 1;
anim.SetFloat ("Speed", Mathf.Abs (move));
}
else if((leftButton.guiTexture.HitTest(touch.position) && touch.phase == TouchPhase.Ended) &&
(rightButton.guiTexture.HitTest(touch.position) && touch.phase == TouchPhase.Ended))
{
move = 0;
}
}
An much easier alternative method for clicking would be
if(Input.GetMouseButtonDown(0))
{
//Your stuff here
}
remember to change input for clickable object (which i think is touch)
First, do a sanity check and verify that the left and right buttons are setup correctly on your component.
I'm not currently on a computer with unity to test everything, but there is a lot of redundancy here, we can clean it up to make debugging the problem easier. Another red flag is I don't see move being set to 0 before the input check, so I'll add that. Try this code and see if you are still seeing the problem, and perhaps you will be able to better debug with monodevelop what is happening.
move = 0;
bool isLeftPressed = false;
bool isRightPressed = false;
foreach (Touch touch in Input.touches)
{
// Only process touches that aren't in the ended phase
if (touch.phase == TouchPhase.Ended)
return;
if (leftButton.guiTexture.HitTest(touch.position))
isLeftPressed = true;
if (rightButton.guiTexture.HitTest(touch.position))
isRightPressed = true;
}
if (isLeftPressed && isRightPressed)
{
// Do nothing when both are pressed (move already set to 0)
}
else if (isLeftPressed)
{
move = -1;
}
else if (isRightPressed)
{
move = 1;
}
anim.SetFloat ("Speed", Mathf.Abs (move));
I made a few assumptions about what you were trying to do with the check if both left and right are pressed. Rather than setting the move value in the foreach loop, we just set flags so that after processing each touch we can see which buttons are being pressed (If finger 0 is touching one, and finger 1 is touching the other, I assume that means you want there to be no movement?)

Unity3d how to reference swipe control from another script?

I have tried every which way possible to get this to work with no success. I have a swipe script and a game/control script. I am trying to reference the swipe control in my control script as the means to control my character. So far I am getting only one error from within Unity.
Assets/RuinRunStarterKit/Scripts/csTempleRun.cs(307,25): error CS1501: No overload for method UpdatePlayer' takes0' arguments
I've tried adding TouchDetector.enTouchType within the parenthesis of UpdatePlayer but that gives me three errors rather than just one. I've contacted numerous people and visited numerous sites looking for answers but have failed to yield a working result. I am not educated in programming. I have only researched online to figure out how to do something as far as programming goes. The second script I have here is from an Asset I purchased on the Unity Asset Store. I have contacted them for support for adding swipe controls and they emailed me the touch script but failed to tell me how to implement it. I just want to play this game on my phone with swipe as the controls. This is for personal use. I would really really appreciate it if someone could help me achieve the desired results. Again, I want to be able to control the character using swipe. Thank you. Here are my scripts:
TouchDetector.cs;
using UnityEngine;
using System.Collections;
public class TouchDetector : MonoBehaviour {
public delegate void deTouchEvent
(enTouchType touchType);
public static event
deTouchEvent
evTouchEvent;
public enum enTouchType
{
SwipeLeft,
SwipeRight,
SwipeDown,
SwipeUp,
}
void Start ()
{
}
void Update ()
{
if (evTouchEvent == null)
return;
if (Input.GetKeyDown(KeyCode.UpArrow )) evTouchEvent(enTouchType.SwipeUp );
if (Input.GetKeyDown(KeyCode.DownArrow )) evTouchEvent(enTouchType.SwipeDown );
if (Input.GetKeyDown(KeyCode.LeftArrow )) evTouchEvent(enTouchType.SwipeLeft );
if (Input.GetKeyDown(KeyCode.RightArrow)) evTouchEvent(enTouchType.SwipeRight);
if (Input.touchCount > 0)
{
foreach (Touch t in Input.touches)
{
Vector3 swipe = t.deltaPosition * t.deltaTime;
if (swipe.y > 0.5f) evTouchEvent(enTouchType.SwipeUp );
if (swipe.y < -0.5f) evTouchEvent(enTouchType.SwipeDown );
if (swipe.x > 0.5f) evTouchEvent(enTouchType.SwipeRight);
if (swipe.x < -0.5f) evTouchEvent(enTouchType.SwipeLeft );
}
}
}
}
csTempleRun.cs;
void Update ()
{
UpdatePlayer();
if (m_player != null)
{
// Make the camera follow the player (if active)
SmoothFollow sF = (SmoothFollow)Camera.mainCamera.GetComponent(typeof(SmoothFollow));
sF.target = m_player.transform;
// Check for collisions with interactive objects
UpdateCoins();
UpdateMines();
// Dynamically update the track
CreateNewCellsIfNeeded(false);
}
}
private void UpdatePlayer(TouchDetector.enTouchType T)
{
// if the player is dead (replaced with ragdoll) then exit since none of this code should fire.
if (m_player == null)
{
return;
}
// Gradually increase the players' running speed, and update the animation to match.
m_playerRunSpeed += Time.deltaTime * 0.005f;
m_playerRunSpeed = Mathf.Clamp(m_playerRunSpeed, 0.5f, 3.0f);
m_player.animation["run"].speed = m_playerRunSpeed * 2.0f;
// ****************************************************************************************
// INPUT
// Player can only turn if they are not already sliding / jumping.
// Equally, sliding / jumping are mutually exclusive.
if (Input.GetKeyDown (KeyCode.LeftArrow)&& m_playerJump <= -1.0f && m_playerSlide <=0.0f)
{
if (m_playerDirection == enCellDir.North) m_playerNextDirection = enCellDir.West;
if (m_playerDirection == enCellDir.East ) m_playerNextDirection = enCellDir.North;
if (m_playerDirection == enCellDir.South) m_playerNextDirection = enCellDir.East;
if (m_playerDirection == enCellDir.West ) m_playerNextDirection = enCellDir.South;
}
if (Input.GetKeyDown(KeyCode.RightArrow) && m_playerJump <= -1.0f && m_playerSlide <=0.0f)
{
if (m_playerDirection == enCellDir.North) m_playerNextDirection = enCellDir.East;
if (m_playerDirection == enCellDir.East ) m_playerNextDirection = enCellDir.South;
if (m_playerDirection == enCellDir.South) m_playerNextDirection = enCellDir.West;
if (m_playerDirection == enCellDir.West ) m_playerNextDirection = enCellDir.North;
}
if (T==TouchDetector.enTouchType.SwipeDown && m_playerJump <= -1.0f && m_playerSlide <=0.0f)
{
m_playerSlide = 1.0f;
m_player.animation.Play("slide_fake");
}
if ((Input.GetKeyDown(KeyCode.UpArrow) || Input.GetKeyDown(KeyCode.Space)) && m_playerJump <= -1.0f && m_playerSlide <=0.0f)
{
AudioSource.PlayClipAtPoint(m_jumpAudio, m_player.transform.position);
m_playerJump = 1.0f;
m_playerYvel = 0.0f;
m_player.animation.Play("jump");
}
I hope I'm not doing anything wrong by posting this script but I feel I need to post this in order to get the help I need. You'll notice in the csTempleRun.cs script that I replaced one of the KeyCode calls with TouchDetector.enTouchType.SwipeDown. Yet I am still getting an error. Thank you in advance for anyone's help. Thank you for your time as well.
Look at your error - No overload for method UpdatePlayer' takes0' arguments. It means that you need to supply an additional data to your method. Which data you need to supply intellisense can tell you.
In your code:
void Update ()
{
UpdatePlayer();
...
You call UpdatePlayer() with zero arguments. However, UpdatePlayer needs an argument:
private void UpdatePlayer(TouchDetector.enTouchType T)
{
So, when you call UpdatePlayer(), you need to send an object of the type TouchDetector.enTouchType as parameter. That would be one of the following:
SwipeLeft
SwipeRight
SwipeDown
SwipeUp

Categories

Resources