Hi
I’ve implemented a script which allows me to grab objects. But when i hit something with the object i’m holding, its propulsing me in the opposite direction. How can i fix this ?
Is there a way to diseable the physics of the object i’m holding ?
Should i just drop the object i’m holding in case of collision ?
I’m getting stuck here. Help !
here is my code so far :
using UnityEngine;
using System.Collections;
public class GrabAndDrop : MonoBehaviour {
GameObject grabbedObject;
float grabbedObjectSize;
// Use this for initialization
void Start () {
}
GameObject GetMouseHoverObject(float range){
Vector3 position = transform.position;
RaycastHit raycastHit;
Vector3 target = position + Camera.main.transform.forward * range;
if (Physics.Linecast (position, target, out raycastHit)) {
return raycastHit.collider.gameObject;
} else
return null;
}
void TryGrabObject(GameObject grabObject){
if (grabObject == null || !CanGrab(grabObject))
return;
grabbedObject = grabObject;
grabbedObjectSize = grabObject.GetComponent<Collider> ().bounds.size.magnitude;
}
void DropObject()
{
if (grabbedObject == null)
return;
if (grabbedObject.GetComponent<Rigidbody> () != null)
grabbedObject.GetComponent<Rigidbody> ().velocity = Vector3.zero;
grabbedObject = null;
}
bool CanGrab(GameObject candidate){
return candidate.GetComponent<Rigidbody> () != null;
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.E)) {
if (grabbedObject == null)
TryGrabObject (GetMouseHoverObject (5));
else
DropObject ();
}
if(grabbedObject != null){
Vector3 newposition = transform.position + Camera.main.transform.forward*grabbedObjectSize/2;
grabbedObject.transform.position = newposition;
}
}
}
Switching the object you’re holding to kinematic will stop physics from being calculated on it.
It works fine now, exept that my grabbed object is now able to pass throught other object, like wall. I can drop it under the ground per examble, which is very problematic.
It works fine when i hit a rigidbody, but if the object i hit is not a rigidbody, the collide box is not working
How can i fix that ?
instead of turning on iskinmatic you could try turning off use gravity. just a guess but it might work
Earlier I talked about some optimizations, but after reading through your code again, I realize that there is a chance that don’t apply in your case. The reason for this is that you apparently want to allow the player to pick up every object that has a rigidbody.
Two simple questions:
Will there be a lot of them?
Are the objects currently in the default layer?
There is only 3 identicals objects i want to grab in my game. In the first place i wanted to create a tag for grabable object but since you can only put one tag on a single object, i chose a easyer solution.
“Are the objects currently in the default layer?” I’m afraid i don’t understand this question : p
I see. What you should have used is layers.
Under Edit/Project Settings/Tags & Layers choose layers and add a layer like “Grabbable” or something.
Then set those objects you can pick up to that layer. You can find the setting right next to the tag, underneath their names.
Layers have various powerful uses. The first one is that you can use the layer collision matrix (Edit/Project Settings/Physics), which let’s you define which layers collide with each other. Say you don’t want that grabbable objects collide with each other, because the player could abuse this to stack them and jump out of your level.
You simply untick the checkbox “Grabbable - Grabbable” and they won’t collide with each other anymore.
Another one is when using ray-/sphere/…-casts. You can use layer masks to define what layers your ray-/sphere/…-casts collide with. Say your “Grabbable” layer is layer number 8 (in the list where you created it).
// This collides with everything, grabbable or not
Physics.Linecast (position, target, out raycastHit))
// This ONLY collides with objects on layer 8.
// Your level and objects that cannot be grabbed don't exist for your Linecast
Physics.Linecast (position, target, out raycastHit, 1 << 8))
The difference is that now you know that your Linecast will either hit an object that you can definitively pick up, or nothing. This means that you can now safely merge some funtions and remove CanGrab(), because as soon as »something« is hit, it is guaranteed to be grabbable.
Quickly written prototype
using UnityEngine;
using System.Collections;
public class GrabAndDrop : MonoBehaviour {
private Transform transform;
private Rigidbody grabbedBody;
private void Awake() {
transfrom = GetComponent<Transform>();
}
private void TryGrabObject() {
Vector3 position = transform.position;
RaycastHit raycastHit;
Vector3 target = position + Camera.main.transform.forward * range;
if (Physics.Linecast(position, target, out raycastHit, 1 << 8)) {
grabbedBody = raycastHit.collider.gameobject.GetComponent<Rigidbody>();
}
}
private void DropObject() {
grabbedBody.velocity = Vector3.zero;
grabbedBody.angularVelocity = Vector3.zero;
grabbedBody = null;
}
private void Update() {
if (Input.GetKeyDown(KeyCode.E)) {
if (!grabbedBody) {
TryGrabObject();
}
else {
DropObject();
}
}
else {
// Move the object with my algorithm from earlier
}
}
}
I don’t guarantee that I haven’t made any mistake because I did not test this code.
1 Like
Thanks a billion time for this lesson
Oh man that line cracked me up - sorry to go off topic but very humorous autocorrect there. What to do about all those 3d racists! Hahaha mannn.
1 Like
Whoa.
SwiftKey, what the fuck?