Unity 2D touch code destroying all objects? - c#

After looking for solutions to handle touch controls in Unity I found a solution that seems to work. Problem is, when a touch is detected, every single object with a 2D collider is destroyed. I only want the object that was touched to be destroyed.
Every Game Object in the scene is a prefab. They are all clones of 8 different random prefabs. Each of these prefabs has a Circle Collider 2D as well as the script for touch controls Called TouchManager.cs
I have tried changing the "if (hit)" portion to "if (hit.collider != null) but this causes it to not work for some reason. I have tried everything I could think of and nothing works!
Can anyone please help?
TouchManager.cs
// Update is called once per frame
void Update ()
{
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
Vector3 wp = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
Vector2 touchPos = new Vector2(wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit)
{
touched = true;
startPos = Input.GetTouch(0).position;
}
}
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
if (touched == true)
{
float swipeDirection = Mathf.Sign(Input.GetTouch(0).position.y - startPos.y);
if (swipeDirection > 0)
{
Destroy(gameObject);
}
else if (swipeDirection < 0)
{
}
// Reset touched
touched = false;
}
} //END SWITCH
} //END IF TOUCHED
} //END UPDATE

Whats happening here is that OverlapPoint returns the collider that the point overlaps, which means that you are checking: if the swipe overlaps any collider, destroy this gameobject.
What you want is to use hit.collider2D, it will store the collider2D that was overlapped.
although hit.collider will always be null, that is because you dont have any colliders, you only have collider2D.
Since OverlapPoint tests against all colliders and dont care about what gameobject it is ran from, it better to place it in single manager object instead of each object and then let that manager destroy the other objects.
This code will destroy just one object. Remember to place it on a separate object from the ones you are destroying. I doubt it will give you a desired behavior but since i dont know what that is, i leave it as an exercise for you.
Vector3 startPos;
GameObject hitObject;
void Update()
{
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Began)
{
Vector3 wp = Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position);
Vector2 touchPos = new Vector2(wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if (hit != null)
{
hitObject = hit.collider2D.gameObject;
startPos = Input.GetTouch(0).position;
}
}
if (Input.GetTouch(0).phase == TouchPhase.Ended)
{
if (hitObject != null)
{
float swipeDirection = Mathf.Sign(Input.GetTouch(0).position.y - startPos.y);
if (swipeDirection > 0)
{
Destroy(hitObject);
}
else if (swipeDirection < 0)
{
}
hitObject = null;
}
}
}
}

Related

Unity lineRenderer takes the 0,0 point as center

In my 2D unity mobile game, when I touch and pull the ball it shows up a lineRenderer from the ball through the way I pull there is no problem with that but if I touch to screen while the ball is dynamic (before it stopped) the new lineRenderer take (0,0) point as the center instead of the location of the ball.
This is how it works properly when I touch the screen while the ball is not moving
This is the problematic version line renderer starts from the point (0,0) instead of the ball
void Update()
{
if (Input.touchCount > 0 && !hasMoved)
{
touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
dragStart();
}
if (touch.phase == TouchPhase.Moved)
{
Dragging();
}
if (touch.phase == TouchPhase.Ended)
{
DragRelease();
}
}
}
void dragStart()
{
dragStartposition = transform.position;
dragStartposition.z = 0;
gostergeLine.positionCount = 1;
gostergeLine.SetPosition(0,transform.position);
}
void Dragging()
{
Vector3 draggingPos = Camera.main.ScreenToWorldPoint(touch.position);
draggingPos.z = 0;
gostergeLine.positionCount = 2;
gostergeLine.SetPosition(1, draggingPos);
}
void DragRelease()
{
gostergeLine.positionCount = 0;
Vector3 dragReleasePos = Camera.main.ScreenToWorldPoint(touch.position);
dragReleasePos.z = 0;
Vector3 forceVec = dragStartposition - dragReleasePos;
forcePower = forceVec.magnitude;
if(forcePower > 45)
{
topRb.velocity = forceVec * 45;
}
else
{
topRb.velocity = forceVec * forcePower;
}
}
Even though it does not read my touch while the ball is moving (!hasmoved); if I touch the screen before it stopped, the new linerenderer shows up in wrong direction.
Update is called every frame.
The TouchPhase.Began is only true in the very first frame of a touch -> your ball was moving then so you ignored it
Now you continue touching so eventually TouchPhase.Moved is true at some point
=> Since the ball stopped in the meantime you now call Dragging without having called dragStart before.
You could make sure that the other cases are only called at all if dragStart was actually called first.
You could e.g. use a nullable
private Vector2? dragStartposition;
and then check for it in
void Dragging()
{
if(dragStartposition == null) return;
...
}
and also reset it in
void DragRelease()
{
if(dragStartposition == null) return;
...
Vector3 forceVec = dragStartposition.Value - dragReleasePos;
...
dragStartposition = null;
}
This way if a touch started to early it doesn't trigger the other methods, only if one started after the ball has stopped.
There is still a pitfall though with multiple touches
=> I would also use exactly one touch only
if(Input.touchCount == 1 && !hasMoved)

Unity Raycast2D problem when the character sitting on the corner

Hi I have a problem with the Raycast2D. When the character sitting on the platform like on the image, the Raycast2D dosen't work. I have tried the Raycast and RaycastAll both. How can I detect the platform under the character when he's on the corner?
https://imgur.com/z7VMRq5
if(Input.GetMouseButton(0))
{
RaycastHit2D[] hit = Physics2D.RaycastAll(transform.position, -Vector2.up, 2f, layerMask);
if(hit[0].collider != null)
{
Destroy(hit[0].collider.gameObject);
}
}
1) Use multiple raycasts
In your code, the game only detects a platform if the center of your player is standing above it. To detect the platform at all times, you should use two raycasts at the bounds of your character's collider.
void Update()
{
// Cast the rays
castRays(transform.localScale.x / 2f);
}
private void castRays(float distanceFromCenter)
{
// Return if the ray on the left hit something
if(castRay(new Vector2(-distanceFromCenter, 0f) == true) { return; }
// Return if the ray on the right hit something
else if(castRay(new Vector2(distanceFromCenter, 0f) == true) { return; }
}
private bool castRay(Vector2 offset)
{
RaycastHit2D hit; // Stores the result of the raycast
// Cast the ray and store the result in hit
hit = Physics2D.Raycast(transform.position + offset, -Vector2.up, 2f, layerMask);
// If the ray hit a collider...
if(hit.collider != null)
{
// Destroy it
Destroy(hit.collider.gameObject);
// Return true
return true;
}
// Else, return false
return false;
}
Optional: You can re-include the ray in the center in case there are platforms smaller than the player or for safety.
2) Use a trigger
Place a BoxCollider2D at the feet of the character and set 'isTrigger' to true. When it enters another collider it will call "OnTriggerEnter2D".
void OnTriggerEnter2D(Collider2D other)
{
Destroy(other.gameObject);
}

Unity - Collider2D not considered in collision check anymore after disabling and enabling

I've got a player, and a shield around him. When a shield is present, it blocks gun projectiles. My CollisionEnter code is
if ((col.collider.gameObject.tag == "hurt") && (col.collider.IsTouching(shield) == false))
{hurt();}
It's perfectly fine, if I start the level with the shield already enabled from default. It blocks damage, projectile dissapears. BUT if I have it disabled from beginning and then enable it, it's... hurting me anyway. Even though the "shield" is still tagged to the Collider2D, and that Collider is enabled. I have no idea what to do. Thanks for help!
Here's an image of my player properties:
And here's a GIF of the improper behaviour after disabling/enabling the shield:
Here's a full code of the collision check.
void OnCollisionEnter2D(Collision2D col)
{
if ((col.collider.gameObject.tag == "hurt_insta") && (col.collider.IsTouching(shield) == false))
{
Instantiate(prefab,transform.position,transform.rotation);
transform.position = new Vector3 (300, 300, transform.position.z);
Vector2 tempxy = new Vector2 (transform.position.x, transform.position.y);
GameObject.Find ("Main Camera").GetComponent<CameraFollow> ().target = null;
PlayerSolid.GetComponent<Renderer> ().enabled = false;
StartCoroutine (Death_prodleva4bit ());
}
if ((col.collider.gameObject.tag == "hurt") && (col.collider.IsTouching(shield) == false))
{
Instantiate(prefab,transform.position,transform.rotation);
//if (PlayerSolid.transform.localScale.y > 0f) {
// PlayerSolid.transform.localScale -= new Vector3 (0f, 0.36f);
//}
//if (actual_bit == player_bits [8] ) {
if (n > 6) {
transform.position = new Vector3 (300, 300, transform.position.z);
Vector2 tempxy = new Vector2 (transform.position.x, transform.position.y);
GameObject.Find ("Main Camera").GetComponent<CameraFollow> ().target = null;
PlayerSolid.GetComponent<Renderer> ().enabled = false;
StartCoroutine (Death_prodleva4bit ());
}
else {
hit = true;
HURT (2);
//if (n < 7) {
// HURT(3);
//}
}
But it's definitely working as it is - when it's enabled from the start it has no problem. It only occurs if it's not woken up immediately when starting the level.
I tried it a few more times and it really seems to be fixed - So, for some reason, the object that I was asking about in IsTouching needed a RIGIDBODY. I still don't understand it, because if I start the game with the shield on, it works flawlessly! Nonetheless, this fixed it!
Thanks everyone!

How to precisely know when a user touches a BoxCollider2D

I want to detect on an Android device every time the user touches a GameObject with a BoxCollider2D attached to it so that code can be executed each time.
In my case the user swipes over the GameObject multiple times thus they probably won't lift the finger from the screen until they need to or a specific condition is met.
Here's an example image:
the user swipes over the GameObject multiple times thus they probably
won't lift the finger from the screen until they need to or a specific
condition is met.
Since the user is not required to remove finger from the screen, you can check for swipe over a 2D GameObject with TouchPhase.Moved and RaycastHit2D. TouchPhase.Began should be used to detect touch only.
void Update()
{
//Check for Press
for (int i = 0; i < Input.touchCount; i++)
{
if (Input.GetTouch(i).phase == TouchPhase.Began)
{
Vector2 fingerRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
RaycastHit2D objectHit = Physics2D.Raycast(fingerRay, Vector2.zero);
if (objectHit)
{
//We hit something
if (objectHit.collider.name == "myGameObjectName")
{
Debug.Log("Touched Finger on GameObject: " + objectHit.collider.name);
}
}
}
//Check if we moved the finger(while press is still down)
if (Input.GetTouch(i).phase == TouchPhase.Moved)
{
Vector2 fingerRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
RaycastHit2D objectHit = Physics2D.Raycast(fingerRay, Vector2.zero);
if (objectHit)
{
//We hit something while moving the finger
if (objectHit.collider.name == "myGameObjectName")
{
Debug.Log("Moved Finger on GameObject: " + objectHit.collider.name);
}
}
}
//Check for release
if (Input.GetTouch(i).phase == TouchPhase.Ended)
{
Debug.Log("Released Finger!");
}
}
}
EDIT:
The code doesn't detect all the swipes over the GameObject. It works
well only if you swipe just a little around it.
You can have your own custom move phase. Replace if (Input.GetTouch(i).phase == TouchPhase.Moved) with if (Input.GetTouch(i).deltaPosition.magnitude > validMoveMagnitude).
validMoveMagnitude is defined as float validMoveMagnitude = 1.5f;.
EDIT 3:
If small move is still not being detected, you can make a variable that stores last touch pos then compare it with the new touch pos.
Vector3 lastPos;
void Update()
{
//Check for Press
for (int i = 0; i < Input.touchCount; i++)
{
if (Input.GetTouch(i).phase == TouchPhase.Began)
{
lastPos = Input.GetTouch(i).position;
Vector2 fingerRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
RaycastHit2D objectHit = Physics2D.Raycast(fingerRay, Vector2.zero);
if (objectHit)
{
//We hit something
if (objectHit.collider.name == "myGameObjectName")
{
Debug.Log("Touched Finger on GameObject: " + objectHit.collider.name);
}
}
}
//Get current Pos
Vector3 currentPos = Input.GetTouch(i).position;
//Check if we moved
if (currentPos != lastPos)
{
//Update Last Pos
lastPos = currentPos;
Debug.Log("Finger Moved!" + lastPos);
Vector2 fingerRay = Camera.main.ScreenToWorldPoint(Input.GetTouch(i).position);
RaycastHit2D objectHit = Physics2D.Raycast(fingerRay, Vector2.zero);
if (objectHit)
{
//We hit something while moving the finger
if (objectHit.collider.name == "myGameObjectName")
{
Debug.Log("Moved Finger on GameObject: " + objectHit.collider.name);
}
}
}
//Check for release
if (Input.GetTouch(i).phase == TouchPhase.Ended)
{
// Debug.Log("Released Finger!");
}
}
}
Attach this script to that gameobject with box collider.
You can detect with mouse pointer enter event which also works with Android. Just tried with a basic canvas with a half sized panel attached to box collider 2D.
using UnityEngine;using System.Collections;
using UnityEngine.EventSystems;
public class Test : MonoBehaviour,IPointerEnterHandler
{
public void OnPointerEnter(PointerEventData eventData)
{
GameObject currentGo;
currentGo = eventData.pointerEnter;
if (currentGo.tag == "GameObjectWithCollider2D" || currentGo.GetComponent<BoxCollider2D>())
{
Debug.Log ("This has Box Collider 2D");
}
}
}

Unity game Drag Object with finger movement

I am new to Unity and develop mobile 2d game,now I am able to make an object move right and left when I touch the screen before or after the screen center. But I want to touch the object and drag it on the x axis while my finger is still touching the screen and move,so I want the object to be in the same x position of my finger,
Any One can help me how to do it correctly:
here is the code of how I am moving the object if I touched before or after the screen center:
public class paddle : MonoBehaviour {
public Rigidbody2D rb;
public float speed;
public float maxX;
bool currentisAndroid=false;
// Use this for initialization
void Start () {
rb = GetComponent<Rigidbody2D> ();
#if UNITY_ANDROID
currentisAndroid=true;
#else
currentisAndroid=false;
#endif
}
// Update is called once per frame
void Update () {
if (currentisAndroid == true) {
if (Input.GetTouch (0).position.x < Screen.width/2 && Input.GetTouch (0).phase == TouchPhase.Stationary)
moveLeft ();
else if (Input.GetTouch (0).position.x > Screen.width/2 && Input.GetTouch (0).phase == TouchPhase.Stationary)
moveRight ();
else
stop ();
} else {
float x = Input.GetAxis ("Horizontal");
//if (Input.GetTouch (0).position.x == rb.position.x && Input.GetTouch (0).phase == TouchPhase.Moved)
if (x == 0)
stop ();
if (x < 0)
moveLeft ();
if (x > 0)
moveRight ();
Vector2 pos = transform.position;
pos.x=Mathf.Clamp (pos.x,-maxX,maxX);
transform.position = pos;
}
}
void moveLeft()
{
rb.velocity = new Vector2 (-speed, 0);
}
void moveRight()
{
rb.velocity = new Vector2 (speed, 0);
}
void stop()
{
rb.velocity = new Vector2 (0, 0);
}
public float getposition()
{
return rb.position.y;
}
}
Easiest way:
Add component DragRigidbody script and you will be able to drag objects via mouse or touchScreen touches.
If I Understand correctly:
1 - Raycast from finger location vertically with your camera into the scene.
2 - select the hit object.
3 - map your camera to world coordinates and move that object according to hit point of your ray with map or game object\objects.
Physics.Raycast();
RaycastHit.collider();
Camera.main.ScreenToWorldPoint(Input.GetTouch(<0 or 1 or all>).position);
If you want to move object across a map you can track your touch and when its close to the corners move the camera on that direct (horizontal - vertical).

Categories

Resources