Hi, I’m trying to make a script which allows the player to drag the rigid body. My problem is that I don’t get the mouse position right.
using UnityEngine;
using System.Collections;
public class IfSelecting : MonoBehaviour {
private Ray ray;
private RaycastHit Hit;
private CollisionBool Bool;
private Vector3 move;
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButtonDown(0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray,out Hit) && !Hit.rigidbody.isKinematic)
{
move = new Vector3(Input.mousePosition.x,Input.mousePosition.y,0f);
Hit.rigidbody.freezeRotation = true;
Hit.rigidbody.MovePosition(Hit.rigidbody.position + move);
}
}
}
}
It is a very simple way to do it and I’ve tried using ScreenToWorldPoint but it did not help me or enlighten me in anyway.
If you have better ways to acquire this feel free to post some examples.
Thanks!
Edit: The game is restricted to x and y axis Therefore the z in move is 0.
3 Answers
3
Here is some additions to your code to implement a drag:
using UnityEngine;
using System.Collections;
public class Drag : MonoBehaviour {
//private CollisionBool Bool;
private Vector3 delta;
private Rigidbody rb;
private Transform trDrag;
private bool dragging = false;
private float zDist;
void Update (){
if (Input.GetMouseButtonDown(0)) {
Ray ray;
RaycastHit hit;
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray,out hit) && hit.rigidbody != null && !hit.rigidbody.isKinematic) {
dragging = true;
rb = hit.rigidbody;
trDrag = hit.collider.gameObject.transform;
delta = trDrag.position - hit.point;
zDist = Mathf.Abs (Camera.main.transform.position.z - hit.point.z);
rb.freezeRotation = true;
}
}
if (Input.GetMouseButton(0)) {
if (dragging) {
Vector3 v3Pos = new Vector3(Input.mousePosition.x, Input.mousePosition.y, zDist);
v3Pos = Camera.main.ScreenToWorldPoint(v3Pos);
rb.MovePosition(v3Pos + delta);
}
}
if (Input.GetMouseButtonUp(0)) {
dragging = false;
}
}
}
I believe your problem is where your vector calculation code is. Input.GetMouseButtonDown() returns true only in the frame the input is registered and no longer. Meaning: if I click, it will only fire in that one frame I happened to click during. After that, it will not return true anymore. Allow me to propose a modified script:
using UnityEngine;
using System.Collections;
public class Draggable : MonoBehaviour {
//How much does the difference in mouse position affect the drag?
//Public allows this value to be modified in the component list of a game
//object once affixed to it.
public float dragPower = 50;
private Ray ray;
private RaycastHit Hit;
private Rigidbody bodyToDrag;
private float distToBody;
private Vector3 moveDirection;
// Update is called once per frame
void Update ()
{
if (Input.GetMouseButton(0))
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
//Are we hitting a new object that isn't kinematic that we also
//don't already know about?
if (Physics.Raycast(ray,out Hit) && !Hit.rigidbody.isKinematic &&
bodyToMove == null)
{
//Make sure we know about the body we're dragging.
bodyToMove = Hit.rigidbody;
//Get the distance to it. This is used to make sure one of the
//3 axes of this and another point are the same later on,
//since the game is 2D. Better explained later.
distToBody = Vector3.Distance(bodyToMove.position, ray.origin);
Hit.rigidbody.freezeRotation = true;
}
if (bodyTomove != null)
{
//This gets the 3D point of the mouse,
//but with one of the axes being the same.
//Since the game is 2D, one of the axes must
//be equal on both points, or the object will be dragged in
//the 3rd dimension. This distance should ensure that.
//If it doesn't, add a comment to my post and I'll help
//you make sure of it.
Vector3 currentMousePos = ray.GetPoint(distToBody);
//Gets the direction we want to drag the body,
//including a small magnitude.
moveDirection = currentMousePos - bodyToMove.position;
//Adds force in the move direction. Since the included
//magnitude is too small for any meaningful change in
//position, we multiply that magnitude with a
//configurable power.
bodyToMove.AddForce(moveDirection * dragPower);
}
}
else
{
bodyToMove = null;
}
}
}
This should enable any object to be dragged once attached to any game object. This is untested, so if you have problems or want to restrict dragging to a single object or group of objects, comment on this answer and I’ll help.
robertbu’s code works excellently moving the objects around, I just added things for rotation freezing and unfreezing correctly as well as isKinematic to avoid the objects gaining falling momentum as you hold them.
However, when dragging an object it ignores collision with the walls and the terrain in my scene. Which is really weird since the dragged object collides with other similar objects and the wall are constructed the exact same way using colliders and even rigidbodys.
The same problem occurs when using IR Nifty’s code example so I’m wondering if the manual moving of object could override the physics or something along those lines.
Any thoughts on this?
Well the objects (which are cubes, triangles and towershaped figures) Collide with the walls and terrain when I'm not dragging them. Also the standard unity asset dragrigidbody.js does not have this problem (it has others though). I have tried comparing the two but I can't seem to find anything that would be the cause. The only thing I could think of is some kind of pointing problem since a private rigidbody and transform is used but since it's c# there should be no such problems.
– XIVMohawkIt could be possible that freezing the rotation causes collision instabilities. Try not freezing the rigid body.
– IR_NiftyIt did not solve anything but when letting them rotate they react to the wall, but as I drag the mouse across it they just jump to my mouse (obviously). Still does not explain why they do with the Nifty solution though. The reason Why the standard js script works is because it traces the ray constantly so when the ray hits the wall the block do not jump through the wall. I'll probably control it using OnCollisionEnter.
– XIVMohawkThe problem might be that the force is too much on my script. Try setting it to 1 and slowly increasing it. Also, I may have mistaken how you want the system to work. Do you want the object to stay with the mouse, as if you were moving a Windows window around? Or do you want it to act as if it has a spring attached to it?
– IR_Nifty