I’ve been attempting to make this function possible without using another mouse button, I want to save mouse buttons for other functionalities like throwing, adjusting distance, etc…
The problem with my script is that whenever I grab the object I cannot release it and it gets stuck forever, someone please tell me what’s wrong in my script and try fix it please? Thanks.
AKA: I want to use the same mouse button to grab an object and while it’s being held I can stop grabbing it by clicking the same mouse button (Left click)
Here’s my script:
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
//variables
private RaycastHit hit;
private GameObject GrabbedObject;
public Transform GrabbedPosition;
private void Update()
{
//Check if attempted object to grab is a rigidbody, is in range of the raycast and if it isn't being grabbed already, if all these are correct then proceed to enter grabbed mode
if(Input.GetMouseButtonDown(0) && Physics.Raycast(transform.position, transform.forward, out hit, 5) && hit.transform.GetComponent<Rigidbody>() && GrabbedObject == null)
{
//Object is activly being grabbed
GrabbedObject = hit.transform.gameObject;
}
if (GrabbedObject)
{
GrabbedObject.GetComponent<Rigidbody>().velocity = 5 * (GrabbedPosition.position - GrabbedObject.transform.position);
}
//If the object is activly being grabbed, then if player clicks it releases object
else if (Input.GetMouseButtonDown(0) && GrabbedObject)
{
GrabbedObject = null;
}
}
}
That’s the thing, I’m new to coding and Unity, could you give me an example code line of what isolating mouse clicks looks like? Thank you for the help!
bool clicked = false;
// read all input at once into a temp variable
if (Input.GetMouseButtonDown(0)) clicked = true;
// TODO: maybe read other inputs like game controllers here? also set clicked!
// now decide what to do:
if (clicked)
{
if (holdingObject)
{
releaseObject();
}
else
{
grabObject();
}
}
Alright uhhhh
I’ve tried my shot to do that but something is still wrong.
The object gets moved on the first click I do while playing and then it releases right after being clicked, and I cannot try grabbing any more objects after that…
Here’s my code, please tell me what’s wrong on it:
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
//variables
private bool holdingObject = false;
private bool clicked = false;
private RaycastHit hit;
private GameObject GrabbingObject;
public Transform GrabbedPosition;
private void Update()
{
//Check if user clicked
if (Input.GetMouseButtonDown(0)) clicked = true;
//Check if attempted object to grab is a rigidbody, is in range of the raycast and if it isn't being grabbed already, if all these are correct then proceed to enter grabbed mode
if (clicked && Physics.Raycast(transform.position, transform.forward, out hit, 5) && hit.transform.GetComponent<Rigidbody>() && GrabbingObject == null)
{
//Maybe this is the raycast hit?
GrabbingObject = hit.transform.gameObject;
if (GrabbingObject)
{
GrabbingObject.GetComponent<Rigidbody>().velocity = 5 * (GrabbedPosition.position - GrabbingObject.transform.position);
holdingObject = true;
}
//If the object is activly being grabbed, then if player clicks it releases object
else if (clicked && GrabbingObject && holdingObject)
{
GrabbingObject = null;
holdingObject = false;
}
}
}
}
I tried to make the changes I’ve made bigger but it didn’t work
Also, the GrabbingObject = null; is supposed to release the object, is that correct?
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
//variables
public bool holdingObject = false;
public bool clicked = false;
private RaycastHit hit;
private GameObject GrabbingObject;
public Transform GrabbedPosition;
private void Update()
{
//Check if user clicked
if (Input.GetMouseButtonDown(0)) clicked = true;
//Check if attempted object to grab is a rigidbody, is in range of the raycast and if it isn't being grabbed already, if all these are correct then proceed to enter grabbed mode
if (clicked && Physics.Raycast(transform.position, transform.forward, out hit, 5) && hit.transform.GetComponent<Rigidbody>())
{
//Assigns a variable of the grabbed object
GrabbingObject = hit.transform.gameObject;
//If the object is activly being grabbed, then if player clicks it releases object
if (holdingObject)
{
GrabbingObject = null;
}
//if the statement above isn't already being performed, then proceed to grab object
else
{
//"lock" object at the front of the player
GrabbingObject.GetComponent<Rigidbody>().velocity = 5 * (GrabbedPosition.position - GrabbingObject.transform.position);
holdingObject = true;
}
}
}
}
I’ve set the holdingObject and clicked to public to see what was wrong.
Turns out that these little tricky variables don’t turn back to false after the desired code is called. How can I turn them back to false after doing what they were supposed to?
Thanks a lot for the help you’ve been giving to me so far, I’m really grateful
//Check if user clicked
clicked = false;
if (Input.GetMouseButtonDown(0)) clicked = true;
By setting clicked to false first, and then checking if it should be true, it always defaults to false except in an Update cycle where the button is actually clicked. As long as that check is made after the variable is set to false, you should be good.
Again, look at my code. And I would make it a local variable, NOT a class variable, since it only has meaning during the function’s lifescope. See my original post, the one with the pseudocode.
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
//Variables
private RaycastHit hit;
public Transform GrabbedPosition;
public GameObject GrabbedObject;
void Grabbing()
{
//Variables
bool holdingObject = false;
bool clicked = false;
if (Input.GetMouseButtonDown(0)) clicked = true;
//Check if attempted object to grab is a rigidbody, is in range of the raycast and if it isn't being grabbed already, if all these are correct then proceed to enter grabbed mode
if (clicked && Physics.Raycast(transform.position, transform.forward, out hit, 5) && hit.transform.GetComponent<Rigidbody>())
{
//Assigns a variable of the grabbed object
GrabbedObject = hit.transform.gameObject;
//If the object is activly being grabbed, then if player clicks it releases object
if (holdingObject)
{
GrabbedObject = null;
}
else
{
GrabbedObject.GetComponent<Rigidbody>().velocity = 5 * (GrabbedPosition.position - GrabbedObject.transform.position);
holdingObject = true;
}
}
}
}
I tried to follow what you and the previous user said, unfortunately it didn’t work and my head is all dizzy…
Perhaps there’s something similar to Update Method but it doesn’t mess up the bool clicked part?
Okay, now we’re moving closer! The click-detection logic is now isolated and can largely be counted on to be working. Time to go deeper inside.
Now let’s look at some other logic on line 18, logic that doesn’t belong there (see my first code).
Keep the logic pure, one check per line:
The if (clicked) check is all you need (see my code).
NOW… we know you have clicked… we have to then decide:
are you holding and want to let go?, or
are you trying to pick something up?
If you’re holding, drop the the object. Is that fully accomplished by setting GrabbedObject to null? Wouldn’t you normally also have to unparent? So that’s one thing to look into. I usually use parenting. There’s lots of ways to do it though.
If you are NOT holding (eg, only in the case of the ELSE statement of the “if you are holding” question in the sentence above), then you need to ask a new series of questions:
are you pointing at something you can pick up?
does that thing have a rigidbody?
if so then pick it up
Some of The above things are in line 18, where they don’t belong.
See how it comes in layers? You don’t care if something has a rigidbody or can be picked up if you’re dropping stuff.
ALSO: why would you set the velocity in line 31? If something is picked up, it should be parented to your hand, typically, or some other long-term script would keep it AT your hand sort of “live,” eg track your hand. Not sure how you are holding onto stuff, but again, there’s lots of tutorials for that step.
@ImprobableDoge , First off let me tell you coding punishes your brain first, then rewards it when things click. So don’t worry. We’ve all been there. Stick with it and it will click at some point. You’re using the right classes and methods but I think you’re just missing a few key points about the flow of the logic.
I didn’t have time to set up everything to test this but I whipped up some pseudocode I think should work. I used a few different variable names on purpose so you can’t just copy paste it, I’d prefer you to go through the logic line by line and actually write the script yourself. I used comments to explain every line and together they make a little story.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
public GameObject grabbedObject; // we will need to remember what we picked up.
private void Update()
{
// if the player clicks..
if (Input.GetMouseButtonDown(0))
{
// ..and we already have an object in our hands..
if (grabbedObject != null)
{
// we drop it.
grabbedObject.transform.parent = null; // this sends it back to the top of the hierarchy. WE DO THIS FIRST.
grabbedObject = null; // this 'forgets' informs our GrabbingSystem our hands are empty. WE DO THIS LAST because after this, we can no longer affect the object.
}
// ..but if we don't..
else
{
// ..we do a raycast..
RaycastHit hit;
bool rayhit = Physics.Raycast(transform.position, transform.forward, out hit, 5);
// ..and if it hits...
if (rayhit)
{
// we remember our object.
grabbedObject = hit.transform.gameObject;
// and reparent it to ourselves
grabbedObject.transform.parent = this.transform;
}
}
}
}
}
You’re using the right classes and methods but your ‘story’ is a bit messy. I find it helps to comment your code, and look for logic flaws when things don’t work as expected. I have done programming in a few languages and to be honest Unity and C# are flexible, but give you enough rope to hang yourself. I made Unity crash 5 times today. You never stop learning!
Holy crap you wizard genious my brain couldn’t figure this all out if it weren’t you. I followed your advice and tried to make the “stories” the way you do, everything all correct. My intentions here were to make a grabbing system where the player clicks the object and it begins “floating” at the place where it was originally clicked, following the cursor. The raycast would be the distance between the player and the object and allow the player control the object to wherever they want.
I have once again tried to make the code like yours but try and make it based on my idea, but there is this one problem in both scripts where if I grab it and it colides and gets stuck in something the “focus point” changes dependently on the way I rotated/moved my player. If you don’t understood it well I can try giving another shot on explaining it as my english is not the best. Plus, in my script whenever I click an object it just grabs and releases quickly in a blink of an eye and I suspect that the issue might be in the line 18.
using UnityEngine;
public class GrabbingSystem : MonoBehaviour
{
//Variables
public Transform GrabbedPosition;
public GameObject GrabbedObject; //We will need to remember what we picked up
private void Update()
{
//if the player clicks..
if (Input.GetMouseButtonDown(0))
{
//and we already have an object in our hands..
if (GrabbedObject != null)
{
//we drop it.
GrabbedObject = null; //this informs our GrabbingSystem our hands are empty.
}
else
{
//we do a raycast..
RaycastHit hit;
bool rayHit = Physics.Raycast(transform.position, transform.forward, out hit, 5);
//and if it hits a rigidbody..
if (rayHit && hit.transform.GetComponent<Rigidbody>())
{
//we remember our object..
GrabbedObject = hit.transform.gameObject;
//and we grab it.
GrabbedObject.GetComponent<Rigidbody>().velocity = 5 * (GrabbedPosition.position - GrabbedObject.transform.position); //this should make the object in our "hands" in a smooth way
}
}
}
}
}
Loving the patience you guys have with me, never felt so special And indeed we never stop learning, based on this experience that is making my head all so dizzy I’ve learnt so much so far!
UPDATE: Thank you so much!!! unfortunately I was very newbie to this kind of stuff so I couldn’t some times understand some of these new words to my brain. But looking forward to come back here in the future when I get some more experience on coding!
Your patience was absurd to deal a guy like me, I once again stay very grateful
Ah, you didn’t think your misery would end now, would you?
With every win come new challenges. My script doesn’t take into account much more then your intentions. So yes, now you will have to think about how your code interacts with the environment, for example… how to manage rotations when grabbing and releasing something. As it happens I made an FPS prototype that does all of this last month. The idea was to make a “barfight” type of game where you grab pots and pans or pull a sword from the wall to defeat enemies, like improvised combat.
A lot more happens in that prototype: the object is reparented and rotated to the hand of my model depending on it’s type. Grabbing and releasing influence the Collider and RigidBody of each object, so they act like physics objects out in the world and just a hitbox when you grab them. How you proceed is off course dependent on the context of your game.
I used velocity to make it like if the object was floating based on the distance of the raycast and the player on the cursor.
Ah, I see what you are doing here. The “Bethesda drag and drop”. You want to push and pull physics objects. Oh boy. That’s a whole other topic. The issue with using the raycast is that you’d use a variable that changes dependent on the thing you’re moving to move it. So it is not the solution to the problem.
I would start to look into reparenting and get to grips with Quaternions and Euler Angles. Perhaps you could work with a local transform point inside the player / camera, such as “one meter in front” and then disable gravity on objects you’re grabbing, using “curated force calls” to the Physics engine to nudge them towards a position.
Can be done, but a quick cheat would be to turn the Rigidbody off entirely, make the Collider a trigger, have the object render a meter in front of the camera or so, and have it render on a seperate Camera so it can clip with other crap as much as it wants (I’ll render it on top of anything else anyway). My game needed to be snappy whereas dragging physics objects is more about the immersion factor. I would experiment with all these features until something clicks for your context.
The way you say it is very welcoming for begginers, isn’t it? My pants are already getting wet just by reading this oh boy…
Btw loved the bar fight idea lmfao
I’ll take your tips and advices as an act of kindness from Satan because I sure don’t understand a thing about all this new stuff. Looking forward to finish this project whatever it takes, because I sure will learn a lot with this new experience.
Thank you so much for your help and patience, learned a lot from this tiny little issue
We need that developer axiety to keep Hell’s factories online. The afterlife thanks you for your contribution.
It’s not as bad as it sounds, it’s just a whole other subject to sink your teeth in. I do have a useful tip: commit to never setting the velocity value on a Rigidbody directly, only getting it. Unity allows you to set it, but you should treat it as the result of all the physics forces affecting an object.
And thank you for your patience as well. Learning a game engine simply isn’t easy and it takes many small steps before you see results. Doing it at all is quite a feat of patience and persistance. Kudos for sticking with it