I wish to detect if a GameObject is touched or clicked and deactivate it. I have followed a Youtube tutorial but cant get it to work.
I get the error Cannot convert from UnityEngine.Ray to UnityEngine.Vector2
I have the script attached to the object.
public class Hand : MonoBehaviour {
void Update() {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit2D;
if (Input.GetMouseButtonDown(0)) {
if (Physics2D.Raycast(ray, out hit2D)) {
transform.gameObject.SetActive(false);
}
}
}
}
You are doing it wrong.
When a click is detected you are disabling the object. Unity has a very handy way of dealing with this problem. Here is the code for it:
private void OnMouseDown()
{
if (Input.GetMouseButtonDown(0))
{
this.SetActive(false);
}
}
Physics2D.Raycast has no version with Ray parameters; and is not really intended to work with the Z axis, which a camera-to-world cast needs, either.
Use OnMouseDown() instead. If on the clicked object itself, as transform.gameObject.SetActive(false); indicates to be the case, no further action is needed.
If for an external object, you can get the mouse world position with var worldMousePoint
= (Vector2)Camera.main.ScreenPointWorldPoint(Input.mousePosition);, and then check for overlap on a target Collider2D with worldMousePoint == targetCollider2D.ClosestPoint(worldMousePoint).
Related
Trying to figure out how to destroy an object by clicking on it. I have tried using
public void Destroy()
{
if (Input.GetMouseButton(0))
Destroy(GameObject);
}
but realise that this will destroy all gameobjects the script is attached to instead of the one I am clicking on.
Try this one:
public void OnMouseDown() => Destroy(gameObject);
Definitely the best way is to implement IPointerClick interface,
using UnityEngine;
using UnityEngine.EventSystems;
public class ClickDestroy : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick(PointerEventData eventData)
{
GameObject.Destroy(gameObject);
}
}
This will work both for UI and for 3D Objects, as long as your camera has PhysicsRaycaster and an EventSystem exists on scene
You can get the mouse position on the screen and fire a raycast from that location. If it hits a gameobject then you can pass it to a function to delete it.
void Update {
//Check for mouse click
if (Input.GetMouseButton(0))
{
//Create a ray from mouse location
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit = new RaycastHit();
//Check if the ray hit a gameobject, gameobject will likely need a collider
//for this to work
if (Physics.Raycast(ray, out hit))
{
//If the ray hit a gameobject, destroy the gameobject
Destroy(hit.gameobject)
}
}
}
When destroying gameobjects, make sure your specifying the gameobject component and not the script or another component of the gameobject.
This code can be improved by defining a camera object in your code and assigning a camera to it in the inspector instead of it defaulting to the main or setting up full player controls in unity (Which I can't remember how to do off the top of my head I'm afraid)
So, I am dragging 2D sprites from the canvas and instantiating a 3D object. But the issue is prefabs are spawning at their default location.This is the code. Removed all the things I tried for spawning
You are trying to instatiate a prefab without specifying the position to instantiate. Try something like this.
public void OnEndDrag(PointerEventData eventData)
{
Instantiate(prefab,eventData.position);
}
Reference:
https://docs.unity3d.com/ScriptReference/Object.Instantiate.html
https://docs.unity3d.com/2017.3/Documentation/ScriptReference/EventSystems.PointerEventData-position.html
You don't do anything with the objects position so it will spawn at the origin.
Without seeing your project it's hard to guess what you game requires for placing behavior, I'm assuming you have some an environment you want to place it on and that can easily be done with a Physics.Raycast(). But if you're not over any environment then you can fire a ray from your mouse position & project it an arbitrary amount forwards from the camera and place the object there for a good effect.
This snippet should be enough for that:
public float raycastDistance = 10f;
public float projectDistance = 4f;
public void OnEndDrag(PointerEventData eventData)
{
var spawned = Instantiate(prefab);
var ray = Camera.main.ScreenPointToRay(eventData.position);
if (Physics.Raycast(ray, out RaycastHit hit, raycastDistance)
{
spawned.transform.position = hit.point;
}
else
{
spawned.transform.position = Camera.main.transform.position + (ray * projectDistance);
}
}
If you prefer you can update the position of the spawned object in OnDrag() instead of just setting it in OnDragEnd() which can look quite nice if you interpolate the position of the object slightly as the mouse moves.
I am trying to recreate a simple laser puzzle mechanic like seen in The Talos Principle - where i have a laser emitter that i can move and rotate, and when the beam (raycast and LineRenderer) hits a specific object, that object will become "active". However when the object is no longer being hit by a laser it should "deactivate".
I am having troubles with the Deactivate part. Is there a way to tell the object that it is no longer being hit by a raycast, or add a collider to the LineRenderer maybe? Or some third way to tell the object that it is no longer being hit by any lasers.
When your target is hit by a raycast, you could use the RaycastHit reference to acquire a script and update the cooldown.
Lets say we have RaySender and RayReceiver.
RaySenderScript
public class RaySenderScript{
RaycastHit Hit;
void FixedUpdate(){
//SendRaycast and store in 'Hit'.
if (Hit.collider != null)
{ //If raycast hit a collider, attempt to acquire its receiver script.
RayReceiverScript = Hit.collider.gameObject.GetComponent<RayReceiverScript>();
if (RayReceiverScript != null)
{ //if receiver script acquired, hit it.
RayReceiverScript.HitWithRay();
}
}
}
}
RayReceiverScript
public class RayReceiverScript{
public float HitByRayRefreshTime = 1f;
float RayRunsOutTime;
public bool IsHitByRay = false;
void Start()
{ //Initialize run out time.
RayRunsOut = Time.time;
}
void Update()
{
if (Time.time > RayRunsOutTime)
{ //check if time run out, if it has, no longer being hit by ray.
IsHitByRay = false;
}
}
public void HitWithRay(){ //method activated by ray sender when hitting this target.
IsHitByRay = true;
RayRunsOutTime = Time.time + HitByRayRefreshTime;
}
}
Sender strikes Receiver with a ray.
Sender has a reference to Receiver, it uses GetComponent() to access it. It can then say receiverScript.HitWithRay();
Receiver keeps checking if it no longer is receiving, if it isnt, it stops being hit by ray.
Add all objects hit by laser to collection and check if current target is in this collection. If it is not there, then it is "deactivated".
So when I am clicking on the object in the game I get this error...
NullReferenceExceptionm : Object reference not set to an instance of an object
JumpDestination.Update () (at Assets/Scripts/JumpDestination.cs.:12)
I don't know what I am doing wrong,how can I fix it?
I want to get the position of the hited object.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JumpDestination : MonoBehaviour {
private RaycastHit hit;
public float jumpMaxDistance;
void Update(){
Physics.Raycast (Camera.main.ScreenPointToRay (Input.mousePosition), out hit, jumpMaxDistance);
if (hit.collider.gameObject.tag == "RichPoint") {
print (hit.collider.transform.position);
}
}
}
I don't know what I am doing wrong,how can I fix it? I want to get the
position of the hited object.
3 things you did wrong:
1.You did not check if mouse is pressed before raycasting.
2.You did not check if Physics.Raycast hit anything before printing the object's position.
3.You defined the hit variable outside a function. Not a good idea because it will still store the old object the mouse hit. Declare that in the update function.
FIX:
void Update()
{
//Check if mouse is clicked
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
//Get ray from mouse postion
Ray rayCast = Camera.main.ScreenPointToRay(Input.mousePosition);
//Raycast and check if any object is hit
if (Physics.Raycast(rayCast, out hit, jumpMaxDistance))
{
//Check which tag is hit
if (hit.collider.CompareTag("RichPoint"))
{
print(hit.collider.transform.position);
}
}
}
}
Regardless, this answer was made to show you what you did wrong. You should not be using this. Use Unity's new EventSystems for this. Check the 5.For 3D Object (Mesh Renderer/any 3D Collider) from this answer for proper way to detect clicked object.
Im currently working on a 2D character selection screen in Unity that should operate similarly to the Mortal Kombat character selection screen. Currently, I have a class called CharacterSelector attached to the main camera. The class holds methods for selection/deselection of characters, hover events, and selection confirmation. I was able to use a RayCast2D to build my character selection method; however, I am running into issues using it for hover events.
In my scene, I have a group of character images that the player can choose from (if they are unlocked). When the player hovers over the character with his/her mouse, the character image should be surrounded by a yellow border. When the user clicks on the desired character, a larger version of the image will popup to the left of the character image group.
Right now, I have the following code for the hover method:
public void onHover(Ray ray, RaycastHit2D hit)
{
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
if (Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity))
{
print(hit.collider.name);
}
}
This method belongs to a class that the CharacterSelection class inherits from. The following is on the CharacterSelection class:
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
}
void Update()
{
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Also, all the character images that I am trying to hover over currently have 2D Box Colliders. As of right now, I am unable to get hover operation to work. It does not print the name of the character image to the console. I am using this as a first step to see if Unity recognizes the character image or not. Let me know if I can provide additional information!
Mouse changes position on screen almost every frame. This means your ray should be updated every frame according to mouse position. So I moved the corresponding statement from Start() to Update();
class CharacterSelector : Selector
{
Ray ray;
RaycastHit2D hit;
public void Start()
{
}
void Update()
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
onHover(ray, hit);
if (Input.GetMouseButtonDown(0))
{
selectCharacter();
}
}
}
Secondly, if you look in the definition of Physics2D.Raycast you'll find that it gives you back the RaycastHit2D object. This is the object you should check the collider of, not your hit object which should have thrown an NullReferenceException, I don't know why it didn't. So this:
public void onHover(Ray ray, RaycastHit2D hit)
{
hit = Physics2D.Raycast(ray.origin, ray.direction, Mathf.Infinity);
if(hit.collider == null)
{
Debug.Log("nothing hit");
}
else
{
print(hit.collider.name);
}
}
Apart from this you don't really need the hit argument in onHover() function, it can be a local variable in the function. But if you are planning on using your hit variable in CharacterSelector script than you should change the declaration of onHover to: onHover(Ray ray, out RaycastHit2D hit) the out keyword passes the variable by reference instead of a copy of its value.
Also, I think checking if mouse is hovering over an object shouldn't be done in onHover, it's kinda misleading and doesn't seem logical to me. I'd move the body of onHover to another function like RaycastChecker(). I'd call onHover() only if mouse is actually hovering over the sprite. (like in OnCollisionEnter you take it granted that the collision did happen, so should the onHover, I think)