How to destroy a specific object when clicked on by mouse? - c#

I'm currently making a sandbox game and it is able to create a object through left click. But, I am struggling to destroy a specific object when it is right clicked. I've looked on previous questions here, but they don't exactly answer my question.
using UnityEngine;
using System.Collections;
public class ControlObjects : MonoBehaviour
{
Vector3 mousePosition, targetPosition;
//To Instantiate TargetObject at mouse position
public Transform targetObject;
public GameObject Prefab;
float distance = 10f;
Ray ray;
RaycastHit hit;
//public int item_num = 1;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position = targetPosition;
//To get the current mouse position
mousePosition = Input.mousePosition;
//Convert the mousePosition according to World position
targetPosition = Camera.main.ScreenToWorldPoint(new Vector3(mousePosition.x, mousePosition.y, distance));
//Set the position of targetObject
targetObject.position = targetPosition;
//Debug.Log(mousePosition+" "+targetPosition);
//If Left Button is clicked
if (Input.GetMouseButtonDown(0))
{
//create the instance of targetObject and place it at given position.
Instantiate(targetObject, targetObject.transform.position, targetObject.transform.rotation);
}
}
}

Implement what you need, but this is the base.
using UnityEngine;
public class Test : MonoBehaviour
{
private float distance = 10;
private float offset = -4;
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse1))
{
GameObject go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.transform.position = new Vector3
{
x = offset += 1.5f,
y = 0,
z = 0
};
}
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Input.GetKeyDown(KeyCode.Mouse0))
{
if(Physics.Raycast(ray, out RaycastHit hit, distance))
{
Destroy(hit.transform.gameObject);
}
}
}
}

You should have a look at IPointerClickHandler. Attach this script to the objects you want to be able to click on
using UnityEngine;
using UnityEngine.EventSystems;
public class DestroyOnRightClick : MonoBehaviour, IPointerClickHandler
{
public void OnPointerClick (PointerEventData eventData)
{
if (eventData.button == PointerEventData.InputButton.Right)
{
Debug.Log ("Right Mouse Button Clicked on: " + name);
Destroy(gameObject);
}
}
}
Note
Ensure an EventSystem exists in the Scene to allow click detection. For click detection on non-UI GameObjects, ensure a PhysicsRaycaster is attached to the Camera.

Related

Raycast not hitting the right position unity

I have been on here forever it feels like and nothing is fixing the issue. So I am relatively new to c# and unity and I set up my weapon and my crosshairs. I went through and set up ray cast and got a impact effect set. When I load in and try to shoot, my impact effect seems to be landing in different positions and it never lands in the same spot. I want to get it to where the effect happens on the target where the crosshairs are.
This line was added after the fact to try and fix it but didn't end up doing anything:
Ray ray = Camera.main.ViewportPointToRay(new Vector2(0.5f, 0.5f));
Here's my script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class shooting : MonoBehaviour
{
public float damage = 10;
public float range = 100;
public Camera cam;
public AudioSource audioSource;
public AudioSource audio1;
public AudioClip clip;
public AudioClip reload;
public float volume = 0.5f;
public ParticleSystem muzzleflash;
public GameObject hitEffect;
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Shooting();
}
if (Input.GetKey(KeyCode.R))
{
Reload();
}
}
void Shooting()
{
muzzleflash.Play();
audioSource.PlayOneShot(clip, volume);
RaycastHit hit;
Ray ray = Camera.main.ViewportPointToRay(new Vector2(0.5f, 0.5f));
if (Physics.Raycast(cam.transform.position, cam.transform.forward, out hit, range))
{
Debug.Log("Shooting");
}
Instantiate(hitEffect, hit.point, Quaternion.LookRotation(hit.normal));
}
void Reload()
{
audio1.clip = reload;
audio1.Play();
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.LeftShift))
{
audio1.Stop();
}
}
}
You've created a ray, you need use it.
Instantiate should be in the if block.
Specify a layer to do raycast, otherwise it can hit any collider in the path.
Ray ray = Camera.main.ViewportPointToRay(new Vector2(0.5f, 0.5f));
var mask = LayerMask.GetMask("Enemy");
if (Physics.Raycast(ray, out hit, range, mask))
{
Instantiate(hitEffect, hit.point, Quaternion.LookRotation(hit.normal));
}
If the effect is still shown at a random place, add some debug code, check the red line in the scene window.
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawLine(ray.origin, hit.point);
}

My draggable UI elements are also dragging camera? How do I prevent UI dragging from moving the camera?

So I have UI elements that can be dragged, so that a prefab can be instantiated OnDragEnd(). I am using below code attached to the UI buttons to achieve this
public class MyButton : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler
{
..
..
..
public void OnDrag(PointerEventData eventData)
{
dragRect.anchoredPosition += eventData.delta;
}
public void OnBeginDrag(PointerEventData eventData)
{
// if we're on deploy cooldown, dont allow dragging this button
if (disableDrag )
{
eventData.pointerDrag = null;
}
}
public void OnEndDrag(PointerEventData eventData)
{
RaycastHit hit;
Ray ray = mainCamera.ScreenPointToRay(eventData.pointerCurrentRaycast.screenPosition);
Physics.Raycast(ray, out hit);
if (hit.collider.gameObject.tag == "Ground")
{
createUnit(hit);
disableDrag = true;
}
}
}
This works fine without any problems, but recently I also implemented the ability to drag the camera. I attached the following code to my camera to achieve this:
public class CameraController : MonoBehaviour
{
public float movementTime;
public Vector3 newPosition;
private Vector3 startPosition;
public Vector3 dragStartPosition;
public Vector3 dragCurrentPosition;
public float xLimit1, xLimit2;
float clampedX;
Camera mainCamera;
private void Start()
{
mainCamera = Camera.main;
newPosition = transform.position;
startPosition = transform.position;
}
// Update is called once per frame
void Update()
{
HandleMouseInput();
clampedX = Mathf.Clamp(newPosition.x, xLimit1, xLimit2);
transform.position = Vector3.Lerp(transform.position, new Vector3 (clampedX, startPosition.y, startPosition.z), Time.deltaTime * movementTime);
}
void HandleMouseInput()
{
// when mouse is pressed,
if (Input.GetMouseButtonDown(0))
{
if (!EventSystem.current.IsPointerOverGameObject())
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
float entry;
if (plane.Raycast(ray, out entry))
{
dragStartPosition = ray.GetPoint(entry);
}
}
}
// if it is still held down
if (Input.GetMouseButton(0))
{
if (!EventSystem.current.IsPointerOverGameObject())
{
Plane plane = new Plane(Vector3.up, Vector3.zero);
Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
float entry;
if (plane.Raycast(ray, out entry))
{
dragCurrentPosition = ray.GetPoint(entry);
newPosition = transform.position + dragStartPosition - dragCurrentPosition;
}
}
}
}
}
And the camera script works as well as it behaves as expected and the camera drags with mouse. But the problem is that when I drag my UI button onto screen that moves the camera also.
I tried to include the if condition of checking if its over a UI if (!EventSystem.current.IsPointerOverGameObject()) But this does not seem to work, the camera still drags when I drag the UI button.
How do I make them work together?
You are on the right path as
!EventSystem.current.IsPointerOverGameObject())
is the right way forward, but make sure to use it like this:
// Check if the left mouse button was clicked
if(Input.GetMouseButtonDown(0))
{
// Check if the mouse was clicked over a UI element
if(!EventSystem.current.IsPointerOverGameObject())
{
Debug.Log("Did not Click on the UI");
}
}
Make sure that the RaycastTarget toggle on your UI component is not enabled.
Also, check the Event Mask in the Physics Raycaster on your camera. IsPointerOverGameObject() will return true if the mouse is over any objects on those layers. If you only want to check for the UI layer, make sure that only UI is checked.
Here are some references:
EventSystem.IsPointerOverGameObject Docu.
EventSystem.IsPointerOverGameObject Manual
Thread that might help you

LineRenderer not drawing where Mouse clicks

Following a tutorial, I'm trying to use a grappling gun mechanic that utilizes a spring joint and Line Renderer.
I've got the line drawing upon mouseclick, but the end of the line is not drawing where the user clicks.
It looks like this:
Can anyone kind of help me out as to why it's not working? Here's the (wonky) project in action-
https://i.imgur.com/IuMsEsQ.mp4
Grappling gun code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrapplingGun : MonoBehaviour
{
private LineRenderer lr;
private Vector3 grapplePoint; //where we grapple to
public LayerMask whatIsGrappable;
public Transform gunTip;
public Transform cam;
public Transform player;
private float maxDistance = 100f;
private SpringJoint joint;
void Awake()
{
lr = GetComponent<LineRenderer>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
StartGrapple();
}
else if (Input.GetMouseButtonUp(0))
{
StopGrapple();
}
}
void LateUpdate()
{
DrawRope();
}
void StartGrapple()
{
RaycastHit hit;
if (Physics.Raycast(cam.position, cam.forward, out hit, maxDistance, whatIsGrappable))
//if (Physics.Raycast(transform.position, Vector3.forward, out hit, maxDistance, whatIsGrappable))
{
grapplePoint = hit.point;
joint = player.gameObject.AddComponent<SpringJoint>();
joint.autoConfigureConnectedAnchor = false;
joint.connectedAnchor = grapplePoint;
float distanceFromPoint = Vector3.Distance(player.position, grapplePoint);
joint.maxDistance = distanceFromPoint * 0.8f;
joint.minDistance = distanceFromPoint * 0.25f;
joint.spring = 4.5f;
joint.damper = 7f;
joint.massScale = 4.5f;
lr.positionCount = 2;
}
}
void DrawRope()
{
//If not grappling, don't draw anything
if (!joint) return;
lr.SetPosition(0, gunTip.position);
lr.SetPosition(1, grapplePoint);
}
void StopGrapple()
{
lr.positionCount = 0;
Destroy(joint);
}
}
Thank you.
The underlying issue is your raycast. the second parameter is the direction of the ray, which you have as the camera direction. Currently your ray is pointing forward from the camera at all times as a result.
What you can do is use Camera.ScreenPointToRay to give a ray to cast along to give you a 3d mouse position to cast to, then use your current raycast but replace the second parameter with the direction from the player to the point hit by the raycast from the function mentioned before
Ray ray = Camera.ScreenPointToRay(Input.mousePosition);
Physics.Raycast(ray, out RaycastHit hit);
if (Physics.Raycast(transform.position, (hit.point - transform.position).normalized, out hit, maxDistance, whatIsGrappable)) {
// Your code here...
}

Moving a instantiated gameobject

I want to change the position of a instantiated game object. For that I have used a UI button when the user clicks on the button a cube will be instantiated and when user clicks on that instantiated cube and move a UI slider, the position of that cube will be changed according to the value given by the slider.
I tried this way but it doesn't work. What am I doing wrong here
using UnityEngine;
using System.Collections;
public class instantiate : MonoBehaviour
{
public GameObject cube;
public float speed = 0f;
public float pos = 0f;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 100.0f))
{
Debug.Log("Clicked");
if (hit.collider.tag == "Cube")
{
// Destroy(hit.collider.gameObject);
// Destroy(this);
speed += Input.GetAxis("Horizontal");
hit.collider.gameObject.transform.eulerAngles = new Vector3(0, 0, speed);
hit.collider.gameObject.transform.position = new Vector3(0, 0, pos);//pos
}
}
}
}
public void objinst()
{
Instantiate(cube, new Vector3(0, 0, 0), Quaternion.identity);
}
public void rotatess(float newspeed)
{
speed = newspeed;
}
public void positions(float newpos)
{
pos = newpos;
}
}
You are supposed to have a callback function that gets called when the Button is clicked and another one that gets called when the Slider value changes. I can't tell if you are doing this from the Editor but the way your functions are named, we can't tell which is one being called during Button click or Slider value change...
Put your Instantiate code in your Button callback function then put your cube moving code in the Slider value change callback function.
In your Raycast code that detects the cube click, store the Transform reference of the cube to a global Transform variable. This stored Transform is what you will use to move the cube in your Slider value change callback function.
You subscribe to Button click event with Button.onClick.AddListener(instantiateButtonCallBackFunction); then to Slider value change event with Slider.onValueChanged.AddListener(delegate { sliderCallBackFunction(cubeSlider.value); });
Here is what it should look like. Everything is done with code. Simply drag the Cube prefab, Slider and Button to the right slot and it should work. When a Button is clicked, Cube is instantiated. When the cube is clicked, you will be able to move it with the slider.
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class instantiate : MonoBehaviour
{
public GameObject cubePrefab;
public Slider cubeSlider;
public Button instantiateButton;
public float speed = 0f;
public float pos = 0f;
private Transform currentObjectToDrag = null;
// Use this for initialization
void Start()
{
//Set Slider Values
cubeSlider.minValue = 0f;
cubeSlider.maxValue = 50f;
cubeSlider.value = 0f;
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, 1000.0f))
{
GameObject objHit = hit.collider.gameObject;
Debug.Log("We Clicked on : " + objHit.name);
//Check if this is cube
if (objHit.CompareTag("Cube"))
{
Debug.Log("Cube selected. You can now drag the Cube with the Slider!");
//Change the current GameObject to drag
currentObjectToDrag = objHit.transform;
}
}
}
}
public void instantiateCube()
{
//Instantiate(cubePrefab, new Vector3(0, 0, 0), Quaternion.identity);
Instantiate(cubePrefab, new Vector3(-15.1281f, 0.67f, 7.978208f), Quaternion.identity);
}
public void rotatess(float newspeed)
{
speed = newspeed;
}
public void positions(float newpos)
{
pos = newpos;
}
//Called when Instantiate Button is clicked
void instantiateButtonCallBack()
{
Debug.Log("Instantiate Button Clicked!");
instantiateCube();
}
//Called when Slider value changes
void sliderCallBack(float value)
{
Debug.Log("Slider Value Moved : " + value);
//Move the Selected GameObject in the Z axis with value from Slider
if (currentObjectToDrag != null)
{
currentObjectToDrag.position = new Vector3(0, 0, value);
Debug.Log("Position changed!");
}
}
//Subscribe to Button and Slider events
void OnEnable()
{
instantiateButton.onClick.AddListener(instantiateButtonCallBack);
cubeSlider.onValueChanged.AddListener(delegate { sliderCallBack(cubeSlider.value); });
}
//Un-Subscribe to Button and Slider events
void OnDisable()
{
instantiateButton.onClick.RemoveListener(instantiateButtonCallBack);
cubeSlider.onValueChanged.RemoveListener(delegate { sliderCallBack(cubeSlider.value); });
}
}
You need to store a reference to the instance you've created.
GameObject myCube = Instantiate(cube, new Vector3(0, 0, 0), Quaternion.identity);
You can then control the position of it using that reference.
myCube.transform.position.x = 10;

Triggering a script on another object when Clicking and Dragging in Unity

I am doing a 2D project where I've added a sprite as a button to shoot. This button works fine. The script attached is: (I added a box collider to the sprite)
using UnityEngine;
using System.Collections;
public class ClickScript : MonoBehaviour {
public shootTest _shooterScript;
// Use this for initialization
void Start () {
}
void LoadScript()
{
_shooterScript.ShootRock();
}
// Update is called once per frame
void Update () {
if(Input.GetMouseButtonDown(0)){
Vector2 mousePosition = new Vector2();
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Collider2D hitCollider = new Collider2D();
hitCollider = this.collider2D;
hitCollider = Physics2D.OverlapPoint(mousePosition);
Debug.Log("mouse pos "+mousePosition.x+" y "+mousePosition.y+" ");
if(hitCollider){
LoadScript();
Debug.Log("Hit "+hitCollider.transform.name+" x"+hitCollider.transform.position.x+" y "+hitCollider.transform.position.y);
}
}
}}
Then I added a crosshair to be able to calculate a direction to aim. Here is the script to click and drag the object. Circle Colider 2D on this object.
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(MeshCollider))]
public class Aim : MonoBehaviour
{
private Vector3 screenPoint;
private Vector3 offset;
void OnMouseDown()
{
screenPoint = Camera.main.WorldToScreenPoint(gameObject.transform.position);
offset = gameObject.transform.position - Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z));
}
void OnMouseDrag()
{
Vector3 curScreenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenPoint.z);
Vector3 curPosition = Camera.main.ScreenToWorldPoint(curScreenPoint)+offset;
this.transform.position = curPosition;
}
}
When I add this aiming script and click on the crosshair to drag it, the shoot script goes off.
I'm very new to unity so I'm assuming it is something simple. Thanks for the help.
I changed the update function in the click script to
void Update () {
if(Input.GetMouseButtonDown(0)){
Vector2 mousePosition = new Vector2();
mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if(this.collider2D.OverlapPoint(mousePosition)){
LoadScript();
}
}
So it only triggers when that specific object is clicked. Maybe there is a cleaner way, but this worked.

Categories

Resources