- Home /
How to block dragging if collider hits
Hello,
I've been searching for a method to restrict a mouse drag when it collides with another object without using a RigidBody and everything I tried resulted in failure (the block I'm dragging goes straight through the others). I tried with OnCollisionEnter and with a Raycast and both aren't working... my brain is about to explode. (T_T)
Also, what is the lightest method to do this kind of thing on iPhone ?
Thank you very much.
Phil
Answer by aldonaletto · Jul 28, 2011 at 01:58 AM
If the objects you want to drag can be rigidbodies, move them by setting the velocity, not the position - it allows the object to respect collisions.
The script below picks a rigidbody when the left mouse button is pressed, and drags it while the button is pressed. Instead of setting the object position, the script calculates the difference between mouse and object positions, and apply a proportional velocity to the object. Velocity is limited to maxSpeed to avoid the object to pass through thin objects. speed is a speed factor which controls how fast the rigidbody will follow the mouse pointer.
var speed: float = 5; // speed factor var maxSpeed: float = 15; // speed limit private var dragObj: Transform = null; private var hit: RaycastHit; private var length: float;
function Update(){
if (Input.GetMouseButton(0)){ // if left mouse button pressed...
// cast a ray from the mouse pointer
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (!dragObj ){ // if nothing picked yet...
// and the ray hit some rigidbody...
if (Physics.Raycast(ray, hit) && hit.rigidbody){
dragObj = hit.transform; // save picked object's transform
length = hit.distance; // get "distance from the mouse pointer"
}
}
else { // if some object was picked...
// calc velocity necessary to follow the mouse pointer
var vel = (ray.GetPoint(length) - dragObj.position) * speed;
// limit max velocity to avoid pass through objects
if (vel.magnitude > maxSpeed) vel *= maxSpeed / vel.magnitude;
// set object velocity
dragObj.rigidbody.velocity = vel;
}
}
else { // no mouse button pressed
dragObj = null; // dragObj free to drag another object
}
}
EDITED: This is a CharacterController version. It uses no gravity, and the objects stay at the position you release them.
var speed: float = 10; // speed private var dragObj: Transform = null; private var hit: RaycastHit; private var length: float; private var character: CharacterController;
function Update(){
if (Input.GetMouseButton(0)){ // if left mouse button pressed...
// cast a ray from the mouse pointer
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (!dragObj ){ // if nothing picked yet...
// and the ray hit some character...
if (Physics.Raycast(ray, hit)){
character = hit.transform.GetComponent(CharacterController);
if (character){
dragObj = hit.transform; // save picked object's transform
length = hit.distance; // get "distance from the mouse pointer"
}
}
}
else { // if some object was picked...
// calc mouse pointer displacement
var mov = ray.GetPoint(length) - dragObj.position;
// set object velocity
character.Move(mov * speed * Time.deltaTime);
}
}
else { // no mouse button pressed
dragObj = null; // dragObj free to drag another object
}
}
Thank you very much for your answer!! :) Is this kind of behavior possible without using any RigidBodies or it HAS TO go through with it ? I'm using BoxColliders everywhere and there is no use of physics whatsoever. It's a block puzzle game. :) Can I target a collider ins$$anonymous$$d ?
You can use the CharacterController ins$$anonymous$$d of a rigidbody. It uses no physics, but recognizes colliders. If your game is 2D, it must run on the XZ plane, since the CharacterController supposes Y is the vertical direction. Just add the CharacterController and it will substitute the collider. I edited my answer to include a CharacterController version.
Aww... crap. $$anonymous$$y game is 2D indeed and runs on the XY plane. I'll try to figure a way around that... I'll tell you if I succeed. Thanks.
Well, I tried the second solution on a brand new scene to test on the XZ plane and when I click/drag the block, it doesn't move at all. Wouldn't ray casting and measuring distance be a good way to do it ? EDIT: Isn't it what you are doing ? :)
$$anonymous$$y initial logic was to do something like this: On$$anonymous$$ouseDown $$anonymous$$esure the Length of Starting point and Collision Point (on both left and right since my game slides blocks only horizontally) then clamp the $$anonymous$$in / $$anonymous$$ax values. I succeeded on clamping with my play field so far but don't have any clue on how to accurately measure the distance of the Raycast until it collides (an do it maybe just once at the beginning to make sure the clamp is precise ?).
Do you think this would be a good way to do it ?
EDIT: I'll try with the RigidBody and lock all position / rotation then destroy the RigidBody once the object is in place.
SECOND EDIT: Your first script works great with 3D cubes but doesn't work well with 2D sprites. $$anonymous$$y sprites are all having BoxColliders. Also, like I said previously, I succeeded into restricting the blocks' movement by clamping an X value (X values of the playfield). I think my problem is different than my question... Thanks for helping me! :)
How can I make it to multi touch script ? so different fingers will drag different object.
Your answer
Follow this Question
Related Questions
Bomberman like explosion 0 Answers
Accessing colliders, in if statement 2 Answers
How do I register damage from the actual sword? not Raycast 1 Answer
Click&Drag Misterious Disappearing! 1 Answer
Trouble with RayCast, rigid body and the colliders tag 0 Answers