- Home /
Push/Pull Physics - Cube
Hello,
I have a tower of cubes, and I can click on a cube to select it with the mouse.
What I want to achieve now is to be able to push and pull that selected cube with my mouse (as if my mouse is a hand, pushing or pulling the cube to or from).
So if I move the mouse in the same cube axis of Z, then the cube will move perfectly on its Z axis. But if I were to move the mouse slightly out of the Z axis, then the cube will rotate on the Y.
Basically, Like a 3D Jenga game. You select a cube, and you can push/pull a cube. If the mouse is pulling/pushing on exactly the same axis as the cube, it will pull/push it straight out with ease. But if you move the mouse slightly off track, you risk rotating the cube slightly (on the Y axis in this example).
I don't really know where to start with this as it's converting 2D mouse position to 3D. All I'm doing right now is applying movement on the selected Cube:
currentSelected.rigidbody.MovePosition(currentSelected.rigidbody.position + speed * Time.deltaTime);
But I guess I will need to use this:
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
var hit : RaycastHit;
if (Physics.Raycast (ray, hit, Mathf.Infinity)){
Debug.DrawLine (ray.origin, hit.point, Color.blue, 1);
And somehow use the hit.point of the cube to apply movement on the axis the mouse is moving to/from:
Would appreciate any advice I can get on this. Thanks.
Did you already think about using the hit.normal for pushing and pulling the cube? Then you could calculate an angle from the mouse world position to that normal on the y-level for the rotation.
Could you explain a bit more? I don't know a great deal of the maths/transform side of Unity
Answer by robertbu · Sep 26, 2013 at 05:07 PM
There are two issues here. The first is determining the direction of movement. The second is translating 2D mouse movements into 3D movements in space. For the direction, I suggest your movement should be relative to the face of the block you click on. For translating the 2D movement into 3D movement I suggest (conceptually) moving the mouse along a plane parallel to the camera face. Whatever movement of the mouse aligns with the direction of the block is what is used.
Here is a bit of source code. Start an empty scene, add a block named "Block", and add this script to an empty game object. Rotate the block or the camera and then drag the block around.
The code is a bit complex. It is written for arbitrary placement of the blocks and the camera. With constraints, it could be simplified. It is also just proof of concept. You are likely dealing with Rigidbodies and will want to use Rigidbody.MovePosition() as well as make other changes:
#pragma strict
private var target : Transform;
private var dir : Vector3;
private var isDragging = false;
private var startPoint : Vector3;
private var startPosition : Vector3;
private var planeDist : float;
function Update() {
var hit : RaycastHit;
var ray : Ray;
if (Input.GetMouseButtonDown(0)) {
Debug.Log("Here");
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, hit) && hit.collider.name == "Block") {
target = hit.transform;
dir = WhichSide(target, hit.point);
isDragging = true;
planeDist = Mathf.Abs(Vector3.Dot(-Camera.main.transform.forward, (Camera.main.transform.position - hit.point)));
startPoint = hit.point;
startPosition = target.position;
}
}
if (isDragging) {
var pos = Input.mousePosition;
pos.z = planeDist;
pos = Camera.main.ScreenToWorldPoint(pos);
var delta = pos - startPosition;
var movement = delta.magnitude * Vector3.Dot(delta.normalized, dir) * dir;
target.position = startPosition + movement;
}
if (Input.GetMouseButtonUp(0))
isDragging = false;
}
function WhichSide(tr : Transform, hitPoint : Vector3) : Vector3 {
var v3 = (hitPoint - tr.position).normalized;
var v3Ret = tr.forward;
var dot = Vector3.Dot(v3, tr.forward);
var f = Vector3.Dot(v3, -tr.forward);
if (f > dot) {
dot = f;
v3Ret = -tr.forward;
}
f = Vector3.Dot(v3, tr.right);
if (f > dot) {
dot = f;
v3Ret = tr.right;
}
f = Vector3.Dot(v3, -tr.right);
if (f > dot) {
dot = f;
v3Ret = -tr.right;
}
f = Vector3.Dot(v3, tr.up);
if (f > dot) {
dot = f;
v3Ret = tr.up;
}
f = Vector3.Dot(v3, -tr.up);
if (f > dot) {
dot = f;
v3Ret = -tr.up;
}
return v3Ret;
}
Wow, okay - this is crazy helpful. I'll have to try it tomorrow, will let you know how I get on. Thanks Robert.
This works really well, the only issue is that when I click/tap on a cube, the centre point of the cube will 'snap' to the mouse position. Is there a way to that when I begin to drag, the cube will move? Thanks again!
Ah, I figured it out, just needed to replace this:
var delta = pos - startPosition;
With this:
var delta = pos - startPoint;
Good catch. I cleaned the code up right before I posted it and obviously introduced a problem.
Your answer
Follow this Question
Related Questions
Pulling objects 2 Answers
Cube collision problems when held 0 Answers
Amnesia like objects, in unity. 2 Answers
adding Up force 0 Answers
Pushing and Pulling an Object. 1 Answer