I know this has been asked many times but I have checked as many forums as I can. Here is everything I'm doing:
I have a cube (that in this case is serving as the floor) with the following properties
and I have a "Runner" that is just a cube with the following properties
I froze the z position and rotations because this is a side-scroller.
The onCollisionEnter method for the "Runner" that you can see is attached to the "Runner" object is as follows:
void onCollisionEnter(){
print("Collision Detected");
}
And when I run it, I get bupkis. So. Help please? It seems so simple but I am clearly messing something up.
It is not
void onCollisionEnter()
but as stated in the documentation
void OnCollisionEnter(Collision collision)
So the method is written in full CamelCase and has an argument.
Related
I am trying to make a wall running script for my player and I was experimenting with OnCollisionStay The only problem I have is that it detects collisions with ground and things I don't want it to check. Is there any way to get it to only check walls or check things I want it too?
There are two ways to do this:
Use an if statement in your OnCollisionStay method and check the tag of the object you are colliding with:
void OnCollisionStay(Collision coll) {
if (coll.transform.tag.Equals("Wall")) {
// Do wall related stuff
}
}
Set up layer based collision detection. This documentation explains that: https://docs.unity3d.com/Manual/LayerBasedCollision.html
Depending on what it is that you're trying to achieve one or a mix of both of these approaches should get you the results you're looking for.
I am very new to c# and Unity and I have a question. I am not able to understand how OnCollisionEnter works fundamentally.
Like, if I have a terrain and a sphere hovering above it which has the rigid body component and I write:-
void OnCollisionEnter(Collision other)
{
Debug.Log(other.gameObject.name);
}
and then run the code we on the console screen would get "Sphere" and not "Terrain". Why is Sphere being passed to "other" and not Terrain?
Secondly, I believe, OnCollisionEnter is a part of the MonoBehavior class and our class is already inheriting it from MonoBehavior.
Then, why do we have to define OnCollisionEnter() again?
These questions are really eating my head up. I will be very grateful if anyone could help me out.
Why is Sphere being passed to "other" and not Terrain?
what is passed in other depends on which object you attached that component to ... if you attach it to the Terrain then in other you should get Sphere and viceversa. So you see the name other actually kind of makes sense, right?
Then, why do we have to define OnCollisionEnter() again?
in MonoBehaviour you can find OnCollisionEnter among al the others like Awake, Update, Start etc under "Messages", not under "private/public/whatever Methods".
In very short: Messages are internally only called by the Unity process if present in a component and not called at all if not present.
I think they use something similar to Component.SendMessage in the background but not sure.
Calls the method named methodName on every MonoBehaviour in this game object.
How it works: "OnCollisionEnter is called when this collider/rigidbody has begun touching another rigidbody/collider" - https://docs.unity3d.com/ScriptReference/Collider.OnCollisionEnter.html
OnCollisionEnter is among other functions (update, fixed update, start, awake, etc.), if defined within a body of MonoBehavior derived class, called by the Engine itself, i.e. these are engine event functions.
Why is triggered on the Sphere: Because you have your method in the class attached to the sphere object, see above how the OnCollisionEnter works.
Hey StackOverflow community, I am making my very first game and I've run into a problem. The game is about a ball dodging obstacles in order to reach the end of a level. So my issue is that I want to implement a "Woosh" sound whenever the ball passes an obstacle. I have created an invisible object which is supposed to execute the "Woosh" sound whenever the ball passes the invisible object.
These are the settings on the "invisible" object:
If you look at the image you can see that there is a "Woosh" script which contains these lines of code:
using UnityEngine;
public class Woosh : MonoBehaviour
{
void OnCollisionEnter(Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Player")
{
FindObjectOfType<AudioManager>().Play("Woosh");
}
}
}
This code is supposed to make the invisible object play the "Woosh" audio whenever it collides with the Player. However, when I try it out in game, the audio never gets played when I pass the invisible object.
For your information, I do have an audio manager, which contains all my sounds that I have implemented so far. It can be seen here:
Note: All the other sounds work, but not the "Woosh" sound.
Any help is appreciated!
Thanks in advance,
E.W
Comments aren't sufficient.
What I'm trying to tell you is that you can't just automatically assume that the problem is with the "Woosh" sound. That's just one of the things that can go wrong. You have this code:
public class Woosh : MonoBehaviour
{
void OnCollisionEnter(Collision collisionInfo)
{
if (collisionInfo.collider.tag == "Player")
{
FindObjectOfType<AudioManager>().Play("Woosh");
}
}
}
Your expectation is that when OnCollisionEnter is called, the "Woosh" sound will be played. You say the sound isn't playing, so you have to figure out what's wrong. This is what I would check:
Can you make the "Woosh" sound play somewhere else? You should be able to add code to your program to make the "Woosh" sound play. Maybe replace code that plays "ShatterSmall" with "Woosh". If the sound doesn't play there, then there's probably something wrong with the "Woosh" sound, and you need to fix it. If the sound does play there, then there's some other problem.
If "Woosh" plays in other places, but not in this code, then you have to check to see if the code is even being executed. If you're running this code in your debugger, put a breakpoint on the OnCollisionEnter method to see if it gets called. If it doesn't get called, then the problem is somewhere else. If you don't have a debugger, then you can output some kind of message like "Hey, I got here!" to tell you that the OnCollisionEnter function actually was called.
If you're getting to OnCollisionEnter, then you need to check to see if collisionInfo.collider.tag does indeed contain the value "Player". Again, use some kind of output function to tell you what is in that variable.
If collisionInfo.collider.tag == "Player", then check to see if the call to FindObjectOfType<AudioManager> returns the expected value.
You can break up your code:
var mgr = FindObjectOfType<AudioManager>();
if (mgr == null)
{
// some error here. Maybe throw an exception.
}
else
{
// Make sure (somehow) that it's really the object you wanted
}
mgr.Play("Woosh");
If the above tells you that you're getting the right object, then perhaps there's a problem playing the sound. Does Play throw any exceptions?
The point I'm trying to make here is that debugging involves questioning all of your assumptions, and doing tests to see where things are failing. This is best done with a debugger, because it lets you move through your code step-by-step to see exactly what's happening.
If you don't know how to use the debugger, now is the perfect time to learn. It will save you days of debugging.
It won't be making the sound because your collider is a trigger not a collision, so if you disable that box of Is Trigger, the sound will play when you collide with it.
If you want to pass through the collider like a trigger you need to use this functions.
void OnTriggerEnter(Collider other) {}
void OnTriggerStay(Collider other) {}
void OnTriggerExit(Collider other) {}
EDIT:
Also using FindObjectOfType is an expensive function, just make the Audio Manager a Singleton
I want to simulate two pistons that replicates the behaviour of a balance. I'm doing this with spring joints and applying the inverse weight one another when OnCollisionStay is called. This are my pistons and their rigidbodies and joints. Are exactly the same on both.
This is my SpringForceTransmisor.cs code:
using UnityEngine;
public Rigidbody InverseJoint;
private void OnCollisionEnter(Collision collision) {
Debug.Log("Enter");
}
private void OnCollisionExit(Collision collision) {
Debug.Log("Exit");
}
private void OnCollisionStay(Collision collision) {
InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
Debug.Log("Stay");
}
And this is a video of what's happening.
So, according to the log showed on the video, OnCollisionStay() stops being called even if OnCollisionExit() had never been called. How is this possible? I've always thought that OnCollisionStay() is called every frame from OnCollisionEnter frame and OnCollisionExit frame.
Can anyone shed some light about what's going on here?
According to the documentation on OnCollisionStay, it says:
OnCollisionStay is called once per frame for every collider/rigidbody
that is touching rigidbody/collider.
Unfortunately, this is not true sometimes. The OnCollisionStay function is called few times in some cases and the call is then stopped. This is either a long time bug that has not been fixed for years or the documentation is wrong.
My usual advise to people is to abandon the OnCollisionStay function and simply set a boolean variable to true in the OnCollisionEnter function then set it to false in the OnCollisionExit function. You can then use the Update function as the OnCollisionStay function by checking that boolean variable in the Update function.
public Rigidbody InverseJoint;
bool collisionStay = false;
Collision collision = null;
private void OnCollisionEnter(Collision collision)
{
Debug.Log("Enter");
collisionStay = true;
this.collision = collision;
}
private void OnCollisionExit(Collision collision)
{
Debug.Log("Exit");
collisionStay = false;
this.collision = collision;
}
void Update()
{
if (collisionStay)
{
InverseJoint.AddForce(-(collision.rigidbody.mass * Physics.gravity));
Debug.Log("Stay");
}
}
The answer to your question would become obvious if you included in the video the part, where the "Enter" is being registered.
Now to explain what is happening, let me show an example on a traingulated sphere . Here is how it looks like (with some triangles intentionally made invisible).
Keep in mind that it is hollow, all it essentially is are a bunch of points that form triangles. Now say this is a mesh for some mesh collider component. If any other collider interacts with this sphere_mesh_collider, the only way for unity to detect it is by checking for the triangles of those two colliders having intersections. This is to say that ANY OTHER area that is not covered INSIDE the triangles will not be checked. In other words the volume of my sphere here will never detect collisions (nor call the collision stay, but the collider havent exited either, so neither it calls exit).
That is what I think is happening in your case, although I can not say for certain because I do not see the whole process of colliders starting to interact (Enter) and than coming apart (Exit).
Edit: You can easily observe this if you enable unity wireframe (or shaded wirefram) in the editor window.
Another note from the Unity documentation:
Note: [...] Collision stay events are not sent for sleeping Rigidbodies.
You could try setting Rigidbody.SleepThreshold to zero to see if that solves your problem.
Just solved this myself. This is because your rigidbodies are sleeping, try setting the rigid body sleep to "Never sleep" and it will work.
I have an object with a mesh collider and a prefab with sphere collider. I want the instance of the prefab to be destroyed if the two collide.
I wrote the following in a script:
private void OnCollisionEnter(Collision c)
{
if (c == target)
Destroy(transform.gameObject);
print("something"); // Doesn't get printed
}
But it is not working. I have tried toggling isTrigger on both the objects.
I had the same problem of OnCollisionEnter not being called and found this question.
For me, the problem was that I was making a 2D game so the answer is to use the OnCollisionEnter2D function instead.
Have a look at this table
If you want your OnCollisionEnter to be called make sure:
(a) Both objects have a collider attached.
(b) None of the objects is a trigger collider (this will issue OnTrigger function & not OnCollisionEnter)
(c) One of the objects (doesn't matter which of them) is a rigid, non kinematic & non static object (the second don't have to be a rigid body).
(d) Due to computational difficulties MeshCollider might have hard times colliding with other mesh collider, use them with caution.
(e) Make sure both the objects are in the same layer (or at least that they collide in scene settings).
(f) If you are working in 2d - OnCollisionEnter2D will be called, rename your function.
Make sure one of them has a non-kinematic rigidbody attached. Taken from the Unity docs:
When a collision between two Colliders occurs and if at least one of them has a Rigidbody attached, three collision messages are sent out to the objects attached to them. These events can be handled in scripting, and allow you to create unique behaviors with or without making use of the built-in NVIDIA PhysX engine.
From here: Unity3D MeshCollider
I had a similar problem. The box collider wasn't as big as the collision object. Setting the x and z values to 2 units fixed the problem!
Have you tried using the OnTriggerEnter() method and setting a collider on the object to a trigger?
If it doesn't need to tell what object its colliding with you could do a simple
void OnTriggerEnter(){
Destroy(transform.gameObject);
}
Edit:
Also I have done OnCollision like this
private string hitobject;
void OnCollisionEnter(UnityEngine.Collision hit)
{
hitobject = hit.gameObject.tag;
if(hitobject == "Plane")
{
isgrounded = true;
}
}
None of the objects are triggers and they don't need rigid bodies to work.