Imagine I have 2 gameobjects, red plate and apple.
When game start(this is crucial), apple already on red plate(2 gameobjects already in contact). so if I move red plate, the apple is "parented" to red plate and follow the transform.
How can I do that in Unity3D? I look at the code Trigger and Collision, both of them need to at least a stage that 1 moving gameobject to collide the other, which I don't have that.
Any idea how to deal with this?
I found the solution: Bounds.Intersect
As in:
var bounds1 = gameObject1.renderer.bounds;
var bounds2 = gameObject2.renderer.bounds;
if (bounds1.Intersects(bounds2))
{
// do something
}
So with this, my problem solved.
Probably the simplest implementation is to use OnTriggerEnter and OnTriggerExit to toggle the parenting of one object's transform to another, so that all children of the parent will accept the transform operations performed on the parent.
Example:
using UnityEngine;
[RequireComponent(typeof(BoxCollider))]
[RequireComponent(typeof(Rigidbody))]
public class
PlateCollider : MonoBehaviour
{
private void
Awake()
{
rigidbody.isKinematic = false;
rigidbody.useGravity = false;
collider.isTrigger = false;
}
}
And
using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
[RequireComponent(typeof(Rigidbody))]
public class
AppleCollider : MonoBehaviour
{
private void
Awake()
{
rigidbody.isKinematic = false;
rigidbody.useGravity = false;
collider.isTrigger = false;
}
private void
OnCollisionEnter(Collision collision)
{
PlateCollider tryGetPlate = collision.gameObject.GetComponent<PlateCollider>();
if (tryGetPlate != null)
{
transform.parent = tryGetPlate.gameObject.transform;
}
}
private void
OnCollisionExit(Collision collision)
{
PlateCollider tryGetPlate = collision.gameObject.GetComponent<PlateCollider>();
if (tryGetPlate != null)
{
transform.parent = null;
}
}
}
There's many other ways you can use to compare the two objects. In this example I try to get the component on a colliding gameobject and check if the component reference exists. Collision tags might be a better option for you, it might not.
Related
THIS POST IS NOW IRRELEVANT PLEASE CHECK MY NEWER ONE
I am making a horror game with next bots on VR (Quest/Quest2)
the player has 1 "Mixed" light on it and the bots use pathfinding AI with navmeshes and stuff but it seems that when the next bot gets within I'll say like 10 feet of the player and the player can see it and all the game just decides it wants to freeze and stop working!
It seems to happen before the player "Dies" but I'm not fully sure.
public class Kill : MonoBehaviour
{
// Start is called before the first frame update
public GameObject tes;
public GameObject LocoToOff;
public Vector3 SPOT;
public GameObject SprintLoco;
public GameObject Dead;
public AudioSource audioSource;
private bool Using;
public GameObject Safe;
public LocomotionControllery Loco;
private bool ChillOutItsGoing;
IEnumerator TurnOff()
{
ChillOutItsGoing = true;
LocoToOff.SetActive(false);
SprintLoco.SetActive(false);
Dead.SetActive(true);
Loco.Disabled = true;
audioSource.Play();
yield return new WaitForSeconds(3);
//foreach (var pls in WallsNStuff)
//{
// pls.SetActive(false);
//}
tes.transform.position = SPOT;
//yield return new WaitForSeconds(0.05f);
Loco.Disabled = false;
Dead.SetActive(false);
//foreach (var pls in WallsNStuff)
//{
// pls.SetActive(true);
//}
Safe.SetActive(true);
ChillOutItsGoing = false;
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "BOT")
{
if (ChillOutItsGoing == false)
{
Debug.Log(other.gameObject.name);
Using = LocoToOff.active;
StartCoroutine(TurnOff());
}
}
}
}
I believe it ended up just being because the thing was set to "Cutout" instead of opaque and Cutout I think is in alpha only 2 things I changed that fixed it for sure was setting it to opaque and adding a lil bit of smoothness (just did that idk if it was part of the fix or not)
My ideia basically is when i score i get 2 points, but when i touch a certain collider that changes to 3 and i am having a lot a trouble figuring out what colliders to use and how to use them.
I thnik i need to use another ontriggerenter
when i touch the cube it should change to 3
if (i touch a certain collider)
{
void OnTriggerEnter(Collider other)
{
ScoringSystem.theScore += 3;
}
}
else
{
ScoringSystem.theScore += 2;
}
First of all we need to create a GameManager to handle the Bool that checks if we are currently on the Line or not. We do this so we can acces it from all the scripts.
This code should be in a GameManager Object.
// Variable to check if the player is on the line or not
public bool stayingOnLine = false;
#region Singelton
public static GameManager instance;
void Awake()
{
if (instance != null) {
Debug.LogWarning("More than one Instance of GameManager found");
return;
}
instance = this;
}
#endregion
Then we add this Code to the GameObject that handles the LineCollider, to handle when the player enters the Line and when he leaves it. When this happens we change the Varible from the GameManager.
This code should be in your GameObject where the LineCollider that is set to IsTrigger is located.
GameManager gm;
void Start() {
gm = GameManager.instance;
}
void OnTriggerEnter(Collider col) {
// Player has entered the Line ColliderBox
if (col.CompareTag("Player Tag"))
gm.stayingOnLine = true;
}
void OnTriggerExit(Collider col) {
// Player has left the Line ColliderBox
if (col.CompareTag("Player Tag"))
gm.stayingOnLine = false;
}
After that we also need to add code to the GameObject that manages the HoopCollider. Because when the Ball enters we need to check if stayingOnline is true or false and then give different amount of points.
GameManager gm;
void Start() {
gm = GameManager.instance;
}
void OnTriggerEnter(Collider col) {
// Ball has entered the Hoop ColliderBox
if (!col.CompareTag("Ball Tag"))
return;
if (gm.stayingOnLine)
ScoringSystem.theScore += 3;
else
ScoringSystem.theScore += 2;
}
I am doing a 2d game and I want my player to be able to change bullets when he collides with an object(power) and destroy that object. I have a script and I was thinking that I need to implement 2 variables prefab ON/Off but now thinking much more I want to change with the help of a tag ( My player has in his script a public Rigidbody2D bullet) and this function
void Fire()
{
if (photonView.IsMine)
{
var firedBullet = Instantiate(bullet, barrel.position, barrel.rotation);
firedBullet.AddForce(barrel.up * bulletSpeed);
}
}
this is the script that I was working on for switching bullets but I think it will not work to change a bullet that I add in the inspector for the Character script , to disable from this script and add other bullet . How I can make it by tag?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponSwitching : MonoBehaviour
{
[SerializeField] private GameObject pickupEffect;
public GameObject[] DisablePrefab;
public GameObject[] EnablePrefab;
public int selectBullet = 0;
// Start is called before the first frame update
// Update is called once per frame
public void Bullet(Character bullet)
{
var effect = Instantiate(pickupEffect, transform.position, transform.rotation);
foreach (GameObject disable in DisablePrefab)
{
disable.SetActive(false);
}
foreach (GameObject enable in EnablePrefab)
{
enable.SetActive(true);
}
Destroy(gameObject);
Destroy(effect, 3.0f);
}
}
and I try this think with a BulletSwitch script to call the function from Weapon Switching script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BulletSwitch : MonoBehaviour
{
[SerializeField] private Character bullet;
// Start is called before the first frame update
private void Awake()
{
if (!bullet) bullet = GetComponent<Character>();
}
private void OnTriggerEnter2D(Collider2D other)
{
// or whatever tag your powerups have
if (!other.CompareTag("Bullet"))
{
Debug.LogWarning($"Registered a collision but with wrong tag: {other.tag}", this);
return;
}
var Bullet = other.GetComponent<WeaponSwitching>();
if (!Bullet)
{
Debug.LogError($"Object {other.name} is tagged PowerUp but has no PowerUp component attached", this);
return;
}
Debug.Log("Found powerup, pick it up!", this);
Bullet.Bullet(bullet);
}
}
inspector character
after my player collides with an object the bullets disappear.
You could make an array of prefabs and change to the correct bullet type when you hit a powerup by setting a CurrentBulletType variable to one of the types from the array. So when you hit powerup X, change bullet type to one of the types from the array.
public GameObject currentPrefab;
public GameObject[] bulletPrefabs;
private void OnTriggerEnter2D(Collider2D other)
{
string tagString = other.tag;
bool foundObject = true;
switch (tagString)
{
case "standard bullet":
currentPrefab = bulletPrefabs[0];
break;
case "fancy bullet":
currentPrefab = bulletPrefabs[1];
break;
case "even fancier bullet":
currentPrefab = bulletPrefabs[2];
break;
default:
foundObject = false;
break;
}
if (foundObject) other.gameObject.SetActive(false);
}
You can instead use a dictionary to directly reference the correct prefab by string name (tag) to make it easy to add more bullet types.
//dictionairy to reference bullet types quickly
public Dictionary<string, BulletTypes> bulletLibrary = new Dictionary<string, BulletTypes>();
//set these in the inspector
public BulletTypes[] bulletTypes;
[System.Serializable]
public struct BulletTypes
{
public string bulletName;
public GameObject prefab;
//public int bulletPower; //more data if you wish
}
private void Start()
{
//fill the dictionary based on the filled bullet type array in inspector
for (int i = 0; i < bulletTypes.Length; i++)
{
if (bulletTypes[i].bulletName != "")
bulletLibrary.Add(bulletTypes[i].bulletName, bulletTypes[i]);
else
print("bullet added, but name empty");
}
}
private void OnTriggerEnter2D(Collider2D other)
{
string tagString = other.tag;
//if the collided tag is in the dictionary, we can reference the bullet type from that dictionairy
if (bulletLibrary.ContainsKey(tagString))
{
print("spawn: " + bulletLibrary[tagString].bulletName);
print("prefab: " + bulletLibrary[tagString].prefab);
//all the data you need is in: bulletLibrary[tagString];
//Bullet.Bullet(bulletLibrary[tagString]);
other.gameObject.SetActive(false);
}
}
Sidenote: If you spawn a lot of bullets, you can use pooling. SimplePool is nice and easy for this. Instead of calling: instantiate and destroy, you call: SimplePool.Spawn() and SimplePool.DeSpawn().
If you have any more questions on this feel free to ask ;)
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.
I'm trying to create objects that mark the cell that I can visit. I mark them with red square:
My code for creating objects:
using UnityEngine;
using System.Collections;
using System;
public class SpawnCheck : MonoBehaviour {
public GameObject checkObject;
public bool canSpawnCheck = true;
Vector2 boxSize;
public GameObject spawnedObject;
// Use this for initialization
void Start () {
Debug.Log("Into spawn check");
}
void OnTriggerEnter2D(Collider2D other) {
Debug.Log("Enter trigger collision");
canSpawnCheck = false;
if (other.gameObject.tag == "Target") {
Debug.Log ("Found Target");
}
if (other.gameObject.tag == "Wall") {
canSpawnCheck = false;
}
if (other.gameObject.tag == "Check") {
canSpawnCheck = false;
}
}
void OnTriggerExit2D(Collider2D other) {
Debug.Log("Exit trigger collision");
canSpawnCheck = true;
}
// Update is called once per frame
void Update () {
Debug.Log ("canSpawnCheck " + canSpawnCheck);
if (canSpawnCheck == true) {
Vector3 currentPosition = this.gameObject.transform.position;
Vector3 spawnPos = new Vector3 (Mathf.Round (currentPosition.x), Mathf.Round (currentPosition.y),0);
Debug.Log ("Physics.CheckSphere " + Physics.CheckSphere (spawnPos, 5));
if (!Physics.CheckSphere(spawnPos,5)) {
spawnedObject = (GameObject)Instantiate (checkObject, spawnPos, Quaternion.identity);
this.gameObject.GetComponentInParent<AILerp> ().possibleTargets.Add (spawnedObject);
}
}
}
}
My problem: as Physics.CheckSphere(spawnPos,5) always return false my code spawns too many red squares and spawn them upon each other. I want red squares to be created only once and never created on walls (white squares).
Your Check(Clone) GameObject has Box Collider 2D attached to it. Therefore every physics function you must use should be Physics2D.something not Physics.something. Notice the keyword there "2D".
If you use just Box Collider without the 2D in it, then you can use Physics.something. So, Physics.CheckSphere cannot be used with a 2D collider.
Check(Clone) is a SpriteRenderer, 2D Collider is appropriate. You just need to use one of the Physics2D overlap functions such Physics2D.OverlapBox, Physics2D.OverlapArea or Physics2D.OverlapCircle. Which ever one you prefer.