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:

[15856-screen+shot+2013-09-26+at+11.42.38.png|15856]

Would appreciate any advice I can get on this. Thanks.

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