That is my code to try and simulate a swipe gesture so when I build to mobile I know it will work. Nothing is being logged and I am confused on why it seems to not work. I want it to print out in the console that I either swiped RTL (Right to Left) or LTR (Left to right). I do not see what I am doing wrong.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
startPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (Input.GetMouseButtonUp(0))
{
endPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (startPosition != endPosition && startPosition != Vector3.zero && endPosition != Vector3.zero)
{
float deltaX = endPosition.x - startPosition.x;
float deltaY = endPosition.y - startPosition.y;
if ((deltaX > 5.0f || deltaX < -5.0f) && (deltaY >= -1.0f || deltaY <= 1.0f))
{
if (startPosition.x < endPosition.x)
{
print("LTR");
}
else
{
print("RTL");
}
}
startPosition = endPosition = Vector3.zero;
}
}
I can spot some few problems in your code. It's not a good idea to compare Vector3 with == or !=. Approximate comparison is fine. You are using Input.GetMouseButtonDown on a mobile platform.
You need to use Input.touches to do this. Loop over it, store the beginning position in TouchPhase.Began and then the end position in TouchPhase.Ended. You can then use both variables to figure it which direction the finger went.
The code below detects swipe direction even when the finger is not yet released with the help of TouchPhase.Moved. You can disable that by enabling the detectSwipeOnlyAfterRelease boolean variable. You can also modify SWIPE_THRESHOLD for sensitivity.
public class SwipeDetector : MonoBehaviour
{
private Vector2 fingerDown;
private Vector2 fingerUp;
public bool detectSwipeOnlyAfterRelease = false;
public float SWIPE_THRESHOLD = 20f;
// Update is called once per frame
void Update()
{
foreach (Touch touch in Input.touches)
{
if (touch.phase == TouchPhase.Began)
{
fingerUp = touch.position;
fingerDown = touch.position;
}
//Detects Swipe while finger is still moving
if (touch.phase == TouchPhase.Moved)
{
if (!detectSwipeOnlyAfterRelease)
{
fingerDown = touch.position;
checkSwipe();
}
}
//Detects swipe after finger is released
if (touch.phase == TouchPhase.Ended)
{
fingerDown = touch.position;
checkSwipe();
}
}
}
void checkSwipe()
{
//Check if Vertical swipe
if (verticalMove() > SWIPE_THRESHOLD && verticalMove() > horizontalValMove())
{
//Debug.Log("Vertical");
if (fingerDown.y - fingerUp.y > 0)//up swipe
{
OnSwipeUp();
}
else if (fingerDown.y - fingerUp.y < 0)//Down swipe
{
OnSwipeDown();
}
fingerUp = fingerDown;
}
//Check if Horizontal swipe
else if (horizontalValMove() > SWIPE_THRESHOLD && horizontalValMove() > verticalMove())
{
//Debug.Log("Horizontal");
if (fingerDown.x - fingerUp.x > 0)//Right swipe
{
OnSwipeRight();
}
else if (fingerDown.x - fingerUp.x < 0)//Left swipe
{
OnSwipeLeft();
}
fingerUp = fingerDown;
}
//No Movement at-all
else
{
//Debug.Log("No Swipe!");
}
}
float verticalMove()
{
return Mathf.Abs(fingerDown.y - fingerUp.y);
}
float horizontalValMove()
{
return Mathf.Abs(fingerDown.x - fingerUp.x);
}
//////////////////////////////////CALLBACK FUNCTIONS/////////////////////////////
void OnSwipeUp()
{
Debug.Log("Swipe UP");
}
void OnSwipeDown()
{
Debug.Log("Swipe Down");
}
void OnSwipeLeft()
{
Debug.Log("Swipe Left");
}
void OnSwipeRight()
{
Debug.Log("Swipe Right");
}
}
Thanks to Programmer, I used his suggestion and wrote a small component which works both with mouse and touch. The mouse will allow you to debug app on PC. I also added time threshold in seconds, since swipe cannot be too long.
using System;
using UnityEngine;
using UnityEngine.Events;
public class SwipeManager : MonoBehaviour {
public float swipeThreshold = 50f;
public float timeThreshold = 0.3f;
public UnityEvent OnSwipeLeft;
public UnityEvent OnSwipeRight;
public UnityEvent OnSwipeUp;
public UnityEvent OnSwipeDown;
private Vector2 fingerDown;
private DateTime fingerDownTime;
private Vector2 fingerUp;
private DateTime fingerUpTime;
private void Update () {
if (Input.GetMouseButtonDown(0)) {
this.fingerDown = Input.mousePosition;
this.fingerUp = Input.mousePosition;
this.fingerDownTime = DateTime.Now;
}
if (Input.GetMouseButtonUp(0)) {
this.fingerDown = Input.mousePosition;
this.fingerUpTime = DateTime.Now;
this.CheckSwipe();
}
foreach (Touch touch in Input.touches) {
if (touch.phase == TouchPhase.Began) {
this.fingerDown = touch.position;
this.fingerUp = touch.position;
this.fingerDownTime = DateTime.Now;
}
if (touch.phase == TouchPhase.Ended) {
this.fingerDown = touch.position;
this.fingerUpTime = DateTime.Now;
this.CheckSwipe();
}
}
}
private void CheckSwipe() {
float duration = (float)this.fingerUpTime.Subtract(this.fingerDownTime).TotalSeconds;
if (duration > this.timeThreshold) return;
float deltaX = this.fingerDown.x - this.fingerUp.x;
if (Mathf.Abs(deltaX) > this.swipeThreshold) {
if (deltaX > 0) {
this.OnSwipeRight.Invoke();
//Debug.Log("right");
} else if (deltaX < 0) {
this.OnSwipeLeft.Invoke();
//Debug.Log("left");
}
}
float deltaY = fingerDown.y - fingerUp.y;
if (Mathf.Abs(deltaY) > this.swipeThreshold) {
if (deltaY > 0) {
this.OnSwipeUp.Invoke();
//Debug.Log("up");
} else if (deltaY < 0) {
this.OnSwipeDown.Invoke();
//Debug.Log("down");
}
}
this.fingerUp = this.fingerDown;
}
}
Modified Developper's approach for a more precise controller (and less code! =D ) :
using System;
using UnityEngine;
using UnityEngine.Events;
using Utilities;
public class SwipeManager : MonoBehaviour {
public float swipeThreshold = 40f;
public float timeThreshold = 0.3f;
public UnityEvent onSwipeLeft;
public UnityEvent onSwipeRight;
public UnityEvent onSwipeUp;
public UnityEvent onSwipeDown;
private Vector2 _fingerDown;
private DateTime _fingerDownTime;
private Vector2 _fingerUp;
private DateTime _fingerUpTime;
private void Update () {
if (Input.GetMouseButtonDown(0)) {
_fingerDown = Input.mousePosition;
_fingerUp = Input.mousePosition;
_fingerDownTime = DateTime.Now;
}
if (Input.GetMouseButtonUp(0)) {
_fingerDown = Input.mousePosition;
_fingerUpTime = DateTime.Now;
CheckSwipe();
}
foreach (var touch in Input.touches) {
if (touch.phase == TouchPhase.Began) {
_fingerDown = touch.position;
_fingerUp = touch.position;
_fingerDownTime = DateTime.Now;
}
if (touch.phase == TouchPhase.Ended) {
_fingerDown = touch.position;
_fingerUpTime = DateTime.Now;
CheckSwipe();
}
}
}
private void CheckSwipe() {
var duration = (float)_fingerUpTime.Subtract(_fingerDownTime).TotalSeconds;
var dirVector = _fingerUp - _fingerDown;
if (duration > timeThreshold) return;
if (dirVector.magnitude < swipeThreshold) return;
var direction = dirVector.Rotation(180f).Round();
print(direction);
if (direction >= 45 && direction < 135) onSwipeUp.Invoke();
else if (direction >= 135 && direction < 225) onSwipeRight.Invoke();
else if (direction >= 225 && direction < 315) onSwipeDown.Invoke();
else if (direction >= 315 && direction < 360 || direction >= 0 && direction < 45) onSwipeLeft.Invoke();
}
}
I searched for the same thing, and found it reasonable to create asset for easy swipe detection, and share it with community. So here it is on github. My solution supports different usecases, including: 8-directions swipe detection, 4-directions, 2-directions (left-right or up-down), swipes on hexagonal grid. All listed is included as a presets, but also you can configure it to detect any number of Vector3 directions. So ti`s really flexible. Also, you can try WebGL build or see video tutorial. If you try it, please, let me know (via youtube comment, or see Contacts section on github), was it suitable for your case, and was it comfortable enough.
Try this Out.
I hope this helps.
void Update(){
if (Input.GetMouseButtonDown(0)){
startPosition = Input.mousePosition;
}
if (Input.GetMouseButtonUp(0)){
float swipe = startPosition.x - Input.mousePosition.x;
}
if (swipe < 0)
{
print("LTR");
} else{
print("RTL");
}
}
}
}
Related
CurrentlyGrounded Should flip to true and false. Instead, visual studio is reporting that it "Doesn't exist in the current context". How do I force this variable to exist EVERYWHERE in the script?
Making it public did absolutely nothing.
The problem occurs in the private void GroundCheck() method on Line 267.
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.FirstPerson
{
[RequireComponent(typeof (Rigidbody))]
[RequireComponent(typeof (CapsuleCollider))]
public class RigidbodyFirstPersonController : MonoBehaviour
{
[Serializable]
public class MovementSettings
{
public float ForwardSpeed = 8.0f; // Speed when walking forward
public float BackwardSpeed = 4.0f; // Speed when walking backwards
public float StrafeSpeed = 4.0f; // Speed when walking sideways
public float AirForwardSpeed = 8.0f; // Speed when flying forward
public float AirBackwardSpeed = 4.0f; // Speed when flying backwards
public float AirStrafeSpeed = 4.0f; // Speed when flying sideways
public bool CurrentlyGrounded = true;
public float RunMultiplier = 2.0f; // Speed when sprinting
public KeyCode RunKey = KeyCode.LeftShift;
public float JumpForce = 30f;
public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f));
[HideInInspector] public float CurrentTargetSpeed = 8f;
#if !MOBILE_INPUT
private bool m_Running;
#endif
public void UpdateDesiredTargetSpeed(Vector2 input)
{
if (input == Vector2.zero) return;
if (input.x > 0 || input.x < 0 && CurrentlyGrounded == true)
{
//strafe
CurrentTargetSpeed = StrafeSpeed;
}
else if (input.x > 0 || input.x < 0 && CurrentlyGrounded == false)
{
//strafe
CurrentTargetSpeed = AirStrafeSpeed;
}
if (input.y < 0 && CurrentlyGrounded == true)
{
//backwards
CurrentTargetSpeed = BackwardSpeed;
}
else if (input.y < 0 && CurrentlyGrounded == false)
{
//backwards
CurrentTargetSpeed = AirBackwardSpeed;
}
if (input.y > 0 && CurrentlyGrounded == true)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = ForwardSpeed;
}
else if (input.y > 0 && CurrentlyGrounded == false)
{
//forwards
//handled last as if strafing and moving forward at the same time forwards speed should take precedence
CurrentTargetSpeed = AirForwardSpeed;
}
#if !MOBILE_INPUT
if (Input.GetKey(RunKey))
{
CurrentTargetSpeed *= RunMultiplier;
m_Running = true;
}
else
{
m_Running = false;
}
#endif
}
#if !MOBILE_INPUT
public bool Running
{
get { return m_Running; }
}
#endif
}
[Serializable]
public class AdvancedSettings
{
public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this )
public float stickToGroundHelperDistance = 0.5f; // stops the character
public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input
public bool airControl; // can the user control the direction that is being moved in the air
[Tooltip("set it to 0.1 or more if you get stuck in wall")]
public float shellOffset; //reduce the radius by that ratio to avoid getting stuck in wall (a value of 0.1f is nice)
}
public Camera cam;
public MovementSettings movementSettings = new MovementSettings();
public MouseLook mouseLook = new MouseLook();
public AdvancedSettings advancedSettings = new AdvancedSettings();
private Rigidbody m_RigidBody;
private CapsuleCollider m_Capsule;
private float m_YRotation;
private Vector3 m_GroundContactNormal;
private bool m_Jump, m_PreviouslyGrounded, m_Jumping, m_IsGrounded;
public Vector3 Velocity
{
get { return m_RigidBody.velocity; }
}
public bool Grounded
{
get { return m_IsGrounded; }
}
public bool Jumping
{
get { return m_Jumping; }
}
public bool Running
{
get
{
#if !MOBILE_INPUT
return movementSettings.Running;
#else
return false;
#endif
}
}
private void Start()
{
m_RigidBody = GetComponent<Rigidbody>();
m_Capsule = GetComponent<CapsuleCollider>();
mouseLook.Init (transform, cam.transform);
}
private void Update()
{
RotateView();
if (CrossPlatformInputManager.GetButtonDown("Jump") && !m_Jump)
{
m_Jump = true;
}
}
private void FixedUpdate()
{
GroundCheck();
Vector2 input = GetInput();
if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon) && (advancedSettings.airControl || m_IsGrounded))
{
// always move along the camera forward as it is the direction that it being aimed at
Vector3 desiredMove = cam.transform.forward*input.y + cam.transform.right*input.x;
desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized;
desiredMove.x = desiredMove.x*movementSettings.CurrentTargetSpeed;
desiredMove.z = desiredMove.z*movementSettings.CurrentTargetSpeed;
desiredMove.y = desiredMove.y*movementSettings.CurrentTargetSpeed;
if (m_RigidBody.velocity.sqrMagnitude <
(movementSettings.CurrentTargetSpeed*movementSettings.CurrentTargetSpeed))
{
m_RigidBody.AddForce(desiredMove*SlopeMultiplier(), ForceMode.Impulse);
}
}
if (m_IsGrounded)
{
m_RigidBody.drag = 5f;
if (m_Jump)
{
m_RigidBody.drag = 0f;
m_RigidBody.velocity = new Vector3(m_RigidBody.velocity.x, 0f, m_RigidBody.velocity.z);
m_RigidBody.AddForce(new Vector3(0f, movementSettings.JumpForce, 0f), ForceMode.Impulse);
m_Jumping = true;
}
if (!m_Jumping && Mathf.Abs(input.x) < float.Epsilon && Mathf.Abs(input.y) < float.Epsilon && m_RigidBody.velocity.magnitude < 1f)
{
m_RigidBody.Sleep();
}
}
else
{
m_RigidBody.drag = 0f;
if (m_PreviouslyGrounded && !m_Jumping)
{
StickToGroundHelper();
}
}
m_Jump = false;
}
private float SlopeMultiplier()
{
float angle = Vector3.Angle(m_GroundContactNormal, Vector3.up);
return movementSettings.SlopeCurveModifier.Evaluate(angle);
}
private void StickToGroundHelper()
{
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) +
advancedSettings.stickToGroundHelperDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
if (Mathf.Abs(Vector3.Angle(hitInfo.normal, Vector3.up)) < 85f)
{
m_RigidBody.velocity = Vector3.ProjectOnPlane(m_RigidBody.velocity, hitInfo.normal);
}
}
}
private Vector2 GetInput()
{
Vector2 input = new Vector2
{
x = CrossPlatformInputManager.GetAxis("Horizontal"),
y = CrossPlatformInputManager.GetAxis("Vertical")
};
movementSettings.UpdateDesiredTargetSpeed(input);
return input;
}
private void RotateView()
{
//avoids the mouse looking if the game is effectively paused
if (Mathf.Abs(Time.timeScale) < float.Epsilon) return;
// get the rotation before it's changed
float oldYRotation = transform.eulerAngles.y;
mouseLook.LookRotation (transform, cam.transform);
if (m_IsGrounded || advancedSettings.airControl)
{
// Rotate the rigidbody velocity to match the new direction that the character is looking
Quaternion velRotation = Quaternion.AngleAxis(transform.eulerAngles.y - oldYRotation, Vector3.up);
m_RigidBody.velocity = velRotation*m_RigidBody.velocity;
}
}
/// sphere cast down just beyond the bottom of the capsule to see if the capsule is colliding round the bottom
private void GroundCheck()
{
m_PreviouslyGrounded = m_IsGrounded;
RaycastHit hitInfo;
if (Physics.SphereCast(transform.position, m_Capsule.radius * (1.0f - advancedSettings.shellOffset), Vector3.down, out hitInfo,
((m_Capsule.height/2f) - m_Capsule.radius) + advancedSettings.groundCheckDistance, Physics.AllLayers, QueryTriggerInteraction.Ignore))
{
m_IsGrounded = true;
CurrentlyGrounded = true;
m_GroundContactNormal = hitInfo.normal;
}
else
{
m_IsGrounded = false;
CurrentlyGrounded = false;
m_GroundContactNormal = Vector3.up;
}
if (!m_PreviouslyGrounded && m_IsGrounded && m_Jumping)
{
m_Jumping = false;
}
}
}
}
What should be happening is that it's seen and changes as expected.
Instead, it's reported as nonexisting in the current context.
Don't listen to people who want to make everything static just to access stuff "more easily".
This actually might cause a lot of trouble as soon as you have more than exactly one instances of that class (e.g. if there are two players, or an AI uses the same component).
Another bad side effect is that you won't be able anymore to configure it via the Inspector e.g. for debugging or to give it the desired start value.
What you want to use instead is
moventSettings.CurrentlyGrounded
to access the value of your MovementSettings instance.
Just the same way you did it e.g. in
movementSettings.Running
You can assign it to a global variable.
public static class Globals
{
public static String value = "Sample Value"; // Modifiable
public static readonly String CODE_PREFIX = "TEST-"; // Unmodifiable
}
You can then retrieve the defined values anywhere in your code
String code = Globals.CODE_PREFIX + value.ToString();
Hey guys my question is in the title. Basically when I press play everything is OK, the ball starts to go up without shaking, but when I start swiping to change position it starts shaking.
I already tried different things like changing to FixedUpdate() or resetting the player, but it doesn't change. Btw there is no animation on the ball. Can you help me?
Here is the script with the swipe parameters :
public class Swipe : MonoBehaviour
{
private const float DEADZONE = 100.0f;
public static Swipe Instance { set; get; }
private bool tap, swipeLeft, swipeRight, swipeUp, swipeDown;
private Vector2 startTouch, swipeDelta;
public bool Tap { get { return tap; } }
public Vector2 SwipeDelta { get { return swipeDelta; } }
public bool SwipeLeft { get { return swipeLeft; } }
public bool SwipeRight { get { return swipeRight; } }
public bool SwipeUp { get { return swipeUp; } }
public bool SwipeDown { get { return swipeDown; } }
private void Awake()
{
Instance = this;
}
private void Update()
{
// Reseting all the booleans
tap = swipeLeft = swipeRight = swipeDown = swipeUp = false;
#region Stadalone Inputs
if (Input.GetMouseButtonDown(0))
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.GetMouseButtonUp(0))
{
startTouch = swipeDelta = Vector2.zero;
}
#endregion
#region Mobile Inputs
if (Input.touches.Length != 0)
{
if (Input.touches[0].phase == TouchPhase.Began)
{
tap = true;
startTouch = Input.mousePosition;
}
else if (Input.touches[0].phase == TouchPhase.Ended || Input.touches[0].phase == TouchPhase.Canceled)
{
startTouch = swipeDelta = Vector2.zero;
}
}
#endregion
// Calculate The Distance
swipeDelta = Vector2.zero;
if (startTouch != Vector2.zero)
{
if (Input.touches.Length != 0)
{
swipeDelta = Input.touches[0].position - startTouch;
}
else if (Input.GetMouseButton(0))
{
swipeDelta = (Vector2)Input.mousePosition - startTouch;
}
}
// Did we cross the deadzone ?
if (swipeDelta.magnitude > DEADZONE)
{
// Which direction ?
float x = swipeDelta.x;
float y = swipeDelta.y;
if (Mathf.Abs(x) > Mathf.Abs(y))
{
// Left or Right
if (x < 0)
swipeLeft = true;
else
swipeRight = true;
}
else
{
// Up or Down
if (y < 0)
swipeDown = true;
else
swipeUp = true;
}
startTouch = swipeDelta = Vector2.zero;
}
}
}
And this the part of the script in Update() or (FixedUpdate(), it doesn't change anything) used to make it move one side or the other on the player :
// Gather the inputs in which tube we should be
if (Swipe.Instance.SwipeLeft)
MoveTube(false);
if (Swipe.Instance.SwipeRight)
MoveTube(true);
// Calculate where we should be in the future
Vector3 targetPosition = transform.position.y * Vector3.up;
if (desiredTube == 0)
targetPosition += Vector3.left * TUBE_DISTANCE;
else if (desiredTube == 2)
targetPosition += Vector3.right * TUBE_DISTANCE;
// Let's calculate our move delta
Vector3 moveVector = Vector3.zero;
moveVector.x = (targetPosition - transform.position).normalized.x * speed;
moveVector.y = speed;
// Move the ball
controller.Move(moveVector * Time.deltaTime);
}
private void MoveTube(bool goingRight)
{
desiredTube += (goingRight) ? 1 : -1;
desiredTube = Mathf.Clamp(desiredTube, 0, 2);
}
I believe you may be having issue here:
// Gather the inputs in which tube we should be
if (Swipe.Instance.SwipeLeft)
MoveTube(false);
if (Swipe.Instance.SwipeRight)
MoveTube(true);
Since Update() is invoked once per frame, this means this will be checked several times per second. So it may be changing the position of the player several times per second, giving this shaking effect you mention.
What you could try is to restrict the times the player can swipe per second.
private float SwipeRate = 0.1f;
private float NextSwipe = 0.0f;
Update(){
if (Swipe.Instance.SwipeLeft && Time.time > NextSwipe)
{
NextSwipe = Time.time+SwipeRate;
MoveTube(false);
}
if (Swipe.Instance.SwipeRight && Time.time > NextSwipe)
{
NextSwipe = Time.time+SwipeRate;
MoveTube(true);
}
}
Edit:
private void MoveTube(bool goingRight)
{
desiredTube += (goingRight) ? 1 : -1;
desiredTube = Mathf.Clamp(desiredTube, 0, 2);
// Calculate where we should be in the future
Vector3 targetPosition = transform.position.y * Vector3.up;
if (desiredTube == 0)
targetPosition += Vector3.left * TUBE_DISTANCE;
else if (desiredTube == 2)
targetPosition += Vector3.right * TUBE_DISTANCE;
// Let's calculate our move delta
Vector3 moveVector = Vector3.zero;
moveVector.x = (targetPosition - transform.position).normalized.x * speed;
moveVector.y = speed;
// Move the ball
controller.Move(moveVector * Time.deltaTime);
}
I found how to solve the problem. So basically I was using the same speed variable to move my ball on the x and y axis and it seems that it created some “switch problem” for unity. So I just created 2 different variables for the speed and I solved the bug like this.
I am trying to make a player spaceship move between three points when the user enters left or right on the keyboard. I would like the player to move smoothly between these points but it seems that the Lerp function is only interpolated once.
Here is the Game master script which checks for input from the user and passes it onto the Player controller which performs the Lerp:
Game master:
void Update ()
{
if (gameIsRunning)
{
if (Input.GetKeyDown(KeyCode.A))
{
//Go Left
player.MovePlayer("left");
}
else if (Input.GetKeyDown(KeyCode.D))
{
//Go Right
player.MovePlayer("right");
}
//Only run this if the game is running...
if (player.Lives <= 0)
{
gameIsRunning = false;
}
}
}
Player controller:
public void MovePlayer (string dir)
{
if (dir == "left")
{
if (currentPosition == Position.Left)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, .5f);
currentPosition = Position.Left;
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
if (dir == "right")
{
if (currentPosition == Position.Right)
{
//Do Nothing!
return;
}
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(transform.position, rightPos.position, .5f);
currentPosition = Position.Right;
}
if (currentPosition == Position.Left)
{
transform.position = Vector3.Lerp(transform.position, middlePos.position, .5f);
currentPosition = Position.Middle;
}
}
}
Screenshot:
Why is this happening?
lerp must be called with a changing parameter. try something like:
Player controller:
enum Direction
{
Left,
Right
}
Direction moveDir;
float progress;
public void MovePlayer (Direction dir)
{
moveDir = dir;
progress = 0.0f;
}
public void Update()
{
switch(dir)
{
case Direction.Left:
if (currentPosition == Position.Middle)
{
transform.position = Vector3.Lerp(middlePos.position, leftPos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Left;
else
progress += 0.1f; // change as necessary
}
if (currentPosition == Position.Right)
{
transform.position = Vector3.Lerp(rightPos.position, middlePos.position, progress);
if(progress >= 1.0f)
currentPosition = Position.Middle;
else
progress += 0.1f; // change as necessary
}
break;
case Direction.Right:
// ...
break;
}
}
I have this script for inputting touches on the mobile device. But it activates only once, I need it to be run until I take my finger off the screen
public float speed = 3;
public Rigidbody rb;
public void MoveLeft()
{
transform.Translate(-Vector3.right * speed * Time.deltaTime);
}
public void StopMoving()
{
rb.velocity = new Vector2(0, 0);
}
public void MoveRight()
{
rb.velocity = new Vector2(-speed, 0);
}
private void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
float middle = Screen.width / 2;
if (touch.position.x < middle && touch.phase == TouchPhase.Began)
{
MoveLeft();
}
else if (touch.position.x > middle && touch.phase == TouchPhase.Began )
{
MoveRight();
}
}
else
{
StopMoving();
}
}
}
You simply need to remove the two && touch.phase == TouchPhase.Began portions. This will have the overall if-statement evaluate true as long as there is one finger on the screen.
private void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
float middle = Screen.width / 2;
if (touch.position.x < middle)
{
MoveLeft();
}
else if (touch.position.x > middle)
{
MoveRight();
}
}
else
{
StopMoving();
}
}
The bases of my game is a simple 2D top down click to move game I. I created a walk blend tree and a idle blend tree. The both blend tree has 6 directional movement. I watch this tutorial on Top-down 8 directions movement. (https://www.youtube.com/watch?v=7URRg8J6mz8). Basically I change the script around so that it could match with my click to move script, but it not 100% perfect. My idle state is not working properly or neither is my Y-axis, to be more speific, when I click long the Y-axis (let's say i'm going up(+)) it's not really playing the right animation in the animator. (Now let's say I went down) It would play the right animation but (when finished with movement) it would continue playing the animation. My parameters are also not working properly, SpeedY and LastMoveY aren't stable (if i'm making any sense). Can someone help me fix this? Here's my game preview uploaded in google drive if anyone doesn't understand what I mean! http://html.editey.com/file/0B6cfYGCOex7BVC1Ja3Q3N3d3NWc#
using UnityEngine;
using System.Collections;
public class move : MonoBehaviour {
private Animator anim;
public float speed = 15f;
public move playerMovementRef;
private Vector3 target;
private Vector3 playerObject;
void Start () {
target = transform.position;
anim = GetComponent<Animator> ();
}
void Update () {
if (Input.GetMouseButtonDown(0)) {
target = Camera.main.ScreenToWorldPoint(Input.mousePosition);
target.z = transform.position.z;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
float inputX = Input.GetAxis ("Mouse X");
float inputY = Input.GetAxis ("Mouse Y");
if (Input.touchCount > 0)
{
inputX = Input.touches[0].deltaPosition.x;
inputY = Input.touches[0].deltaPosition.y;
}
anim.SetFloat ("SpeedX", inputX);
anim.SetFloat ("SpeedY", inputY);
}
void FixedUpdate () {
float LastInputX = Input.GetAxis ("Mouse X");
float LastInputY = Input.GetAxis ("Mouse Y");
if (Input.touchCount > 0)
{
LastInputX = Input.touches[0].deltaPosition.x;
LastInputY = Input.touches[0].deltaPosition.y;
}
if (LastInputX != 0 || LastInputY != 0) {
anim.SetBool ("walking", true);
if (LastInputX > 0) {
anim.SetFloat ("LastMoveX", 1f);
} else if (LastInputX < 0) {
anim.SetFloat ("LastMoveX", -1f);
} else {
anim.SetBool ("walking", false);
}
if (LastInputY > 0) {
anim.SetFloat ("LastMoveY", 1f);
} else if (LastInputY < 0) {
anim.SetFloat ("LastMoveY", -1f);
} else {
anim.SetFloat ("LastMoveY", 0f);
}
} else {
anim.SetBool ("walking", false);
}
}
You should not use Input values inside FixedUpdate. You should store it in a variable inside Update and then check it inside FixedUpdate.
You should also add some depth to the mouse position according to your camera.
wrong:
void FixedUpdate () {
if (Input.touchCount > 0)
{
...
}
}
correct:
void Update () {
...
if (Input.touchCount > 0)
{
touched = true;
}
}
void FixedUpdate () {
if (touched)
{
...
}
}
sample:
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = 10; // distance from the camera
target = Camera.main.ScreenToWorldPoint(mousePosition);
target.z = transform.position.z;
}
if (Input.touchCount > 0)
{
target.x = Input.touches[0].deltaPosition.x;
target.y = Input.touches[0].deltaPosition.y;
}
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
void FixedUpdate()
{
float LastInputX = transform.position.x - target.x;
float LastInputY = transform.position.y - target.y;
if (LastInputX != 0 || LastInputY != 0)
{
anim.SetBool("walking", true);
if (LastInputX > 0)
{
anim.SetFloat("LastMoveX", 1f);
}
else if (LastInputX < 0)
{
anim.SetFloat("LastMoveX", -1f);
}
else {
anim.SetBool("walking", false);
}
if (LastInputY > 0)
{
anim.SetFloat("LastMoveY", 1f);
}
else if (LastInputY < 0)
{
anim.SetFloat("LastMoveY", -1f);
}
else {
anim.SetFloat("LastMoveY", 0f);
}
}
else {
anim.SetBool("walking", false);
}
}