It's like a mario game. The player is jumping around and has to collect some items.
The problem is that my ray isn't colliding with the item box colliders.
I need the ray to know, so i can destroy the right item that the player has collided.
void OnCollisionEnter2D(Collision2D colisor)
{
if((colisor.gameObject.name == "floor" || colisor.gameObject.name == "floor2" || colisor.gameObject.name == "floor3"))
{
anim.SetBool("jump", false);
anim.SetFloat("speed", 0);
}
if (colisor.gameObject.name == "space(Clone)")
{
RaycastHit hit;
Ray ray = new Ray(player.position, transform.right);
Debug.Log("hit1");
if (Physics.Raycast(ray, out hit))
{
BoxCollider bc2d = hit.collider as BoxCollider;
Debug.Log("hit2");
if (bc2d != null)
{
Destroy(bc2d.gameObject);
}
}
}
}
You're mixing 3d and 2d physics; Physics will only look for 3d objects, so you should be using Physics2D instead. This raycast may still fail if the cast starts inside the target, because the surface normals point in the wrong direction.
Also note that since you already have the Collision2D, you can just grab the otherCollider and shouldn't need to raycast in the first place.
Physics.Raycast isn't working with 2D objects. Instead you need to use Physics2D.Raycast or Graphic Raycaster.
Raycast2D - https://docs.unity3d.com/ScriptReference/Physics2D.Raycast.html
Graphic Raycaster - https://docs.unity3d.com/eng/current/Manual/script-GraphicRaycaster.html
Related
I used to raycast to destroy things in my game and it didn't work unless I moved quite fast I attached this script to my main camera in unity, Can anyone tell me what I have done wrong as I want it to happen regardless of movement whether you're still or not.
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Vector2 mousePos = new Vector2(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
RaycastHit2D hit = Physics2D.Raycast(mousePos, Vector2.zero, 100f);
if (hit.collider.tag == "Ground")
{
Debug.Log("You clicked a block and tried to break it!");
Destroy(hit.collider.gameObject);
}
}
}
Physics2D.Raycast should be used in FixedUpdate because in there is when the physics are calculate. Physics are not frame dependant.
From the docs:
RaycastHit2D Raycast(Vector3 origin, Vector3 direction, float distance)
You've given the raycast a zero direction.
Generally, you should use ScreenPointToRay and pass the ray origin and direction to Raycast instead
playerLayer = 11;
if (Input.GetMouseButtonDown(1))
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, crooshair.transform.position - transform.position, 100, ~playerLayer);
if (hit != null)
{
Interactable interactable = hit.collider.GetComponent<Interactable>();
if (interactable != null)
{
SetFocus(interactable);
}
}
else
Debug.Log("Nothing was hit");
}
Every time my player shoot a raycast it ends up hitting my player. The reason this is is because the raycast is starting inside of the player (which is what I want it to do) but it keeps detecting the player no matter what I do. I've used layers, tried to disable Queries start in colliders, and even starting the raycast from a little bit outside of the player but nothing works. When I try and offset the raycast from the player it sometimes works but that is only as long as you shoot in the direction that the offset is going. Please help.
Does your Player have any childed objects with a Collider that are not layered as playerLayer? Just to assure your layermask is setup correctly, I would advise assigning it in the inspector then invert it using the tilde.
public LayerMask playerLayer;
void Update()
{
if (Input.GetMouseButtonDown(1))
{
RaycastHit2D hit = Physics2D.Raycast(transform.position, crooshair.transform.position, 100, ~playerLayer);
if (hit != null)
{
Interactable interactable = hit.collider.GetComponent<Interactable>();
if (interactable != null)
{
Debug.Log("Hit" + hit.collider.name);
}
}
}
}
If you are still unable to debug this with assigning the LayerMask in the inspector, if you could post your hierarchy it might help solve the issue.
I have an object hit that contains a Polygon Collider, and in this object I have some objects that contain BoxCollider. Now I'm trying to detect when I click Polygon Collider, and when I click Box Collider. So when I click Box Collider, you should avoid the Polygon Collider.
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
if (hit.collider.GetType() != typeof(BoxCollider2D))
{
Debug.Log("Bad Click");
}
else
Debug.Log("Good Click");
}
So I can not find any way to help me. If anyone has any idea, thank you!!!
This shouldn't work at-all because RaycastHit and Physics.Raycast are used for 3D colliders. For 2D colliders, RaycastHit2D and Physics2D.Raycast should be used. Also, for checking if the object has BoxCollider2D or PolygonCollider2D attached to it, the GetComponent function is used instead of hit.collider.GetType(). It returns null when the component is not available.
Your raycast code should look like something below:
if (Input.GetMouseButtonDown(0))
{
Camera cam = Camera.main;
Vector2 wPoint = Camera.main.ScreenToWorldPoint(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(wPoint, Vector2.zero);
//Check if we hit anything
if (hit)
{
if (hit.collider.GetComponent<BoxCollider2D>() != null)
{
Debug.Log("Bad Click");
}
else if (hit.collider.GetComponent<PolygonCollider2D>() != null)
Debug.Log("Good Click");
}
}
That should fix your problem but I suggest you use the new Event System with OnPointerClick. See #7 from my other answer on how to use it with a 2D collider.
I am making a game where an object follows my finger. But I do not want the object to jump to my finger if I tap anywhere on the screen. I am using a raycast to do this. It works perfectly except if I move my finger too fast the object freezes.
My theory is that because of it being in Update() that once I move my finger off the object it detects that I can no longer drag it. I have no idea how to fix this.
public GameObject Bigball;
public GameObject Smallball;
// Update is called once per frame
private void Update ()
{
// lets ball follow finger
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved || Input.GetTouch(0).phase == TouchPhase.Stationary)
{
var touch = Input.GetTouch(0);
Vector3 fingerPos = touch.position;
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(fingerPos);
if (Physics.Raycast(ray, out hit) && (hit.collider.tag == "ball"))
{
Smallball.SetActive(false);
Bigball.SetActive(true);
Vector3 pos = new Vector3((Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).x,
(Camera.main.ScreenToWorldPoint(Input.GetTouch(0).position)).y, 0);
Bigball.transform.position = pos;
}
}
else
{
Bigball.SetActive(false);
Smallball.SetActive(true);
Smallball.transform.position = new Vector3(Bigball.transform.position.x, Bigball.transform.position.y, 0);
}
}
It might make more sense to only Raycast once when the finger touches the screen. If that Raycast finds an object to drag, simply store that object and move it to follow the finger every Update(), as long as the finger continues to touch the screen.
Once the finger is released, just forget about the object until the next touch finds a new object to drag.
An alternative would be to use no Raycasts at all but build on IBeginDragHandler, IDragHandler and IEndDragHandler, as Bijan already mentioned.
I have two concentric Box Colliders on same GameObject. Outer Box Collider rotates the object (on swiping the screen) and inner Box Collider plays animation when we touch the screen.
But when ray goes from my mobile screen to outer Collider it destroys and does not pass through that collider.
Is there any way to do it?
You could make the outer one a Trigger Collider by checking Is Trigger in the inspector:
and have the inner collider as just a collider. Then you can check the outer one with OnTriggerEnter and the inner one with OnCollisionEnter.
Alternatively you could give them different Tags and check for each Ray hit by checking for the tag (use OnTriggerEnter for this).
void OnTriggerEnter (Collider other)
{
if (other.gameObject.tag == "Inner Cube")
{
// We have hit the inner cube
}
else if (other.gameObject.tag == "Outer Cube")
{
// We have hit the outer cube
}
}
Looking at what you want to do in your question though, using 2 concentric colliders is not as good as simply detecting which input action the user performs (tap or swipe) and acting according to that.
Take a look at Physics.RayCastAll. With RayCastAll your Ray won't return just the first collision but an array of all collisions.
RayCastHit[] hits;
Ray ray = camera.ScreenPointToRay(Input.mousePosition);
hits = Physics.RaycastAll(ray);
// If you have objects behind your object then sort the hit array by distance:
// hits = hits.OrderBy(l => l.distance).ToArray();
for(int i = 0; i < hits.Length; i++)
{
RaycastHit hit = hits[i];
// From here you can use a tag approach similar to what Flaming Zombie posted to check whether the collision object supports swipes or touches.
// Once you find the first valid object then you can perform your action and break out of this loop.
}
However, there are a couple of things to note with this approach:
You will need to loop through each collision.
You will need to determine whether or not the user swiped or touched (you probably already have this down)
Colliders behind the GameObject will also return collisions.
If there is not a specific reason you are using two colliders then I would do what Flaming Zombie suggested and use a single collider. Here is a simple implementation:
Component on collider:
public class ExampleComponent : MonoBehaviour
{
public void OnInteract(bool isSwipe)
{
if (isSwipe)
{
//Rotate
}
else
{
//Animate
}
}
}
Raycast logic:
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
ExampleComponent c = hit.transform.GetComponent<ExampleComponent>()
if(c != null)
{
c.OnInteract(isSwipe); // You'll need to implement isSwipe
}
}