Finding angle of swipe in Unity3D - unity3d

I need to find the angle between the swipe in Unity3D. In the update function I'm using the following code:
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
fingerup=Input.mousePosition;
fingerdown=Input.mousePosition;
}
if (Input.GetMouseButtonUp(0))
{
fingerdown=Input.mousePosition;
CheckSwipe();
}
}
and in the CheckSwipe function I'm doing this:
CheckSwipe()
{
var directionvector = fingerup-fingerdown;
if(directionvector.magnitude>SwipeThreshold)
{
/* I need to find the angle between the fingerup and the fingerdown vectors and based on that angle I need to check if the user swiped left, right, up or down. */
/*if (angle>= 45 && angle< 135) onSwipeUp.Invoke();
else if (angle>= 135 && angle < 225) onSwipeRight.Invoke();
else if (angle>= 225 && angle< 315) onSwipeDown.Invoke();
else if (angle>= 315 && angle< 360 || angle >= 0 && angle< 45) onSwipeLeft.Invoke();*/
}
}
How can I get the angle of swipe? I tried various solutions, but it was not working. Any help from any one is appreciated. Thanks in advance.

First thing, during button mouse up event, you should assign value to fingerup variable, not down.
If this doesn't fix your issue, I came up with idea to use trigonometry to calculate the angle:
if (Input.GetMouseButtonDown(0))
{
fingerup = Input.mousePosition;
fingerdown = Input.mousePosition;
}
if (Input.GetMouseButtonUp(0))
{
fingerup = Input.mousePosition;
double angle = Mathf.Atan((fingerup.x - fingerdown.x) / (fingerup.y - fingerdown.y)) * Mathf.Rad2Deg;
if (fingerup.y < fingerdown.y) angle += 180;
if (fingerup.y > fingerdown.y && fingerup.x < fingerdown.x) angle += 360;
Debug.Log("fingerDownPos : " + fingerdown + " fingerUpPos: " + fingerup + " angle: " + angle);
}
Probably it can be written better, but I had no other idea but to use ifs and add angles depending on start and end. Anyway, it's working, and should be a good start.
Edit: your question is about an angle, but I just realized, that since you need only the general direction of a swipe (left, right, up, down) you don't need to calculate angle. Just substract fingerup.x - fingerdown.x and fingerup.y - fingerdown.y Compare which absolute value of this is bigger. If abs from vertical is bigger than horizontal, then it will be either up or down, up if the substraction is greater than 0. You get the idea how to do the rest.

Related

Unity: Finding Side that a 2D Collision Occurs On

I am working on a 2D Game. I am detecting when an object collides with the player, but I am getting a little stuck trying to find which side it is colliding on. I want to be able to rotate the player to face either Left, Right, Up, or Down towards the object it collided with. How can I find which side the object collided on so that I can then rotate the player accordingly?
I am using a Rigidbody2D on the player and 2D Colliders, I am able to find the point that it collides with the player using Collider2D.ClosestPoint() but am unsure how to proceed. Thank you for the help.
So once you have the hit point
var hitPoint = collider.ClosestPoint();
// Instead of the transform.position the collider.bounds.center is often more accurate
var playerPosition = collider.bounds.center;
You could e.g. take the direction between those and check where it hits relative to the player like e.g.
var dir = hitPoint - playerPosition;
var angle = Vector2.SignedAngle(transform.right, dir);
// Now check the angle
if(Maths.Abs(angle) <= 45)
{
Debug.Log("hit right");
}
else if(angle > 45 && angle <= 135)
{
Debug.Log("hit top");
}
else if(angle < 45 && angle >= -135)
{
Debug.Log("hit bottom");
}
else
{
Debug.Log("hit left");
}
The simplest solution I see is that you first get the size of the player 2D collider with BoxCollider2D.size. Then you create a simple block of if statements to check on which side is the hit point based on the player position.
Something like this should work:
var size = collider.size;
var hitPoint = collider.ClosestPoint();
var playerPosition = transform.position;
if (hitPoint.x >= playerPosition + size.x/2)
// hit on the right
else if (hitPoint.y >= playerPosition + size.y/2)
// hit on the top
else if (hitPoint.x <= playerPosition - size.x/2)
// hit on the left
else if (hitPoint.y <= playerPosition - size.y/2)
// hit on the bottom
Note that there may be some problems in the edge cases. You reorder the if statements based on your wanted behaviour.
Hope this help.

weapon is supposed to flip after higher than 90 degress / lower than -90 degrees so it isnt upside down (unity2d)

The weapon flips if the angle is above 90 degrees like intended but doesnt flip if the angle is bellow -90 degrees. For some reason it does flip on the Y axis if the angle is 0 or 180 degrees.
if (Weapon.transform.eulerAngles.z < 90 && Weapon.transform.eulerAngles.z > -90)
{
Weapon.GetComponent<SpriteRenderer>().flipY = false;
}
else
{
Weapon.GetComponent<SpriteRenderer>().flipY = true;
}
visualization
the weapon follows my mouse with this code:
Vector2 mouseScreenPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector2 direction = (mouseScreenPosition - (Vector2)transform.position).normalized;
transform.right = direction;
i dont have any issues with the weapon pointing towards my mouse.
I already tried it with different angles but only the positive one flipped the weapon and 0 degrees. I appreciate every answer. Thank you for your time.
Fixed it with this:
if ((Weapon.transform.eulerAngles.z < 90 && Weapon.transform.eulerAngles.z >= 0) || (Weapon.transform.eulerAngles.z > 270 && Weapon.transform.eulerAngles.z <= 360))

OnCollisionEnter2D executing before Start on prefab

I know my code is ugly, I welcome any improvement suggestions. My goal seems simple, spawn 75 "bubbles" (prefabs) on the screen in random positions at random rotations, and have them move with a random velocity between 0.3 and 0.7, or -0.3 and -0.7. When they collide with a wall, calculate a new random velocity of the same range with respect to which wall it hit.
Currently how I am doing this:
GameManager object has a script that instantiates the bubbles
Bubble prefab has a script that sets the velocity.
How I IMAGINED it going: When the prefab script executes, the start routine would determine an initial random velocity. Then, the OnCollisionEnter2D would be called when the bubble hits a wall and it would recalculate a velocity going in whatever opposite direction the wall is (if it hits the bottom wall, set velocity to a random positive Y value, if it hits the right wall, set velocity to a random negative X value, etc).
How it is ACTUALLY going: Debug logs show the OnCollisionEnter2D executing before Start. This is causing bubbles to get "stuck" in the corner of the screen, and other unexpected behavior. See images of Bubble #70 it is stuck in the bottom left corner with the Rigidbody showing a velocity of 0,0. Debug Log shows the velocity was first calculated in the collision routine, then last calculated in the Start method as -0.7, -0.7. Obviously being stuck in the bottom left, it can't go any lower so it froze it to 0,0. This wouldn't have happened if Start had run first and THEN the OnCollisionEnter2D because the collision routine would have detected the bottom walls and set the velocity to a positive value. Now that it's stuck, it can't collide again.
I'm not sure what to do, I can put something in Start to check the position first, but I feel like I have a bigger problem with my code running the OnCollisionEnter2D before Start, and that would only be a bandaid.
GameManager script to instantiate bubble prefab:
void Start()
{
buffer = 10f;
objectCount = 75;
for (int loop = 0; loop < objectCount; loop ++){
worldMin = Camera.main.ScreenToWorldPoint(new Vector2(buffer, buffer));
worldMax = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width - buffer, Screen.height - buffer));
spawnPosition = new Vector2(
Random.Range(worldMin.x, worldMax.x),
Random.Range(worldMin.y, worldMax.y));
GameObject newGO = (GameObject)Instantiate (objectToSpawn, spawnPosition, Quaternion.Euler(new Vector3(0, 0, Random.Range(-40.0f, 40.0f))));
newGO.name = newGO.name + loop;
}
Bubble prefab script to set velocity (my reason for the if statements are because if the velocity random value is very close to 0 the object moves TOO slow):
void Start()
{
Physics2D.IgnoreLayerCollision(gameObject.layer, gameObject.layer);
min = -0.8f;
max = 0.8f;
compareMax = max - 0.5f;
compareMin = min + 0.5f;
moveX = Random.Range(min, max);
moveY = Random.Range(min, max);
if (moveX < 0.0f && moveX > compareMin){
moveX = min;
}
if (moveX > 0.0f && moveX < compareMax){
moveX = max;
}
if (moveY < 0.0f && moveY > compareMin){
moveY = min;
}
if (moveY > 0.0f && moveY < compareMax){
moveY = max;
}
Debug.Log("Start name: " + gameObject.name + ", moveX: " + moveX + ", moveY: " + moveY);
rb = GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(moveX, moveY);
}
void OnCollisionEnter2D(Collision2D col){
rb = GetComponent<Rigidbody2D>();
if (col.gameObject.tag == "Border"){
min = -0.8f;
max = 0.8f;
compareMax = max - 0.5f;
compareMin = min + 0.5f;
moveY = Random.Range(min, max);
moveX = Random.Range(min, max);
if (col.gameObject.name == "BottomWall"){
moveY = Random.Range(compareMax, max);
}
if (col.gameObject.name == "TopWall"){
moveY = Random.Range(min, compareMin);
}
if (col.gameObject.name == "LeftWall"){
moveX = Random.Range(compareMax, max);
}
if (col.gameObject.name == "RightWall"){
moveX = Random.Range(min, compareMin);
}
Debug.Log("OnCollision name: " + gameObject.name + ", moveX: " + moveX + ", moveY: " + moveY);
rb.velocity = new Vector2(moveX, moveY);
}

Prevent Diagonal movements

I'm developing a 3D tactical RPG game and I would like to know how I could prevent diagonal movements when the NPC moves? I want him to detect where the human player is in the grid and then go after him.
I can take their grid position but it didn't work. The NPC makes diagonal movements and starts to "sink" in the grid.I've tried something like this, target position is a vector 3 and I call the function in Update(), this script is attached to the NPC:
public void MoveNPC()
{
HumanPlayer = GameObject.FindGameObjectWithTag("Player");
ScriptPlayer PlayerPosition = HumanPlayer.GetComponent<ScriptPlayer>();
NPC NPCPosition = this.GetComponent<NPC>();
if ((PlayerPosition.GridPosition.x - NPCPosition.GridPositonNPC.x) + PlayerPosition.GridPosition.y - NPCPosition.GridPositonNPC.y) >= movMax &&
(PlayerPosition.GridPosition.x -NPCPosition.GridPositonNPC.x) + (PlayerPosition.GridPosition.y - NPCPosition.GridPositonNPC.y) <= movMax)
{
if((PlayerPosition.GridPosition.x - NPCPosition.GridPositonNPC.x) - (PlayerPosition.GridPosition.y - NPCPosition.GridPositonNPC.y) >= movMax &&
(PlayerPosition.GridPosition.x - NPCPosition.GridPositonNPC.x) - (PlayerPosition.GridPosition.y - NPCPosition.GridPositonNPC.y) <= movMax){
targetPosition = HumanPlayer.transform.position;
targetPosition.y = 1.4f;
}
}
if(this.transform.position != targetPosition)
{
this.transform.position = Vector3.MoveTowards(transform.position, targetPosition, velocity * Time.deltaTime);
}
}
How could I solve it?

Unity - following finger only works for one direction

I have made some code that should make my player move into the direction of the finger:
if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Moved)
{
Vector2 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 0));
if (pos.x < rb.position.x)
{
movehorizontal = -1;
}
if(pos.x > rb.position.x)
{
movehorizontal = 1;
}
if (pos.y < rb.position.z)
{
movevertical = -1;
}
if(pos.y > rb.position.z)
{
movevertical = 1;
}
}
Vector3 movement = new Vector3(movehorizontal, 0.00f, movevertical)*speed;
It's a 3D game, with a top-view, so my player starts at 0,0,0 and only moves along the x and z axis. My camera is positionated on 0,10,3. The following works on the x axis, so when my finger touches on the right side it goes to the right, if on the left to the left, but no matter where I touch it, it will only move to the front and not to the bottom of my screen.
I tried debugging, but the instructions werent working at the time.
screentoWorldPoint should be stored as a vector3. also since the camera is 10 units away from your plane the last parameter should be 10.
edit, that will only work for a cam pointing straight down. this code should work regardless of the camera angle.
Vector3 pos = Camera.main.ScreenToWorldPoint(new Vector3(Input.GetTouch(0).position.x, Input.GetTouch(0).position.y, 1f));
Vector3 pointDelta = pos - Camera.main.transform.position;
float multiplier = -Camera.main.transform.position.y / pointDelta.y;
pos = Camera.main.transform.position + pointDelta * multiplier;
finally these lines should compare the z values to each other
if (pos.z < rb.position.z)
if(pos.z > rb.position.z)
make those changes and let us know if any other problems still exist