I have an empty gameobject on my scene with a component box collider 2D.
I attached a script to this game object with :
void OnMouseDown()
{
Debug.Log("clic");
}
But when i click on my gameobject, there is no effect. Do you have any ideas ? How can i detect the click on my box collider ?
Use ray cast. Check if left mouse button is pressed. If so, throw invisible ray from where the mouse click occurred to where to where the collision occurred.
For 3D Object, use:
3D Model:
void check3DObjectClicked ()
{
if (Input.GetMouseButtonDown (0)) {
Debug.Log ("Mouse is pressed down");
RaycastHit hitInfo = new RaycastHit ();
if (Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hitInfo)) {
Debug.Log ("Object Hit is " + hitInfo.collider.gameObject.name);
//If you want it to only detect some certain game object it hits, you can do that here
if (hitInfo.collider.gameObject.CompareTag ("Dog")) {
Debug.Log ("Dog hit");
//do something to dog here
} else if (hitInfo.collider.gameObject.CompareTag ("Cat")) {
Debug.Log ("Cat hit");
//do something to cat here
}
}
}
}
2D Sprite:
The solution above would work for 3D. If you want it to work for 2D, replace Physics.Raycast with Physics2D.Raycast. For example:
void check2DObjectClicked()
{
if (Input.GetMouseButtonDown(0))
{
Debug.Log("Mouse is pressed down");
Camera cam = Camera.main;
//Raycast depends on camera projection mode
Vector2 origin = Vector2.zero;
Vector2 dir = Vector2.zero;
if (cam.orthographic)
{
origin = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
else
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
origin = ray.origin;
dir = ray.direction;
}
RaycastHit2D hit = Physics2D.Raycast(origin, dir);
//Check if we hit anything
if (hit)
{
Debug.Log("We hit " + hit.collider.name);
}
}
}
Related
So I'm working on a little top-down perspective game and wanted to add a combat system. I set it up so that it'll shoot a raycast and if it hits an enemy they'll take damage but the raycast is returning nothing.
Vector3 mouse_pos = Input.mousePosition;
mouse_pos.z = 5.23f;
Vector3 objectPos = Camera.main.WorldToScreenPoint(transform.position);
mouse_pos.x = mouse_pos.x - objectPos.x
mouse_pos.y = mouse_pos.y - objectPos.y
if (Input.GetMouseButtonDown(0))
{
Raycast hit;
print(Physics.Raycast(transform.position, mouse_pos, out hit));
if (Physics.Raycast(transform.position, mouse_pos, out hit))
{
if (hit.collider.gameObject.name.Contains("enemy"))
{
hit.collider.gameObject.GetComponent<enemyMovement>().life -= 1;
}
}
}
The print returns false even when there's a gameobject there. It's probably a simple problem but I don't know what to do lol.
I changed the code for you, because I am not very familiar with the ray, thank you and hope it can help you.
void update(){
if (Input.GetMouseButtonDown(0))
{
// When the left mouse button is pressed, emit a ray to the screen
position where the mouse is located
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
if (Physics.Raycast(ray,out hitInfo))
{
// When the ray collides with the object, draw the ray in the scene view
Debug.DrawLine(ray.origin, hitInfo.point, Color.red);
if (hitInfo.collider.gameObject.name.Contains("enemy"))
{
hitInfo.collider.gameObject.GetComponent<enemyMovement>().life -= 1;
}
}
}
}
I'm making a small space game in 3D, but it looks awful when my ship is rotating in the middle of movement
So can someone please help me with code ? I need to rotate to that position and than move to it. (And i forgot to say, that rotation needs to be on Y axis)
Here is my code for that movement.
NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if(Input.GetMouseButton(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.tag == "Ground")
{
agent.SetDestination(hit.point);
}
}
}
You are supposed to stop the agents rotation.
this is the code:
NavMeshAgent agent;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
void Update()
{
if(Input.GetMouseButton(0))
{
agent.updateRotation = false;
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.tag == "Ground")
{
agent.SetDestination(hit.point);
}
}
}
And I also have a more efficient way for you to check if the player is on Ground.
Here is what you should do instead of
hit.collider.tag == "Ground
First, make a Layer named "Ground" (anything... depends on you).
Then, add a LayerMask in the script above the NavMeshAgent. public LayerMask groundLayer
And in the if statement
do this:
if (Physics.Raycast(ray, out hit, groundLayer))
{
agent.SetDestination(hit.point);
}
What this does is, it only considers the click on objects with the selected layer.The plus point here is that you can select multiple layers in the Inspector.
And do not forget to select the layer in the Inspector.
Thank you! <3
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);
}
I spawn objects that have laser beam property. When I click on one of them(specific object), I want it to only show its laser beam not the others.
How can I prevent it? I have a static GameObject variable (touch_detect.clickedObject) by which I can determine which object is clicked.
using UnityEngine;
using System.Collections;
public class Laser : MonoBehaviour
{
private LineRenderer lr;
private bool clicked = false;
RaycastHit rh;
// Use this for initialization
void Start()
{
lr = GetComponent<LineRenderer>();
}
// Update is called once per frame
void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
if (rh.collider.gameObject.name == touch_detect.clickedObject.name)
{
Debug.Log(rh.collider.gameObject.name + " clicked.");
Debug.Log("static object name" + touch_detect.clickedObject.name + " clicked.");
clicked = true;
lr.enabled = true;
}
}
}
if (Input.GetMouseButtonUp(0))
{
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
if (rh.collider.gameObject.name == touch_detect.clickedObject.name)
{
Debug.Log(rh.collider.gameObject.name + " clicked.");
Debug.Log("static object name" + touch_detect.clickedObject.name + " clicked.");
clicked = false;
lr.enabled = false;
}
}
}
if (clicked)
{
lr.SetPosition(0, transform.position + new Vector3(0, 0, 0));
RaycastHit hit;
if (Physics.Raycast(transform.position + new Vector3(0, 0, 0), -transform.up, out hit))
{
if (hit.collider)
{
lr.SetPosition(1, hit.point);
}
}
else lr.SetPosition(1, -transform.up * 5000);
}
}
}
The issue is that since this script is attached to both of your gameobjects, there are two rays being cast at the mouse position (one from each script). Because you are just looking to see that the raycollider matches the static object, this statement is true for both scripts no matter which you click on:
if (rh.collider.gameObject.name == touch_detect.clickedObject.name) // always true
To get an immediate fix, you should change the above statement to something like this to check that the ray is intersecting the same gameobject that the script is attached to:
if (rh.collider.gameObject.name == gameObject.name)
This really is not the best method though since you are still casting two rays and therefore doing all the logic twice (or more times if you spawn more cubes).
A better method would be to have one master gameobject that casts the ray. When this ray intersects a cube, you would then activate a method inside that cubes script to show the laser. So for example:
on the master object you would have:
if (Physics.Raycast(ray, out rh, Mathf.Infinity))
{
// add a tag to all objects with the laser script
if (rh.collider.gameObject.tag == "hasLaser") //verify object has laser script via tag
rh.collider.GetComponent<laser>().activateLaser(); // call public method in collider script
}
and then the cube would have the laser script with a public method:
public void activateLaser()
{
lr.enabled = true;
}
void Update()
{
MovePlayer();
}
Then the first original MovePlayer i did rotate the player but in the specific angle i set for example:
private void MovePlayer()
{
if (Input.GetMouseButtonDown(0))
{
targetAngles = transform.eulerAngles + 85.0f * Vector3.up;
StartCoroutine(TurnObject(transform, transform.eulerAngles, targetAngles, smooth));
}
}
But i want it to rotate to the angle of the mouse cursor position clicked not to walk there or move there only to rotate and face to the mouse cursor position clicked. So i tried to change the MovePlayer method to this but this is wrong it does nothing:
private void MovePlayer()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit))
{
startPositon = hit.point;
targetAngles = transform.eulerAngles + 0 * Vector3.up;
StartCoroutine(TurnObject(transform, transform.eulerAngles, targetAngles, smooth));
}
}
}
And
IEnumerator TurnObject(Transform ship, Vector3 startAngle, Vector3 endAngle, float smooth)
{
float lerpSpeed = 0;
isSpinning = true;
while (lerpSpeed < 1)
{
ship.eulerAngles = Vector3.Lerp(startAngle, endAngle, lerpSpeed);
lerpSpeed += Time.deltaTime * smooth;
yield return null;
}
startPositon = ship.position;
isSpinning = false;
}
This is working but with some problems:
void Update()
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100000))
{
transform.LookAt(hit.point);
}
}
The first problem is when i point the mouse cursor to the sky since it's too far the player is not rotating and then when i point back to something in the distance range the player jump to the position. Not sure how to solve it. Maybe to calculate the sky(sky box in my case) distance so it will rotate also when pointing the sky ?
The second problem is when i point the mouse cursor on my self the player body it's making some fast rotations on place. How can i avoid it ? Or solve it ?
I tried to change the line:
if (Physics.Raycast(ray, out hit, 100000))
To
if (Physics.Raycast(ray, out hit))
But it didn't solve it. Maybe the problem is that my sky is a skybox i dragged to the Scene window so it's not an object.
My skybox is material i dragged to the Scene window so maybe this is the problem i can't rotate the player when the mouse cursor is pointing the sky. Any solution?