- Home /
Pick up an item with colliders, using C#
I've been looking around trying to find a tutorial that utilizes C# for a script that allows me to pick up items with collision. Possibly a button press such as "e" or similar.
I know how to set up the colliders on the objects and such, I just don't know where to begin with the scripting part where I can walk over the item and have it disappear and enable an item I already have disabled in the background for use.
Answer by Xtro · Aug 07, 2013 at 07:15 PM
1) Pickup colliders must be Trigger so you can walk over.
2) Write a script on the character to handle the OnTriggerEnter event.
3) In this event, store the pickup trigger object into a variable (Which is reachable from keyboard control script)
4) In keyboard control script (maybe a global function or maybe in character script) try to detect if "E" key is down
5) if E is down, you have the object you want to interact in the variable set from the step 3.
Something like this might work?
using UnityEngine;
using System.Collections;
public class Example : $$anonymous$$onoBehaviour {
void OnTriggerEnter(Collider other) {
Destroy(other.gameObject);
}
}
Yes but this destroys the pickup object immediately when you walk over it. I think you wanted to have a keyboard action "E".
Another tip : adding a Rigidbody with Is$$anonymous$$inematic=true to the pickup object will help you on performance tuning. Colliders without rigidbodies are static. Static colliders aren't supposed to move or be destroyed because this will cause a recalculation of static colliders in the scene. So we want to make the pickup objects as dynamic by adding a $$anonymous$$inematic Rigidbody.
So this is the code I have, and it's not working as planned.
I got it to where I can walk over the item and make it dissappear, but now I want to use the keycode "e" as you suggested.
using UnityEngine;
using System.Collections;
public class pickupItem : $$anonymous$$onoBehaviour {
void OnTriggerEnter(Collider other) {
if(Input.Get$$anonymous$$eyDown($$anonymous$$eyCode.E))
{
Destroy(other.gameObject);
}
}
}
Dude you can't do this :) Walking over and Pressing the E key are different events. You can't combine them like this.
You should have a global variable named something like "WalkedOverObject". If it's null, character is not on a pickup object. If it has an object stored in it, then character are standing on a pickup object.
In OnTriggerEnter and OnTriggerExit event, you have set this global variable. On enter, set it to other.gameObject. On exit, set it to null.
Ok this was part one...
In part two, You have to detect the E key pressed in another script. It may be in a global keyboard script or you may want to do it in your character control script.
When you detect the E key, you see that user pressed the E key. After that, you can check the global WalkedOverObject to see if we are standing on a pickup object. If it's null, do nothing, if it has an object in it, then do pickup (destroy).
What happens in your code is that... you have to walkover the object and press the E key AT THE SA$$anonymous$$E $$anonymous$$iliseconds :) If you fail to do that, it won't pickup the object. Did you get what's wrong with your code ?
Please don't feel like idiot.
Here is the code for triggers...
void OnTriggerEnter(Collider other) {
WalkedOverObject = other.gameObject;
}
void OnTriggerExit(Collider other) {
if (WalkedOverObject == this.gameObject) WalkedOverObject = null;
}
Since WalkedOverObject is a global variable, every pickup object tries to write itself into that variable when walkover. But it nullifies the global variable if only the variable equals itself.
After storing the walkedover object(or nullifying), you can use WalkedOverObject in keydown check in the other script (maybe the character controller script)
Walking over and $$anonymous$$eydown are seperate events. Triggers in pickupItem handle the walking over event. $$anonymous$$eydown check in character controller script handles the $$anonymous$$eydown event if WalkedOverObject isn't null.
I hope I could explain my self.
Answer by moqam · Jun 10, 2020 at 02:24 AM
For anyone in 2020 trying to implement this into their game this works. I didn't have to add any reference to the player controller only the input button. This was attached to my object for pickup.
void OnTriggerStay(Collider other) // If ammo object collides with any collider... {
if ((other.gameObject.tag == "Player") && (Input.GetButton("Pickup")
it's 2021 while I write this, and while your answer didn't apply to my project, I had no idea about the difference between OnTriggerEnter and OnTriggerStay, not even about the existence of the latter.
With OnTriggerEnter it was just not registering the key. OnTriggerStay is what I was missing in order to implement picking up with a button while colliding. Thank you!
OnTriggerStay
is called every frame the objects are colliding, where as OnTriggerEnter
is only called the first frame of collision. In this case, the developer is using OnTriggerStay
in conjunction with the Input system in order to check if the player has pressed the "Pickup" button.
Pros: Its quicker and easier to develop this way. Cons: Its spaghetti code. The player Input is now in a class that has nothing to do with the player itself, so it gets harder to debug and fix.
Alternative solution: Give the player some kind of context based interface, and when the player clicks the "Use" or "Pickup" button, it calls a method on that context item.
public interface IContextItem
{
void Use(Player player);
}
public class Door : MonoBehavior, IContextItem
{
bool isOpen = false;
public void Use(Player player)
{
isOpen = !isOpen;
//Play appropriate animation, change states etc...
}
}
Then in the trigger object, you just pass that IContextItem to the player.
void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
Player p = other.GetComponent<Player>();
//For this example, Player.contextItem is of type 'IContextItem'.
p.contextItem = GetComponent<Door>();
}
}
And then in Player:
if(!contextItem.Equals(null) && Input.GetButtonDown("Use))
{
contextItem.Use(this);
}
You don't necessarily have to use an interface, you could use an abstract class. You would probably have to do some complex workings to clear the context item on use or keep track of which item the player has context over so he isn't able to use the door after he walks away, but you get the general idea.
Answer by CameronF305 · Nov 12, 2015 at 04:23 PM
@klown use this script-
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour {
public float speed;
private Rigidbody rb;
void Start ()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate ()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0.0f, moveVertical);
rb.AddForce (movement * speed);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
}
}
}
Your answer
Follow this Question
Related Questions
keep collider disabled even when the player re-enter the scene 1 Answer
How to disable collision detection while a UI Panel is enabled 2 Answers
I need to puck up object using a key, but something is wrong with code 1 Answer
Collider.enabled working differently from inspector? 1 Answer
Terrain collision problem 1 Answer