8
\$\begingroup\$

I bring yet-another-drag-with-mouse question (I am using Unity with C#), but with a less common particular detail: the existence of obstacles in the middle of the way trough which dragging occurs (3D space, not 2D).

Let me explain. Suppose I have a plane over which I want to drag a cube called "obj" .That's easy. Here is my simple implementation for that:

void Update () {
  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  RaycastHit hit;
  if(Physics.Raycast(ray, out hit, 1000000))
  obj.transform.position = new Vector3(hit.point.x,0.25F,hit.point.z);
}

It works. However, suppose that I also have a few other cubes over the plane, which are the obstacles. Obviously, when the player moves "obj" over the plane, such movement should be blocked by the obstacles. And then, while colliding with the obstacles, "obj" should move only snipped to the sides of that obstacle. If mouse is moved and "obj" stops colliding with obstacles, free dragging-style movement resumes again.

object being dragged toward an obstacle and stopping at its edge, then resuming when drag passes the obstacle

To make the challenge harder, I am trying hard to achieve that without the use of RigidBody components at the obstacles (the dragged object can have it). Any ideas on what is the most efficient way of achieving that? Many thanks!

EDIT: Commentators have brought to my attention that I should mention that objects are allowed to rotate when snapping.

EDIT 2: Considering the difficulty of the original formulation, I changed the question allowing the use of Rigidbody components at the dragged objects. The solution just can not use Rigidbody components at the obstacles.

\$\endgroup\$
  • \$\begingroup\$ Are you moving arbitrary convex shapes - are they always four sided? Are they always 2D? \$\endgroup\$ – Steven Oct 6 '15 at 15:02
  • \$\begingroup\$ May I know the reason why you won't use Rigidbodies? They're the easiest way to do what you want to without having to reimplement code already available in Unity. \$\endgroup\$ – EvilTak Oct 6 '15 at 15:44
  • \$\begingroup\$ @EvilTak I rather learn how to deal with the geometry involved in the task and due to performance reasons, I don't like to use Rigidbodies unless it is really really unavoidable. In this particular case, I will have many thousands of objects behaving as obstacles \$\endgroup\$ – MAnd Oct 6 '15 at 18:52
  • \$\begingroup\$ Btw, thanks to @Anko (or to whoever did it) for including that animated image to illustrate the problem! I was still thinking of the best way to do so. \$\endgroup\$ – MAnd Oct 6 '15 at 19:00
  • 1
    \$\begingroup\$ @Steven and EvilTak: the object may be allowed to rotate, the obstacles should not. Usual ways of detecting collision seem to be not enough: the main object keeps getting inside the objects. \$\endgroup\$ – MAnd Oct 7 '15 at 3:04
2
\$\begingroup\$

It's difficult to detect collision without any rigidbodies involved, but since you're using cubes you may be able to use Bounds.Intersects. Each update, check if the dragged object's bounds intersect with any obstacles' bounds. If it does, then you could try this:

  1. Disable the Mesh Renderer for the dragged object to make it invisible (but continue to drag it).
  2. Drop a visible, placeholder object identical to the dragged one at the last position before bounds intersection (now it looks like the object stopped, but really you are still dragging the original).
  3. Each update, check to see if the bounds of the object you're still dragging intersect with an obstacle's bounds.
  4. When the dragged object's bounds no longer intersect with an obstacle's, delete/deactivate the placeholder object and re-enable the Mesh Renderer for the dragged object to make it visible again.

You never stop dragging the block; it simply appears to the user that the block has stopped dragging while it would intersect with an obstacle.

\$\endgroup\$
  • \$\begingroup\$ Based on previous comments and on your reply, I edited the question to make it easier to accomplish: let's now say that Rigidbody could be used for the draggable object or its placeholders. Rigidbody just could not be used for the obstacles. \$\endgroup\$ – MAnd Oct 19 '15 at 16:25
1
\$\begingroup\$

Without having done it myself, here's what I'd try:

  1. Decide how high some obstacle on the plane has to be in order to block your dragged object (where "high" means removed along whichever axis is appropriate—I'd assume the one that points toward the camera).
  2. Each update, save the position of your raycast hit.
  3. Each update, before saving the position of the current raycast hit, check the position of the current raycast hit against the position of the previous raycast hit.
  4. If the difference >= blocking height, stop your moving object at the previous raycast hit position.

It seems to me that if you'd like your object to drag along a slanted plane of an obstacle, you should simply have its transform continue to follow the position of the latest raycast hit.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer, @Evan. However, that solution wouldn't be accurate. Suppose the RayCast would be fired from the center of the draggable object's bounding box. What if the obstacle in the way block only a part of the draggable object that is to the left or right of the ray cast? Even if we increase the number of rays cast (what can get exponentially high if the draggable object can be dragged in 360º directions in the X,Z dimensions), depending on how small the obstacle is in relation to the draggable object, it could still be in-between rays cast - and therefore wouldn't be detected \$\endgroup\$ – MAnd Oct 14 '15 at 18:27
  • \$\begingroup\$ Alright, I think I see what you mean. \$\endgroup\$ – Evan Oct 19 '15 at 15:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.