Non-existent collision detected with OnCollisionEnter() - c#

I'm trying to make a sticky grenade by disabling its rigidbody upon collision, using OnCollisionEnter(). However, OnCollisionEnter() fires when there is clearly no collision happening, as you can see in this image :
This causes my grenade to stick in the air. I suspect this is due to a lack of synchronization between physics loop & rendering loop. Also, my standard "non-sticky" grenade uses the same model & is working finely.
I already tried the following :
Verify that there are no other colliders which could cause my grenade
to "stick in the air"
Use OnTriggerEnter() instead. The result is a little better but the problem is that it is fired too late, only once the grenade is inside an obstacle or an enemy.
Add rigidbody & continuous collision detection to all objects
Tweak PhysicsManager.DefaultContactOffset from 0.01 to 0.001, as suggested by Eliasar
Switch from "PCM" to "Legacy Contacts Generation"
None of these worked so I'm feeling a little desperate. Thanks in advance for your help !
Code I use to stick the grenade upon collision :
void OnCollisionEnter(Collision c) {
rigidbody.isKinematic = true;
transform.parent = c.transform;
}

Related

Collisions between objects?

My problem looks like this:
I have one stationary object wall and second object that is moving projectile. I want projectile to stop when it collides with wall. But ewery my attempt ended with projectile passing through wall.
Only script that affects movement of projectile:
public Transform trans;
void Update()
{
trans.Translate(0, 0, speed * Time.deltaTime, Space.Self);
}
All compomponents of projectile:
All components of wall:
Note: I have correctly set up layers in project settings.
I have tried many combinations of rigit boddies, colliders, layers and so on, but projectile always passed through wall.
In general, your presented setup is right. The contacting object have a Rigidbody component, and the objects you can collide have at least a collider (not a trigger).
First possible problem: your Rigidbody is set to Kinematic. Did you enable all collision modes in Project Settings > Physics > Contact Pairs Mode?
Second problem is the use of transform.Translate in the Update. Translate will ignore physic and just move the object when you tell it to do, and Update may be out of sync with the physic loop, where it would be recommended to use FixedUpdate. Even using FixedUpdate, Translate will not do the right job. It will force the object to move and the physic can complain or not about that (it can move the object back, glitching, or it can just ignore and let the object pass).
The right way to move a Kinematic rigidbody is through rigidbody.MovePosition, as stated in the Unity docs. For non-kinematic objects, you can use AddForce. Some tutorials also teach to set velocity of Rigidbody, which is not recommended because it can have undesired effects. Do it if you know the side effects and really want them.
I had a similar issue before. May I suggest destroying the projectile instead? You will then have to use OnCollisionEnter().
First, create a script and attach it to your projectile game object. After that, give your wall a tag, like 'wall'. Then, do something like this:
void OnCollisionEnter(Collision collision)
{
// Gets information about the game object the projectile collided with
GameObject objectCollided = collision.gameObject;
if (objectCollided.tag == "wall'){
// Do something with either the wall/enemy
}
// Destroy the projectile
Destroy(gameObject);
}
Note: If the intent was not to destroy the projectile but rather sticking to the wall, I suggest you to use detect collision using Raycast. Raycast has a hitInfo parameter and stores information about a gameObject that it hit, as well as the where did the Ray hit the gameObject.
Thus you can use this to move your projectile accordingly. In my previous projects, I used the Rigidbody component of my projectile and used .AddForce() to shoot it out, then detect collision with OnCollisionEnter().
Maybe you could do the same, but have a separate function to remove that force on entering a collision. I never tried it so I do not know if it will work.
Transform.Translate overrides the physics engine of unity. If you want to take advantage of the rigidbody and collider components of your gameObjects, you need to use rigidbody.Velocity or (as unity recommends in the docs) rigidbody.AddForce, and make sure you set IsKinematic to False on both rigidbodies, so that they can interact with one another physically.

Collision with projectile causing SceneManager to LoadScene

Thank you in advance for any input.
What is essentially happening is this: When the player shoots, the scene resets
What I interpret as happening:
Player shoots a laser beam
Laserbeam prefab collides immediately with player (so far as I can tell)
SceneManager resets scene
I suspect two possible causes:
Either the origin of my laserbeam is causing the created projectilePrefab to trigger the player's collision in this piece of code:
private void OnCollisionEnter2D(Collision2D collision)
{
SceneManager.LoadScene(0);
//if collider is projectile.Prefab, don't run this piece of code
}
More generally that my laserbeam collision doesn't exclude the player gameobject:
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
var projectile = Instantiate(
projectilePrefab,
transform.position,
projectilePrefab.transform.rotation);
}
}
The typical solutions then would likely look like this:
Ensure the laserbeam spawns away from the player, so they do not collide.
or, ideally,
The collider on my player would be able to simply exclude contact with a laserbeam as cause for SceneManager to reset the scene.
Where I get stuck when it comes to testing these solutions is the exact syntax. I was hoping someone might be willing to give some insight that is adept at conditional statements and the like. I'm still super new, so while I can largely comprehend what I'm reading and being shown, I'm still stuck before that hump of really being able to dissect it all myself.
Essentially what my ideal might look like (so far as I can tell) is: "If collider is projectilePrefab, do not run SceneManager.LoadScene"
Cheers and thank you in advance!

Unity Player jump: when to use RaycastHit and when OnCollisionEnter

I am currently learning Unity with C# and now learned two ways to perform a player jump with double jump prevention.
The first is the GetComponent<Rigidbody>().AddForce method with double jump prevention by OnCollisionEnter, e.g. on transform.tag == "Floor".
The second is with the RaycastHit and Velocity for up.
For me the second method didn't work quite well. I was still able to do a double jump.
I was now wondering if someone could explain to me why or when to use one method above the other or which might be superior.
Thanks in advance!
Neither approach is necessarily superior. It all depends on the needs of your game.
Using a well-placed collider at the "feet" of a player model to check for groundedness can work well, but the emphasis is on "well-placed". Poorly positioned or poorly sized/shaped colliders will lead to false positives/negatives. For example, a player may hit the underside of a "ground" platform in the sky and set grounded to true. Or if a player is standing on the very edge of a platform their ground-check collider may not be colliding with the surface they are standing on, causing grounded to be false. And many other edge cases.
Using raycasting gives far more precise control over when and where groundedness should be checked, however, it is more expensive from a processing perspective. Raycasting also allows for upcoming ground collisions to be checked for.
A sophisticated system might use both raycasting and collision detection to cover all necessary groundedness cases.

My projectiles wont collide with my enemies in a 2D side scrolling Unity project?

As the title suggests, I've literally just started learning Unity recently and I'm practising by making a side scrolling shooter. I've been following a Udemy course about it and (to my knowledge) I've been following the tutor's instructions to the letter, but at the point where he tests his and it works fine, by projectiles go straight through my enemies.
I'm a bit stumped at this point and so I thought I'd post here to see what you guys thought. I bet it's something really simple I've not done.
Please see my projectile code below:
using UnityEngine; using System.Collections;
public class DestroyEnemyAndProjectile : MonoBehaviour {
public GameObject WhiteExplosion;
public GameObject OrangeExplosion;
void Start()
{
}
void Update()
{
}
void OnCollisionEnter2D (Collision2D tempCollision)
{
if (tempCollision.gameObject.tag == "Collision")
{
spawnParticles(tempCollision.transform.position);
Destroy(tempCollision.gameObject);
}
}
void spawnParticles(Vector2 tempPosition)
{
Instantiate(WhiteExplosion, tempPosition, Quaternion.identity);
Instantiate(OrangeExplosion, tempPosition, Quaternion.identity);
}
}
Thanks for your help!
I did post a question to them which got a response, they suggested that perhaps the projectile is going too fast and check there was a Rigidbody 2D attached - both of which were already collect
make sure that the object you're colliding with has the tag "Collision", with the same capitalisation.
If it's not, you can do this by:
1. Selecting the GameObject to be collided with
2. In the top-right, select the Tag property
3. Add tag, click the plus and type in "Collision"
4. Select the GameObject again, and select the "Collision" tag from the Tag property dropdown
Otherwise, if that's not the issue. Make sure the projectile has a type of Collider2D component, and that the projectile, or the object being collided with, has a Rigidbody2D.
First I would like to know what the behaviour of this script curently is. Is the collision method being called, and the projectile goes through the enemy anyway? Or the collision method is not being called at all?
That being said, these are things that you should check in order for collision to work:
Make sure that the projectile and the enemy have Collider2D components attached to them.
Make sure that the projectile and/or the enemy (at least one of them must) have a Rigidbody2D attached to it.
Make sure that the layer of the projectiles and the layer of the enemies are set to collide in the collision matrix (You can find the collision matrix in Edit->ProjectSettings->Physics)
Make sure that the enemy GameObject has its tag set to "Collision".
P.S: Welcome to Unity where issues like this are, in fact, usually caused by something super simple that you probably missed.

Kinematic Rigidbody moves on its own

I have a very weird issue in my 2D Unity game, which I was able to reduce to the following core problem/minimal reproducing test case. Follow these steps to reproduce (Unity 5.1.1f1):
Create a player object (Cube) at location (0,0,0).
Remove the BoxCollider Component.
Attach the following C# script, Unity will automatically add the required Components and thereby make it a Rigidbody Collider.
Set the isKinematic flag.
Add another Cube to the scene at location (2,0,0).
Remove the BoxCollider Component and add a BoxCollider2D. This makes this cube a static Collider.
Set the isTrigger flag.
Run the scene.
Expected behavior:
The player cube accelerates towards the other cube and stops moving once it touches it.
Observed behavior:
The player cube accelerates towards the other cube, then continues moving at constant speed.
Additional implementation details:
I originally moved all objects by translating their transform and didn't use Rigidbodies at all because I didn't need collision detection. Now I do, so I want Rigidbodies. I dived into online resources and found out I'm supposed to use rigidbody.MovePosition() rather than transform.Translate() or transform.position. I changed my script, and the above error appeared.
Going back to transform.position fixes the issue, but that's not a good solution, as it involves bad practice which, according to what I read, produces significant CPU loads.
Failed attempts to solve:
Switching to Update() and Time.deltaTime didn't make any difference.
I tried not returning in the Update() and instead simply resetting the timestep to 0 while stop is set. No change.
Fiddling with the Inspector and doing stuff like freezing position on the rigidbody or setting the player objects to also be a trigger had no effect at all. Changing anything on the Rigidbody component while the game is running (after the collision) makes the cube stop immediately. Literally anything, even setting its mass to 0.
I also tried setting velocity to 0, resulting in no change. Which does make sense since Update() is skipped entirely (I also checked that with a Debug.Log() by the way).
So at this point, I'm down to barely 30 lines of code and I still have no idea what's causing this. Since the involved objects are a static Trigger collider and a kinematic rigidbody collider, both with no physics materials, there should be nothing that makes this thing move once the flag is set. But it does move.
SimpleController2D.cs
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (BoxCollider2D), typeof (Rigidbody2D))]
public class SimpleController2D : MonoBehaviour {
public Vector3 velocity = Vector3.zero;
private Transform thisTransform;
private Rigidbody2D thisRigidbody;
public bool stop = false;
void Awake () {
thisTransform = GetComponent<Transform> ();
thisRigidbody = GetComponent<Rigidbody2D> ();
}
void FixedUpdate() {
float timestep = Time.fixedDeltaTime; // temporarily stored for ease of access
if (stop) {
return; // freeze on hit
}
velocity.x += timestep; // accelerate
/* add a second slash (/) to toggle between transform and rigidbody
thisTransform.position += velocity * timestep; /*/
thisRigidbody.MovePosition ((Vector3)thisRigidbody.position + velocity*timestep); //*/
}
void OnTriggerEnter2D(Collider2D col) {
stop = true;
}
}
Solution
This is a bug in Unity 5.1.1f1 and was fixed in the patch release 5.1.1p2 and later.
Get it here:
http://unity3d.com/unity/qa/patch-releases?version=5.1
What happened?
You can even reduce the problem to a single MovePosition call. MovePosition uses the physics engine to move the object. Therefore Unity calculates the velocity necessary to reach the target position within the next physics update. Version 5.1.1f1 fails to reset the velocity to zero after reaching the position, so the object will just continue moving with the calculated velocity.

Categories