- Home /
Moving a 3D object with 2D swipes
I'm trying to move a 3D object in 6 possible directions using 2D swipes. I've actually accomplished that but I can only move the object one step. I want the movement to be grid based so whenever there is a swipe i increase the corresponding axis value by 1.
Depending on the length of the swipe, I want to be able to move the object further. I can imagine how to implement that, but there is no point in doing so if the movement in not updated in real time. So my real problem is that the movement only starts after the swipe is over. Also, if there is a change of direction during a swipe, the object should move in that direction too.
I have the feeling that this shouldn't be so complicated. Maybe there is another way to approach this? Am I reinventing the wheel?
Here is my code so far:
using UnityEngine;
using System.Collections;
public enum Swipe {
None,
Up,
Down,
UpLeft,
UpRight,
DownLeft,
DownRight
};
public class DetectSwipes : MonoBehaviour {
public float MinSwipeLength = 5f;
public static Swipe SwipeDirection;
public float ReturnForce = 10f;
private Vector2 _firstPressPos;
private Vector2 _secondPressPos;
private Vector2 _currentSwipe;
private Vector2 _firstClickPos;
private Vector2 _secondClickPos;
private bool objectSelected = false;
private GameObject objecte;
private void Update() {
//Raycast to find "movable" object
if (Input.GetMouseButtonDown(0)) {
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, 100.0f)) {
if(hit.collider.tag == "Movable"){
objecte = hit.collider.gameObject;
objectSelected = true;
}
}
}
if (objectSelected == true) {
DetectSwipe(objecte);
}
}
public void DetectSwipe(GameObject objecte) {
if ( Input.touches.Length > 0 ) {
Touch t = Input.GetTouch( 0 );
if ( t.phase == TouchPhase.Began ) {
_firstPressPos = new Vector2( t.position.x, t.position.y );
}
if ( t.phase == TouchPhase.Ended ) {
_secondPressPos = new Vector2( t.position.x, t.position.y );
_currentSwipe = new Vector3( _secondPressPos.x - _firstPressPos.x, _secondPressPos.y - _firstPressPos.y );
// Make sure it was a legit swipe, not a tap
if ( _currentSwipe.magnitude < MinSwipeLength ) {
SwipeDirection = Swipe.None;
return;
}
_currentSwipe.Normalize();
// Swipe up
if ( _currentSwipe.y > 0 && _currentSwipe.x > -0.5f && _currentSwipe.x < 0.5f ) {
SwipeDirection = Swipe.Up;
setDirection (SwipeDirection, objecte);
}
// Swipe down
else if ( _currentSwipe.y < 0 && _currentSwipe.x > -0.5f && _currentSwipe.x < 0.5f ) {
SwipeDirection = Swipe.Down;
setDirection (SwipeDirection, objecte);
}
// Swipe up left
else if ( _currentSwipe.y > 0 && _currentSwipe.x < 0 ) {
SwipeDirection = Swipe.UpLeft;
setDirection (SwipeDirection, objecte);
}
// Swipe up right
else if ( _currentSwipe.y > 0 && _currentSwipe.x > 0 ) {
SwipeDirection = Swipe.UpRight;
setDirection (SwipeDirection, objecte);
}
// Swipe down left
else if ( _currentSwipe.y < 0 && _currentSwipe.x < 0 ) {
SwipeDirection = Swipe.DownLeft;
setDirection (SwipeDirection, objecte);
// Swipe down right
} else if ( _currentSwipe.y < 0 && _currentSwipe.x > 0 ) {
SwipeDirection = Swipe.DownRight;
setDirection (SwipeDirection, objecte);
}
}
}
}
public void setDirection(Swipe swipeDir, GameObject objecte){
Vector3 objPosition = objecte.transform.position;
if(swipeDir == Swipe.Up){
Vector3 newPosition = new Vector3(objPosition.x, objPosition.y + 1, objPosition.z);
StartCoroutine (moveObject(objecte, newPosition));
}
else if(swipeDir == Swipe.Down){
Vector3 newPosition = new Vector3(objPosition.x, objPosition.y - 1, objPosition.z);
StartCoroutine (moveObject(objecte, newPosition));
}
else if(swipeDir == Swipe.UpLeft){
Vector3 newPosition = new Vector3(objPosition.x - 1, objPosition.y, objPosition.z);
StartCoroutine (moveObject(objecte, newPosition));
}
else if(swipeDir == Swipe.UpRight){
Vector3 newPosition = new Vector3(objPosition.x, objPosition.y, objPosition.z + 1);
StartCoroutine (moveObject(objecte, newPosition));
}
else if(swipeDir == Swipe.DownLeft){
Vector3 newPosition = new Vector3(objPosition.x + 1, objPosition.y, objPosition.z);
StartCoroutine (moveObject(objecte, newPosition));
}
else if (swipeDir == Swipe.DownRight){
Vector3 newPosition = new Vector3(objPosition.x, objPosition.y, objPosition.z + 1);
StartCoroutine (moveObject(objecte, newPosition));
}
}
public IEnumerator moveObject(GameObject objecte, Vector3 newPosition) {
float elapsedTime = 0f;
Vector3 startPosition = objecte.transform.position;
float time = 0.1f;
while (elapsedTime <= time){
objecte.transform.position = Vector3.Lerp(startPosition, newPosition, elapsedTime/time);
elapsedTime += Time.fixedDeltaTime;
yield return null;
}
objectSelected = false;
}
}
Answer by AlwaysSunny · Apr 28, 2015 at 10:54 PM
"Depending on the length of the swipe, I want to be able to move the object further...my real problem is that the movement only starts after the swipe is over...if there is a change of direction during a swipe, the object should move in that direction too."
There is a single answer to all these requirements. Or rather, a single change would make satisfying these three requirements a great deal easier. Your "swipe" algorithm needs to stop considering a single gesture, and instead "poll" for the distance / direction of the dragged object until the input state exits.
Entering this state (press finger?) begins the polling process, and exiting the state (lift finger?) ends it, so it's quite similar. The key difference is how you'll measure and respond to the input. When the input is one tile-width from the dragged entity's current tile, it begins moving in the direction suggested by the difference, and will respond to additional movement requests in the most rapid manner possible given your animation requirements.
Depending on if-and-how your camera can move, this may present a new set of challenges, lest you wind up with a 'flip flop' situation where the same input position creates a back 'n forth motion. Other challenges will emerge as you try to implement this in your particular scenario. But yeah, this is how I'd recommend approaching these requirements.
The above answer assumes you want the object to react in real time. If your intention was to use a gesture to create a path, that's a whole different thing. Similar, I guess. You'd be building a collection of tiles based on what the input suggests, and the "difference" you're looking for would be between the input and the last tile added, ins$$anonymous$$d of the input and the entity.
I've now added TouchPhase.$$anonymous$$oved ins$$anonymous$$d of TouchPhase.Ended but I still can't get the _secondPressPos variable to update as the touch moves. I also tried using a bool that becomes true if the touch is moving, and then used a coroutine to see if the variable was updating but nope :S
Answer by anubhavsd · Apr 30, 2015 at 07:16 AM
Try the following code
void Update()
{
TakeMouseInput();
}
void TakeMouseInput()
{
if(Input.GetMouseButtonDown(0))
{
startMousePos = Input.mousePosition;
}
if(Input.GetMouseButtonUp(0))
{
Vector3 endMousePos = Input.mousePosition;
SwipeOrTouch(endMousePos);
}
}
void SwipeOrTouch(Vector3 pos)
{
Vector3 dir = pos - startMousePos;
dir.Normalize();
}
with direction "dir" calculated in hand you can translate your object in that direction. If in case you want drag like situation just replace Input.GetMouseButtonUp with Input.GetMouseButton. Workable on every platform. for 3d the value you get for y place those value as z
Your answer
Follow this Question
Related Questions
How to select an object with TOUCH and change its animation 2D 1 Answer
Distribute terrain in zones 3 Answers
Diagonal swipe issues on Android 1 Answer
Door only opening once on Raycast 1 Answer