How to Drag Objects in unity3D? - unity3d

I am new to unity. I am working on cake maker like game for android device. I am facing a difficulty in dragging objects from cabinet to table. On table i want to mix them in a jar. These are Many items. So, I cannot do it by separating them using unity Tags. How to make a generic way to drag them on table?
I am using this code but its not working for me.
using UnityEngine;
using System.Collections;
public class DragObjects : MonoBehaviour {
Ray ray;
RaycastHit hit;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown(0))
{
ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit))
{
if (hit.collider.tag == "oil")
{
OnMouseDrag();
}
}
}
}
void OnMouseDrag()
{
Vector3 point = Camera.main.ScreenToWorldPoint(Input.mousePosition);
point.x = gameObject.transform.position.x;
gameObject.transform.position = point;
}
}

The Unity way of doing this would be to have a Draggable behaviour which you attach to each object you wish to drag.
If you are using 2D colliders you can use something like this:
Vector3 pos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
bool isOver = collider2D.OverlapPoint(pos);
With 3D colliders you can get a ray from the camera and see if that intersects with a draggable.
Then you can use other colliders to detect when they are placed on the jar.

Related

Got an error about RayCast when getting the mouse position

NullReferenceException: Object reference not set to an instance of an object
DragBlock.Update () (at Assets/Script/DragBlock.cs:13)
using UnityEngine;
public class DragBlock : MonoBehaviour
{
private bool isBeingHeld = false;
private Vector3 startPos;
private Transform heldObject;
private void Update()
{
if (Input.GetMouseButton(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.transform.CompareTag("Blocks"))
{
isBeingHeld = true;
startPos = hit.transform.position;
heldObject = hit.transform;
}
}
}
if (isBeingHeld)
{
Vector3 currentMousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
currentMousePos.z = heldObject.position.z;
heldObject.position = currentMousePos;
}
if (Input.GetMouseButtonUp(0))
{
isBeingHeld = false;
}
}
}
I tried to change the group of the object tried to check the position and so on in this code it should check the position of the mouse and drag the object with the Blocks tag
If line 13 is this one...
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
... then the only part of the code that could realistically be null is the Camera.main property. Camera.main is returned by Unity when Unity looks for, and finds, a Camera in your scene that's tagged "MainCamera".
I suggest that you might have removed or changed that tag of the Camera, or a parent of the camera, and now Unity can't find an appropriate camera.
This is echoed in the online documentation https://docs.unity3d.com/ScriptReference/Camera-main.html

Dragging an object with raycast is laggy

When dragging an object slowly with a raycast the object moves with a bit of lag.
When dragging the object fast the mouse pointer gets out of the field of layer raycasting so the object is no more moving.
The main project is dragging a cube on a plane.
But in order to make the project more simpler, I opened a new 2D project and made a circle and assigned to it the following script, and attached to it a sphere collider (the main target is in 3D space).
// If some one wrote:
private Vector2 deltaPos;
void Update () {
Vector2 touchPos;
if (Input.GetMouseButtonDown (0)) { // Clicking the Target
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
touchPos = new Vector3 (hit.point.x, hit.point.y);
deltaPos.x = touchPos.x - transform.position.x;
deltaPos.y = touchPos.y - transform.position.y;
Debug.Log ("You Clicked Me");
}
}
if (Input.GetMouseButton (0)) {
RaycastHit hit;
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit, Mathf.Infinity)) {
transform.position = new Vector2 (hit.point.x - deltaPos.x, hit.point.y - deltaPos.y);
}
}
}
I expected to drag the sphere regularly, but what happens is that the pointer goes outside the sphere collider when moving fast, therefore the circle stops moving.
I found this article, then I changed the void from Update() to FixedUpdate() but same result.
Try putting your physics code in FixedUpdate() function which is built for physics calculation. then if it's laggy, you can changeFixed Timestep in physics settings.
Fixed Timestep: A framerate-independent interval that dictates when physics calculations and FixedUpdate() events are performed.
https://docs.unity3d.com/Manual/class-TimeManager.html
EDIT
this code:
if (Physics.Raycast (ray, out hit, Mathf.Infinity))
checks if the raycast has hit something, therefore when the pointer goes out of the sphere there is nothing else to hit, so the if condition returns false and you cannot move it, to solve the problem add a big quad or plane as child to your camera and make sure it fills the camera view perfectly, and it's behind all your other scene elements.
you also can make a script that sets this plane for you.
EDIT 2
As another approach to solve the issue, you can use flags.
Add this to your camera, or edit it to your needs.
public class DragObjects : MonoBehaviour
{
Camera thisCamera;
private Transform DraggingObject;
bool DraggingFlag = false;
RaycastHit raycast;
Ray ray;
Vector3 deltaPosition;
void Start()
{
thisCamera = GetComponent<Camera>();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
ray = thisCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out raycast, Mathf.Infinity))
{
DraggingObject = raycast.collider.transform;
DraggingFlag = true;
deltaPosition = thisCamera.ScreenToWorldPoint (Input.mousePosition) - DraggingObject.position;
}
}
else if (Input.GetMouseButton(0))
{
if (DraggingFlag)
{
DraggingObject.position = new Vector3 (thisCamera.ScreenToWorldPoint (Input.mousePosition).x - deltaPosition.x, thisCamera.ScreenToWorldPoint (Input.mousePosition).y - deltaPosition.y, DraggingObject.position.z);
}
}
else if (Input.GetMouseButtonUp(0))
{
DraggingFlag = false;
}
}
}
Remember to cash your Camera.main in a variable at the start, because it is not performant and does this in the background:
GameObject.FindGameObjectsWithTag("MainCamera").GetComponent<Camera>();

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;
}
}
}

Click and object, then click the ground, make object move to that position

Hi there I'd like to be able to click on an object then click a position on a plane and would like my object to lerp to that mouse clicked position. The problem is doing this for more than one object becomes tricky. Anybody got any ideas? so far I have followed the tutorial on Coroutines on unity3D's website under the advanced scripting tutorials. here is the code:
attached to the game object:
private Vector3 target;
public float smoothing = 7f;
public Vector3 Target
{
get{return target;}
set
{
target = value;
StopCoroutine("Movement");
StartCoroutine("Movement",target);
}
}
IEnumerator Movement(Vector3 target)
{
while (Vector3.Distance(transform.position,target) > 0.05f)
{
transform.position = Vector3.Lerp(transform.position, target, smoothing* Time.deltaTime);
yield return null;
}
}
attached to the plane:
public propertiesandcoroutines coroutinescript;
private float Deltapos = 0.5f;
private GameObject collobj;
public void OnMouseDown()
{
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
Physics.Raycast (ray, out hit);
if (hit.collider.gameObject == gameObject)
{
coroutinescript.Target = new Vector3( hit.point.x,hit.point.y + Deltapos,hit.point.z);
}
}
this code works perfectly for one game object. how can I change this to work for a game object that I click on?
You just need to add a couple of lines to each script to get the result you want.
To the script attached to your moveable GameObjects
//This is the same type as the script attached to your plane. Rename it
//to whatever it's actually called (I've just called it PlaneScript). Also
//drag the plane into this field for each of the moveable GameObjects in the inspector
public PlaneScript planeScript;
//Paste this method anywhere inside the script attached to the GameObjects
void OnMouseUpAsButton () {
planeScript.SetObjectToMove(this);
}
Now, in the script attached to your plane, add the following
public void SetObjectToMove (propertiesandcoroutines script) {
coroutinescript = script;
}
How it works
Basically, what we're doing here is when one of your GameObjects are clicked, we reassign the "coroutinescript" variable in the script attached to the plane.
So, when the plane is clicked, the last GameObject that was clicked on before clicking the plane is moved.

Turn Sub-Object Code (raycast & mouse click & sub-objects)

Game characters are going somewhere that is clicked with the mouse
My problem : the code only works over a GameObject. I want to use one in the ground in the box, it can not.
I use a line of code :
public GameObject obj;
void Update() {
if(Input.GetMouseButton(0)) {
RaycastHit rayHit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (obj.collider.Raycast (ray, out rayHit, Mathf.Infinity)) {
transform.position = rayHit.point;
renderer.material.color = Color.green;
}
}
}
Map as the only model so I need to do. prevents me from making changes to my map
I need to call the individual sub-objects. but I could not.
Translating google translate :)
Try using Physics.Raycast(ray, out rayHit). This will raycast from your screen into the world. Then you can check the type of the object:
if (rayHit.collider.GetType() == typeof(YourTypeHere))
{
doSomething();
}