There are many questions like this, but I didn't find a valid solution to my problem.
I would like to click an object behind a collider, this is my code:
void Update () {
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.transform.name);
}
}
I put this code inside the script attached to the first object but the debug log will never be called.
Any ideas?
If I understand your question right, you want to click on the yellow sphere (see image) and want the name of the white cube?
There are two possible ways to do that:
1. Ignore Raycast Layer
You could give the yellow sphere the unity standard layer "Ignore Raycast":
Then your code should work (I added the on left mouse click)
void Update()
{
if (Input.GetMouseButtonDown(0)) // Click on left mouse button
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.transform.name);
}
}
}
2. Use Layer Mask
See: Using Layers and Bitmask with Raycast in Unity
If that's not what you're looking for please give further information and a screen shot of your problem.
Related
I'm creating a top down 2D game, where the player has to break down trees. I made it so the player casts a ray toward the mouse, and when the ray hits a tree, it should lower the tree's health. I don't get any errors when I run the game or click, but it seems like the tree isn't detecting the hits.
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
RaycastHit2D hit = Physics2D.Raycast(playerRb.transform.position, mousePosition - playerRb.transform.position, 2.0f);
if (hit.collider != null)
{
if (hit.collider == GameObject.FindWithTag("Tree"))
{
hit.collider.GetComponent<TreeScript>().treeHealth--;
}
}
}
}
Still pretty new to coding and I'm teaching myself, so please make your answer easy to understand to help me learn.
Input.mousePosition is equal to the pixel your mouse is on. This is very different than the location your mouse is pointing at in the scene. To explain further, Input.mousePosition is where the mouse is. Think about it. If the camera was facing up, the mouse positon would be the same, but where they are clicking is different.
Instead of using Input.mousePosition, You should pass this into a function called Ray Camera.ScreenPointToRay();
You just input the mouse position and then use this new ray to do the raycast.
ANOTHER EXTREMELY IMPORTANT THING 1: Do not use Camera.main in Update(), as it uses a GetComponet call, which can cause perormance decreases. Store a reference of it in your script and use that.
Extremely important thing 2: I notice you are using GetComponent to change the tree's health. This is fine, but do not use GetComponent if you don't have to.
Like this:
Camera cam;
void Start()
{
cam = Camera.main; //it is fine to use this in start,
//because it is only being called once.
}
void Update()
{
...
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray);
...
}
}
You need to convert your mouse position from screen point to world point with Z value same as the other 2D objects.
Vector3 Worldpos=Camera.main.ScreenToWorldPoint(mousePos);
Also use a Debug.DrawRay to check the Raycast
Debug.DrawRay(ray.origin, ray.direction*10000f,Color.red);
Source
so, basically, I have created a pretty simple turret script that basically just smoothly aims at the player, so long as the player is within a certain amount of range. The problem I am having, is that the Raycast I wrote that actually checks if the 'bullet' (which is nothing - it's just a raycast), would hit the target. This means that even if the player hides behind a wall, the turret can still shoot him.
My current raycast script allows the raycast to go straight through the wall, and since I am new to Unity, I have no idea how to make it check if the first object it hits is the player, so that it cannot go through walls.
Here is my current raycast script:
void Shoot()
{
//I think the problem is here - I want the raycast to return false if it hits a wall - which has the layer "ground", and true if it hits the player. Problem is, I need to make the turret return to resting position when the player is behind a wall.
//To do this, I can just set inRange = true; But I need to be able to determine when the player is behind a wall.
LayerMask layerMask = LayerMask.GetMask("Player");
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
{
//This determines how much damage will the player take.
int damage = Random.Range(1, 5);
hit.collider.gameObject.GetComponent<playerMovement>().Shot(damage);
//I personally THINK this means that it only triggers collisions with the player, which is why it is not working.
// The player has layer "Player", and tag "Player", so if anyone who wants to help can figure out how to make it stop when it hits anything - and then only return true if it hit the player (meaning the player is not behind walls).
}
}
If you want to check if there is anything between the player and the Raycast, then simply remove the Layermask
Change this:
LayerMask layerMask = LayerMask.GetMask("Player");
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
To this:
Ray ray = new Ray(transform.position, transform.TransformDirection(Vector3.forward));
if (Physics.Raycast(ray, out RaycastHit hit) {..}
You want to
remove the check for the layer in order to hit everything with the raycast
then you can use TryGetComponent to check whether the hit object has such component attached or not
and in general instead of
transform.TransformDirection(Vector3.forward)
simply use transform.forward ;)
So something like
void Shoot()
{
if (Physics.Raycast(transform.position, transform.forward, out var hit))
{
// Without the need for any tag or layer check
// Simply check if the object you hit has a playerMovement component
// GetComponent was improved a lot lately and now uses hashes
// it's not that performance intense anymore and almost as fast as CompareTag
if(hit.gameObject.TryGetComponent<playerMovement>(out var movement)
{
int damage = Random.Range(1, 5);
movement.Shot(damage);
}
}
}
All you'd need to do is cast from the turret to the player and detect what the raycast has hit. Your current code is setting a mask to only be on the player, so it will never hit a wall. You can change your code to something like this:
private LayerMask layerMask = (1 << LayerMask.NameToLayer("Player") | (1 << LayerMask.NameToLayer("ground")));
void Update () {
if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out RaycastHit hit, Mathf.Infinity, layerMask))
{
if(hit.collider.gameObject.layer == LayerMask.NameToLayer("Player"))
{
// you can shoot as you see the player
}
else
{
// you hit the ground - player is behind a wall
}
}
}
I am casting a ray from an empty transform at the tip of a gun. The cast is to head towards the mouse position on Right Click. There is a unexpected result of the hit point being half way from expected.
I have attempted to rework the Raycasting and check out the Unity documents and forums, perhaps i am missing so simple. I have included the code of my Fire Function. Note "Raycaster" is the empty gameobject it fires from.
public void Fire(Vector3 point)
{
RaycastHit hit;
if(Physics.Raycast(Raycaster.transform.position, point, out hit))
{
Debug.DrawLine(Raycaster.transform.position, point, Color.green); //expected
Debug.DrawLine(Raycaster.transform.position, hit.point, Color.red); //actual
if(hit.rigidbody != null)
{
hit.rigidbody.AddForce(-hit.normal * weapon.Damage);
}
GameObject Impact = Instantiate(ImpactParticle, hit.point, Quaternion.LookRotation(hit.normal));
Destroy(Impact, 1f);
}
}
The first Debug.Drawline in Green is what I expect, but the second Debug.Drawline is the actual. I must be the hit.point from the Raycast but it always is half way.
Issue example, Green is expected and red is actual
I think you use world position(point). Try convert your point argument to direction.
Vector3 dir = point - Raycaster.transform.position;
Physics.Raycast(Raycaster.transform.position, dir, out hit)
I have a Physics Raycaster attached to the Camera. The Pointer Click Event Trigger is working correctly. However I need to do it from the source code. These are my attempts:
private void SetOnPushButtonFireManager(){
cardboard.OnTrigger += () => {
Debug.Log("Button triggered!");
RaycastHit hit;
// if(Physics.Raycast(headGameObject.GetComponent<GvrHead>().Gaze, out hit, Mathf.Infinity)){
if(Physics.Raycast(cameraGameObject.transform.position, cameraGameObject.transform.forward, out hit, Mathf.Infinity)){
Debug.Log("Collision detected!");
}
};
}
"Button triggered!" is shown in the Console. Unfortunately "Collision detected!" is not. However the Pointer Click Event Trigger is working correctly (the component attached in the inspector). How can I know what is going on? Why isn't it working?
UPDATE: I have answered this answer here: http://answers.unity3d.com/answers/1200449/view.html
(stackoverflow does not allow me to delete this question)
Here's some code I've been using to fire a ray from the camera. I don't have Google Cardboard, this was setup for a camera and a mouse pointer.
// Fire ray from camera
float rayLength = 2f
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
// If ray hits object within length
if (Physics.Raycast(ray, out hit, rayLength))
{
Debug.Log("Collision detected!:);
}
It didn't work for me either, in the end, I forgot to put the "GvrPointerPhysicsRaycaster" class in the camera. Inspector Image
Once added, it worked perfectly.
void Update()
{
RaycastHit hit;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hit, Mathf.Infinity))
{
if (activeSelected == null)
{
if (hit.collider.tag == "Plane")
activeSelected = Instantiate(mainApp.mainModel.preafabSelect, hit.point, Quaternion.LookRotation(hit.normal));
} else
{
activeSelected.transform.position = hit.point;
activeSelected.transform.rotation = Quaternion.LookRotation(hit.normal);
}
}
}
I've tried some examples of code to handle click on object, but they are don't work.
I have object's mesh on scene:
On Main Camera there is one C# Script Component with code:
using UnityEngine;
using System.Collections;
public class cameraAnim3 : MonoBehaviour
{
void Update() {
if (Input.GetMouseButtonDown (0)) { // if left button pressed...
print ("cli!!!");
// create a ray passing through the mouse pointer:
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit)) { // if something hit...
print ("clicked on object!!!");
// if you must do something with the previously
// selected item, do it here,
// then select the new one:
Transform selected = hit.transform;
selected.gameObject.SetActive (true);
print (selected.gameObject.name);
// do whatever you want with the newly selected
// object
}
}
}
}
When I clicked with left button on the mesh of head, in console message "cli!!!" showed, but no message "clicked on object!!!" was showed.
How to catch click on this mesh?
Answer is here Unity: Object is not being detected by raycast for highlighting
The modern to detect collisions is to implement IPointerClickHandler interface, and ensure that you have an EventSystem and a relevant Raycaster (2d or 3d, depending on what collider are you using) present in the scene. It's much better than writing your own code to manage clicks and pointer positions. Also, the game object itself has to have a Collider component. It can either be a mesh collider, or a more generic (and better for performance) box collider.