Destroy GameObject when its clicked on - unity3d

I'm making a building mechanic in my game and I want to be able to clear out certain objects around the map (trees, other decor) so I have room to build. I've tried using a ray cast to find what object is being clicked on and destroy it but that doesn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectDestroy : MonoBehaviour {
// Start is called before the first frame update
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
Debug.Log (Input.mousePosition);
if (Physics.Raycast (ray, out hit)) {
if (hit.collider.gameObject == gameObject) Destroy (gameObject);
}
}
}
}

Here is a little example script:
public class Destroyable : MonoBehaviour
{
private void OnMouseDown()
{
Destroy(gameObject);
}
}
You can attach this script to the GameObject you want to destroy and then during Play-Mode you can click on it to destroy it. It is modifiable if you just need it in your In-Game-Editor.
Note: You need an active Collider on the same Gameobject.
Edit:
The following script shows an example for changing the color of the object:
public class Destroyable : MonoBehaviour
{
public Color mouseHoverColor = Color.green;
private Color previousColor;
private MeshRenderer meshRenderer;
private void Start()
{
meshRenderer = GetComponent<MeshRenderer>();
previousColor = meshRenderer.material.color;
}
private void OnMouseDown()
{
Destroy(gameObject);
}
private void OnMouseOver()
{
meshRenderer.material.color = mouseHoverColor;
}
private void OnMouseExit()
{
meshRenderer.material.color = previousColor;
}
}

You don't need to add this script on every object, just add it to a manager and also I think you are missing Raycast parameters.
To see where you ray is going you can use Debug.Ray()
Also, I would prefer you use #MSauer way since is much cleaner for what you want, just be sure the object contains a collider, I think they can be a trigger and the click will still happen.

Related

How to destroy instantiated button upon collision exit - Unity 3D

I am a beginner in Unity and I am currently making a simple game. I have a problem where the instantiated Button is not destroyed.
The process of the script is to instantiate a button and destroy it upon collision exit. But when I move out of the object, the object stays and it is not destroyed. i don't know if there is something wrong with the Destroy code of line.
Here is the script for the collision:
using UnityEngine;
using UnityEngine.UI;
public class InteractButtonPosition : MonoBehaviour
{
public Button UI;
private Button uiUse;
private Vector3 offset = new Vector3(0, 0.5f, 0);
// Start is called before the first frame update
void Start()
{
//uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
}
// Update is called once per frame
void Update()
{
//uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
private void OnCollisionEnter(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
uiUse = Instantiate(UI, FindObjectOfType<Canvas>().transform).GetComponent<Button>();
uiUse.gameObject.SetActive(true);
uiUse.transform.position = Camera.main.WorldToScreenPoint(this.transform.position + offset);
}
}
private void OnCollisionExit(Collision collisionInfo)
{
if(collisionInfo.collider.name == "Player")
{
Destroy(uiUse);
}
}
}
The code does exactly what you have written, which is destroying uiUse which is a Button component. If you go and inspect your game object in the scene, you will see, that indeed, the button component has been destroyed.
What you want to do is to destroy the GameObject the button component is attached to, like: Destroy(uiUse.gameObject)

How to show a trigger only when pointing to it directly?

I created a transparent cube trigger and I placed it in front of closed doors, so whenever the player walks near the door a message appears saying "this door is locked".
However, I want the message to be gone whenever the player is Not pointing to the door. currently, it shows even when I turn around, the player needs to walk away from the door to make the message disappear.
Here is my code:
public class DoorsTrigger : MonoBehaviour
{
public GameObject partNameText;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
partNameText.SetActive(true);
}
}
private void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
partNameText.SetActive(false);
}
}
}
How can I modify it to achieve my goal?
Here is a simple example using Vector3.Angle() to get the direction the player is facing relative to that trigger.
public class DoorsTrigger : MonoBehaviour
{
public GameObject partNameText;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
//Assuming 'other' is the top level gameobject of the player,
// or a child of the player and facing the same direction
Vector3 dir = (this.transform.position - other.gameObject.transform.position);
//Angle will be how far to the left OR right you can look before it doesn't register
float angle = 40f;
if (Vector3.Angle(other.gameObject.transform.forward, dir) < angle) {
partNameText.SetActive(true);
}
}
}
private void OnTriggerExit(Collider other)
{
//Make sure the text is actually showing before trying to disable it again
if (other.CompareTag("Player") && partNameText.activeSelf)
{
partNameText.SetActive(false);
}
}
}
Alternatively, you can keep your trigger mostly as is, and do a ray cast from the player to see if they are looking at the door.
//Put this snippet in a function and call it inside the player's Update() loop
RaycastHit hit;
Ray ray = new Ray(this.transform.position, this.transform.forward);
if(Physics.Raycast(ray, out hit))
{
//Tag the gameObject the trigger is on with "Door"
if(hit.collider.isTrigger && hit.collider.CompareTag("Door"))
{
//Here is where you would call a function on the door trigger to activate the text.
// Or better would be to just have that code be on the player.
// That way you can avoid unnecessary calls to another gameObject just for a UI element!
}
}

Unity NavMeshAgent not reaching target - moving around

I've created a simple scene and I'm now trying to make a rabbit move to the mouse-click position on a Plane.
So I've added a Rigidbody, a Nav Mesh Agent and a simple "Pathfinding" script to the rabbit.
The planes Mesh Renderer is set to "Navigation Static", "Generate OffMeshLinks" and "Walkable"
Now as soon as the rabbit gets close to the given destination, it will not stop but rather is "running around" in a very small circle around the destination.
Here is my script
using UnityEngine;
using UnityEngine.AI;
public class Pathfinding : MonoBehaviour {
private NavMeshAgent agent;
private Animator animator;
// Use this for initialization
void Start() {
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update() {
RaycastHit hit;
if(Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)) {
agent.SetDestination(hit.point);
animator.SetInteger("AnimIndex", 1);
animator.SetBool("Next", true);
}
}
}
}
and a picture of my rabbit object ;)
Stopping Distance should be > 0
Actually I was wrong, updating Unity didn't fix the problem, but I recognized that the problem was that the animations "Root Transformation Position (XZ)"/ Bake Into Pose was deactivated.
I also changed my script to
using UnityEngine;
using UnityEngine.AI;
public class Pathfinding : MonoBehaviour {
private NavMeshAgent agent;
private Animator animator;
private bool run = false;
// Use this for initialization
void Start() {
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
// Update is called once per frame
void Update() {
RaycastHit hit;
if(Input.GetMouseButtonDown(0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit)) {
Debug.Log("start");
agent.SetDestination(hit.point);
animator.SetInteger("AnimIndex", 1);
animator.SetBool("Next", true);
run = true;
}
}else if(agent.remainingDistance <= agent.stoppingDistance && run) {
Debug.Log("stop");
animator.SetInteger("AnimIndex", 0);
animator.SetBool("Next", true);
run = false;
}
}
}

Control object rotation by mouse click in unity

I need help with my project in unity
I want to stop each object by clicking on it.
What I did so far:
all my objects rotate but when I click anywhere they all stop, I need them to stop only if I click on each one.
This is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EarthScript : MonoBehaviour
{
public bool rotateObject = true;
public GameObject MyCenter;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
if(rotateObject == true)
{
rotateObject = false;
}
else
{
rotateObject = true;
}
}
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}
}
Theres two good ways to achieve this. Both ways require you to have a collider attatched to your object.
One is to raycast from the camera, through the cursor, into the scene, to check which object is currently under the cursor.
The second way is using unity's EventSystem. You will need to attach a PhysicsRaycaster on your camera, but then you get callbacks from the event system which simplifies detection (it is handled by Unity so there is less to write)
using UnityEngine;
using UnityEngine.EventSystems;
public class myClass: MonoBehaviour, IPointerClickHandler
{
public GameObject MyCenter;
public void OnPointerClick (PointerEventData e)
{
rotateObject=!rotateObject;
}
void Update()
{
if(rotateObject == true)
{
Vector3 axisofRotation = new Vector3(0,1,0);
transform.RotateAround(MyCenter.transform.position,axisofRotation, 30*Time.deltaTime);
transform.Rotate(0,Time.deltaTime*30,0,Space.Self);
}
}

Script code only seems to work on single instance of prefb

I am experiencing the strangest issue
I have a ray cast and when it touches a certain layer it calls my function which does a small animation.
The problem is, this only works on a single object, I have tried duplicating, copying the prefab, dragging prefab to the scene, it doesn't work.
Now I have this code below, and as you can see I have this line which allows me to access the script on public PlatformFall platfall; so I can call platfall.startFall();
Something I've noticed, If I drag a single item from the hierarchy to the public PlatFall in Inspector then that SINGLE object works as it should. ( in that it animates when startFall is called). HOWEVER, if I drag the prefab from my project to the inspector then they do not work. (Even if debug log shows that the method is called animation does not occur).
public class CharacterController2D : MonoBehaviour {
//JummpRay Cast
public PlatformFall platfall;
// LayerMask to determine what is considered ground for the player
public LayerMask whatIsGround;
public LayerMask WhatIsFallingPlatform;
// Transform just below feet for checking if player is grounded
public Transform groundCheck;
/*....
...*/
Update(){
// Ray Casting to Fallingplatform
isFallingPlatform = Physics2D.Linecast(_transform.position, groundCheck.position, WhatIsFallingPlatform);
if (isFallingPlatform)
{
Debug.Log("Here");
platfall.startFall();
}
Debug.Log(isFallingPlatform);
}
}
Platform Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlatformFall : MonoBehaviour
{
public float fallDelay = 0.5f;
Animator anim;
Rigidbody2D rb2d;
void Awake()
{
Debug.Log("Awake Called");
anim = GetComponent<Animator>();
rb2d = GetComponent<Rigidbody2D>();
}
private void Start()
{
Debug.Log("Start Called");
}
//void OnCollisionEnter2D(Collision2D other)
//{
// Debug.Log(other.gameObject.tag);
// GameObject childObject = other.collider.gameObject;
// Debug.Log(childObject);
// if (other.gameObject.CompareTag("Feet"))
// {
// anim.SetTrigger("PlatformShake");
// Invoke("Fall", fallDelay);
// destroy the Log
// DestroyObject(this.gameObject, 4);
// }
//}
public void startFall()
{
anim.SetTrigger("PlatformShake");
Invoke("Fall", fallDelay);
Debug.Log("Fall Invoked");
// destroy the Log
// DestroyObject(this.gameObject, 4);
}
void Fall()
{
rb2d.isKinematic = false;
rb2d.mass = 15;
}
}
I understood from your post that you are always calling PlatformFall instance assigned from inspector. I think this changes will solve your problem.
public class CharacterController2D : MonoBehaviour {
private PlatformFall platfall;
private RaycastHit2D isFallingPlatform;
void FixedUpdate(){
isFallingPlatform = Physics2D.Linecast(_transform.position, groundCheck.position, WhatIsFallingPlatform);
if (isFallingPlatform)
{
Debug.Log("Here");
platfall = isFallingPlatform.transform.GetComponent<PlatformFall>();
platfall.startFall();
}
}
}
By the way, i assume that you put prefab to proper position to cast. And one more thing, you should make physics operations ,which affect your rigidbody, in FixedUpdate.