How do I stop my objects from going through walls when I pick them up and drop them down? - unity3d

When I pick an object up I can glitch it through the map making it fall out of the world. This happens when I pick it up and drop the object half way through the floor. The outcome I receive is not what I was expecting what can I do to fix this. Also yes the colliders and rigidbody's are setup correctly.
public GameObject PressEtoInteractText;
public bool pickup, inrange;
public Collider Playercol;
public Vector3 guide;
private GameObject temp;
private Rigidbody rb;
void Update()
{
if (Input.GetKeyDown(KeyCode.E) && inrange == true)
{
PressEtoInteractText.SetActive(false);
pickup = true;
}
if (Input.GetMouseButtonDown(0) && pickup == true)
{
pickup = false;
Playercol.isTrigger = true;
}
UpdatePickUpFollow();
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "Interact")
{
PressEtoInteractText.SetActive(true);
temp = other.gameObject;
inrange = true;
}
if (other.gameObject.tag == "Interact" && temp.transform.position == guide)
{
return;
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.name != "Interact")
{
PressEtoInteractText.SetActive(false);
inrange = false;
}
}
public void PickUp()
{
rb = temp.GetComponent<Rigidbody>();
rb.MovePosition(transform.position += guide);
Playercol.isTrigger = false;
}
public void UpdatePickUpFollow()
{
if (pickup == true)
{
PickUp();
}
}

If you deactivate the objects collider with tempCol.enabled = false; it will not register any collisions and you can just push or pull it through walls all day. Make sure to remove that from your script.
Also, using MoveTowards can cause issues with collision detection. In my experience it is best to use AddForce or MovePosition to move the Rigidbody component instead of modifying the Transform directly. Try Rigidbody.MovePosition(Vector3 position). Maybe this works better for you.
Here is a link to the documentation page. It's basically your exact use case:
Rigidbody.MoveTowards Unity Docs
(Hint: notice how they use FixedUpdate instead of regular Update. You should also always do this when working with Rigidbodies because it is synced with physics updates.)
//Edit:
This is a little implementation of your code in a cleaner and hopefully correct way. I have not tested this and there is propably something I missed. Use this as a reference to build your own working solution.
//set in inspector
public Transform guidePosition;
public GameObject pressEToInteractText;
private bool isObjectInRange;
private GameObject inRangeObject;
private bool isObjectPickedUp;
private Rigidbody pickedUpRigidBody;
/* check if button is pressed.
* If no object is in hand -> pick up;
* if object is in hand -> drop;
*/
private void FixedUpdate()
{
if (Input.GetKeyDown(KeyCode.E) && isObjectInRange && !isObjectPickedUp)
{
PickupObject();
}
if(Input.GetKeyDown(KeyCode.E) && isObjectPickedUp)
{
DropObject();
}
if (isObjectPickedUp)
{
PickedUpObjectFollow();
}
}
//save references
private void PickupObject()
{
pickedUpRigidBody = inRangeObject.GetComponent<Rigidbody>();
isObjectPickedUp = true;
}
//remove saved references
private void DropObject()
{
isObjectPickedUp = false;
pickedUpRigidBody = null;
}
//move position to guidePosition
private void PickedUpObjectFollow()
{
pickedUpRigidBody.MovePosition(guidePosition.position);
}
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Interact") && !isObjectPickedUp)
{
pressEToInteractText.SetActive(true);
isObjectInRange = true;
inRangeObject = other.gameObject;
}
}
private void OnTriggerExit(Collider other)
{
if(other.CompareTag("Interact") && other.gameObject == inRangeObject)
{
pressEToInteractText.SetActive(false);
isObjectInRange = false;
inRangeObject = null;
}
}

You could do multiple things. Unfortunately the way VR tracks the hands and there is no way to stop ur hands in real life your hand will defy the physics in the application.
I would either make the item drop from the users hand when it gets close enough to a certain area that you dont want it going through.
Or you can make it that if it does pass through a space you can report the item right above the floor it went through.
Ive looked long and hard for an answer to this and it doesnt seem like it can at this point be blocked from moving through if its currently grabbed.

Related

Why is this Projectile Script Continuing to Hit Targets After I've Destroyed It?

I am new to Unity2D. I am trying to make castle defense game. When the spawners start to inheritance the enemies overlap (they should), but when the archer arrow collides whit the enemies it kills them all. I searched everywhere for the answer of this but nothing...
My questions is:
Is there a way to only hit one target at time?
Arrow script:
void Start()
{
target = GameObject.FindGameObjectWithTag("Enemy").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speedProjectile * Time.deltaTime);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("Enemy"))
{
Destroy(gameObject);
}
}
Enemy script:
void Start()
{
target = GameObject.FindGameObjectWithTag("target3").GetComponent<Transform>();
}
// Update is called once per frame
void Update()
{
transform.position = Vector2.MoveTowards(transform.position, target.position, speed * Time.deltaTime);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (col.gameObject.CompareTag("arrow"))
{
EHealth -= HDamage;
}
if (EHealth <= 0)
{
Destroy(gameObject);
}
Your enemies are all taking damage because destroying a GameObject isn't something that happens immediately (for good reason). Because of this, in a single frame, any number of enemies can be hit by the same arrow.
If you'd like to rely on these collision methods, I'd suggest controlling the damage from the arrow instead of from the enemy, so you can be sure it only hits something once:
private bool dealtDamage = false;
private void OnTriggerEnter2D(Collider2D col) {
// Only deal damage once
if (dealtDamage) {
return;
}
// Does the thing I hit have this "EnemyScript" ?
var enemy = col.gameObject.GetComponentInChildren<EnemyScript>();
if (enemy == null) {
return;
}
// Make this "DealDamage()" method public on your EnemyScript
enemy.DealDamage();
dealtDamage = true;
Destroy(gameObject);
}
Then get rid of the Enemy Script's OnTriggerEnter2D because the arrow is handling it all. I don't know what the name of the script is on your enemies so I just called it EnemyScript. This is also calling a DealDamage() method that you'd have to make (which would probably look a lot like the one you current have listed in your "Enemy Script.")
its hard to say with the information given, based on what you have said it seems that all the entity's are just 1 entity(so when you kill 1 enemy you kill the only enemy which is all of them). you can have them run independently from each other.
Maybe you can use collision enter function to check bullet is hitting enemy's body.
You can use this code below...
private bool isEntered = false;
void OnCollisionEnter(Collision collision)
{
if(isEntered) return;
if(collision.gameObject.tag == "enemy") isEntered = true;
....
....
}
I hope it will work for you.
Finally figured it out. First of all the script is dealing damage so I should hit the target specific number of times, so I can't stop the collision of the arrow without turning it back on. So I made a method, that is being Invoked (InvokeRepeating()) after the arrow collides, that turns a bool back to false. Which method (function) of course should be in Update();
I am not sure if I am saying it right bc I am a beginner but I hope this helps somebody. :D
And here is the code:
Arrow Script:
private void DealDamage()
{
if (hit == true)
return;
eHealth.EHealth -= hDamage.HDamage;
hit = true;
}
void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.CompareTag("enemy"))
{
DealDamage();
Destroy(gameObject); //Destroying arrow on collision
}
}
private void HitSetter()
{
hit = false;
}
void Update()
{
InvokeRepeating("HitSetter", 0f, 1.1f);
}
Enemy Script:
void Update()
{
if (EHealth <= 0)
{
anim.SetBool("EnemyDie", true);
Destroy(gameObject, 0.833f);
}
Also thanks to #Foggzie

Unity Door open with "e"?

I would like to be able to open my Gate with "e". I've got to the point where the player has to stand in front of the Gate and then you have to press "e", but I don't know how to do it. So far I've written that
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player") && Input.GetKeyDown("e"))
{
Debug.Log("door opens");
}
}
}
As OnTriggerEnter is only called the single frame the player collides with the door, instead use OnTriggerStay. The other option would be to store whether or not you have collided with the door then detecting the input in Update instead.
If you use OnTriggerStay:
private void OnTriggerStay(Collider other)
{
if(other.CompareTag("Player") && Input.GetKeyDown("e"))
{
Debug.Log("door opens");
}
}
If you would like to use OnTriggerEnter still, I would also use OnTriggerExit to know when they are no longer colliding with it.
private bool touchingDoor = false;
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Player"))
{
touchingDoor = true;
}
}
private void OnTriggerExit(Collider other)
{
if(other.CompareTag("Player"))
{
touchingDoor = false;
}
}
private void Update()
{
if(Input.GetKeyDown("e") && touchingDoor)
{
Debug.Log("door opens");
}
}

Trigger Collinder doesnt work with Input.GetKey

I'm trying to make a game where u can cut down trees, but when I tested my script it didn't work at all. This script is for cutting down trees. When I put TakeDmg and Destroytree in the private void OnTriggerEnter2D(Collider2D other) it works fine, but when I add if(Input.GetKey(KeyCode.E)), it stops working I really don't know that's the problem.
public int treeHp;
public GameObject logPrefab;
public Animator anim;
private void OnTriggerEnter2D(Collider2D other){
if(Input.GetKey(KeyCode.E)){
TakeDmg();
Destroytree();
}
}
public void TakeDmg(){
anim.SetTrigger("TreeDamage");
treeHp = treeHp -1;
}
public void Destroytree(){
if(treeHp <= 0){
//spawn la loguri
Destroy(gameObject);
}
}
Thanks :D
You code would require the User to already hold down the E key before(or in the same frame as) hitting the tree.
I would rather expect that you want to first move close to the tree and then press E in order to cut it.
You should rather use OnTriggerStay2D
Sent each frame where another object is within a trigger collider attached to this object (2D physics only).
in order to listen for the E key as long as you are within the trigger. I would then also use Input.GetKeyDown in order to handle the press only once instead of every frame.
Otherwise you would do
anim.SetTrigger("TreeDamage");
treeHp = treeHp -1;
ever frame while holing E down which is A) frame-rate-dependent and B) probabl not what you want to do here.
public float cooldownDuration;
private bool coolDown;
// Listen for the key as long as you stay in the collider
private void OnTriggerStay2D(Collider2D other)
{
if(!coolDown && Input.GetKeyDown(KeyCode.E))
{
TakeDmg();
Destroytree();
StartCoroutine(CoolDown());
}
}
IEnumerator CoolDown()
{
coolDown = true;
yield return new WaitForSeconds(cooldownDuration);
coolDown = false;
}
As alternative if you actually want to continue cutting while holding down E you could do it like
// Adjust in the Inspector: Seconds to wait before next cut
public float cutInterval = 1f;
private bool colliderExitted;
// Listen for the key as long as you stay in the collider
private void OnTriggerStay2D(Collider2D other)
{
if(Input.GetKeyDown(KeyCode.E))
{
StartCoroutine(CuttingRoutine())
}
}
private void OnTriggerExit2D(Collider2D other)
{
colliderExitted = true;
}
private IEnumerator CuttingRoutine()
{
colliderExitted = false;
while(!colliderExitted && Input.GetKey(KeyCode.E))
{
anim.SetTrigger("TreeDamage");
treeHp = treeHp -1;
// Add a delay before the next iteration
yield return new WaitForSeconds(cutInterval);
}
}

Problem with Colliders and their rotation in the Unity Game

The problem is that I what to create an openable door. This door should open when the player enter the Box Collider which is connected to the door. But the problem is when the door begins to open and to rotate, Collider starts to rotate too which brings me a lot of problems with usind such an idea. I try to create EmptyObject with its Collider but I can't connect this Collider with script and OnTriggerEnter function itself. Maybe I don't understand something, who knows, I'm just a begginer. How knows how to help, please write an answer.
My code if somebody needs it:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class openDoor : MonoBehaviour {
public Vector3 Rotation_;
private int i;
public float speed;
bool opentheDoor;
bool closetheDoor;
// Use this for initialization
void Start () {
opentheDoor = false;
closetheDoor = false;
}
// Update is called once per frame
void Update () {
if (opentheDoor == true) {
this.transform.Rotate (Rotation_ * Time.deltaTime * speed);
i += 1;
if (i == 70) {
opentheDoor = false;
i = 0;
}
}
if (closetheDoor == true) {
this.transform.Rotate (-Rotation_ * Time.deltaTime * speed);
i += 1;
if (i == 70) {
closetheDoor = false;
i = 0;
}
}
}
void OnTriggerEnter (Collider other) {
if (other.gameObject.tag == "Player") { {
opentheDoor = true;
}
}
}
void OnTriggerExit (Collider other) {
if (other.gameObject.tag == "Player") {
closetheDoor = true;
}
}
}
This is how i would handle the scenerio
Take
DoorHandler.cs
public class DoorHandler : MonoBehaviour {
public Door door;
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
door.OpenDoor();
}
}
}
This should be attached to Parent of the door.
Next Take
Door.cs
public class Door : MonoBehaviour {
public bool isOpened = false;
public void OpenDoor()
{
if (!isOpened)
{
isOpened = true;
Debug.Log("OPEN");
//OPEN DOOR CODE!
}
}
}
Attach this to the Door GameObject
NOTE
The hierarchy would be like DoorHandler->Door->DoorModel (where Door is just an empty gameobject pivot of the Door)
In DoorHandler GameObject attach BoxCollider and Check Mark IsTrigger.
Also Player SHOULD HAVE A RIGIDBODY (preferably Kinametic) and obviously a collider
So When Player enters the DoorHandler's Collider -> The DoorHandler's OnTriggerEnter will be triggered and finally Call the Door to OpenDoor()
Add another check in OnTriggerEnter that checks if the door is currently opening or not.
void OnTriggerEnter (Collider other) {
if (other.gameObject.tag == "Player" && !opentheDoor) {
opentheDoor = true;
}
}
attach the door to an empty object. put the trigger on the empty object. then make the ontrigger entry rotate the door, not the paent object, and the collider will remain in place.
Parent
-child(door)
-child(collider)

Teleport script not working as intended

I would like to make a gameobject in my game, which when enter trigger, then it will teleport my character to an another position (otherTeleport.transform.position), however when I use the script what I have written, my character won't teleport there, while the enemy will. If I put a Debug.Log in the bounce script which will log the character's position I see that my character has been at the otherTeleport's position, but only for one debuglog, and after that it's back to the original teleport's position. The teleport's would be working two-way so if the user go to one it will port it to the second, and if he goes to the second, then it will be ported to the first.
Here is my code:
public class TeleportScript : MonoBehaviour {
public GameObject otherTeleport;
private Collider otherTeleportColl;
public bool isNeedToTeleport;
private TeleportScript otherTeleportScript;
private GameObject player;
private Bounce bounceScript;
// Use this for initialization
void Start () {
isNeedToTeleport = true;
otherTeleportColl = otherTeleport.GetComponent<Collider>();
otherTeleportScript = otherTeleport.GetComponent<TeleportScript>();
player = GameObject.Find("Player");
bounceScript = player.GetComponent<Bounce>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider collider) {
if (isNeedToTeleport == true) {
if (collider.tag == "Enemy") {
otherTeleportScript.setNeedToTeleport(false);
collider.transform.position = otherTeleport.transform.position;
}
if (collider.tag == "Player") {
otherTeleportScript.setNeedToTeleport(false);
bounceScript.player.transform.position = otherTeleport.transform.position;
collider.transform.position = otherTeleport.transform.position;
bounceScript.playerTransform.position = otherTeleport.transform.position;
}
}
}
void OnTriggerExit(Collider collider) {
Debug.Log ("TELEPORTED OUT");
setNeedToTeleport(true);
otherTeleportScript.setNeedToTeleport(true);
}
public void setNeedToTeleport(bool value) {
if (value == true) {
isNeedToTeleport = true;
}
else {
isNeedToTeleport = false;
}
}
}
Any help would be appreciated!
I did some changes to your code, can't test it because I don't have access to unity right now, let me know if it works...
public class TeleportScript : MonoBehaviour {
public GameObject otherTeleport;
private Collider otherTeleportColl;
public bool isNeedToTeleport;
private TeleportScript otherTeleportScript;
private GameObject player;
private Bounce bounceScript;
// Use this for initialization
void Start () {
isNeedToTeleport = true;
otherTeleportColl = otherTeleport.GetComponent<Collider>();
otherTeleportScript = otherTeleport.GetComponent<TeleportScript>();
player = GameObject.Find("Player");
bounceScript = player.GetComponent<Bounce>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider collider) {
if(collider.tag == "Player" && isNeedToTeleport)
{
otherTeleportScript.setNeedToTeleport(false);
collider.transform.position = otherTeleport.transform.position;
bounceScript.player.transform.position = otherTeleport.transform.position; //not sure what is this for....
}
}
void OnTriggerExit(Collider collider) {
Debug.Log ("TELEPORTED OUT");
setNeedToTeleport(true);
otherTeleportScript.setNeedToTeleport(true);
}
public void setNeedToTeleport(bool value) {
if (value == true)
isNeedToTeleport = true;
else
isNeedToTeleport = false;
}
}
Your character teleports to the other place
after that you move the collider over there aswell, notice that the collider's object of other script of teleportation has been initialized with the isNeedToTeleport = true;
The character now also bounces there, hits the collider of the other object, it checks that isNeedToTelport is in fact true in this other script and it goes into the same If condition and teleports back!
Take this line:
otherTeleportScript.setNeedToTeleport(true);
out of your OnTriggerExit, or set it to false. Actually setting it to false might be better. You want to tell the other script that someone is incoming and it shouldn't immediately teleport them back.
As an aside, you should change your setNeedToTeleport function to this:
public void setNeedToTeleport(bool value) {
isNeedToTeleport = value;
}
Those ifs are redundant.