#bunp-collision-detection-issue

1 messages · Page 1 of 1 (latest)

hidden osprey
#

Yes, CollisionAvoidance is only called by the player manager right now
The other object does not yet call it

fresh jetty
#

Okay, so, let's do another debug thingy. You have most of it, but let's expand a bit. Make this the first line of CollisionAvoidance:

Debug.Log($"Collision Avoidance is happening between {collider.gameObject.name} and {collisionPoint.collider.gameObject.name} with {collisionPoint.contactCount} points of contact");
hidden osprey
#

First line before the IF or after the IF?

fresh jetty
#

Before the if

hidden osprey
#

Okay

fresh jetty
#

It'll spam the console a lot but it'll give valuable information

hidden osprey
#

commented out mine, putting yours in

#

It thinks something is null, let me solve that

#

Ah, collisionPoint is null because I havent collided with anything yet

#

because the debug is before the if statement that checks if collisionPoint is null

fresh jetty
#

Right, forgot about that. Wrap it in it's own if that only does the null check

hidden osprey
#

Will do

fresh jetty
#

What we should see here, is that whenever the player is colliding with something, we get the player's name, the collider (9) or whatever object you touch, and 1. There might be a single instance of it being 0, and that could be the root cause of the issue

hidden osprey
#

That is without the dog in the scene which causes the break

#

now with the dog..

#

hrm that shouldnt be showing, should it

#

why is the dog firing off that if statement, there is only one reference to that method and its on the player

fresh jetty
#

If you click on that last debug log, you get a stacktrace, just like for an error. Can you send a screenshot of that?

hidden osprey
#

Oh

#

this is why

#

the dog has this on it

#

it was just similar is why I mistook it

fresh jetty
#

Yeah, the first one should fire for both

#

The collision avoidance is only happening with the player

hidden osprey
#

clicking on the last debug log

hidden osprey
fresh jetty
#

I think the issue is what I thought before, CollisionStay seems to fire one last time on the frame CollisionExit happens, when the contact points are 0

hidden osprey
#

is this what you wanted to see?

#

Oh, zero 👀

#

one single instance of zero

fresh jetty
fresh jetty
hidden osprey
#

It does the zero call if I walk away from the wall, if I stand next to it, no zero

fresh jetty
hidden osprey
fresh jetty
#

Just so you can see the most recent stuff last

hidden osprey
#

this will help you understand the weirdness maybe

#

what you are seeing here is the full entire avoidance method being executed, but it only happens when the ball is there

#

I noticed it calls the zero check over and over, when the ball is there

#

but not when the ball is gone

fresh jetty
#

When the ball is gone, do you get spammed with 0 logs?

hidden osprey
#

Let me check

#

Yes

#

if I turn off the dog, I get spammed with zeros

fresh jetty
#

And when the ball is there, do you get spammed with 1 logs?

hidden osprey
#

I only get spammed from the one on the dog

#

if the dogball exists

#

and I dont move my player adjacent to the wall

fresh jetty
#

Okay, so collision avoidance is not being called when the dogball is touching the wall

hidden osprey
#

hat seems to be the case, it starts only after I touch the wall with the player

#

and if I step away, I get 1 single instance of zero

#

but if I pull the DOG away from the wall, I then get spammed with zeros

fresh jetty
#

Are those "collision avoidance" zeros, or "collision happened" zeros? In fact, let's repeat this experiment with the OnCollisionEnter one commented out

hidden osprey
#

Will do

fresh jetty
#

this is getting a bit hard to keep track of, and that log's served its purpose for now

hidden osprey
#

Okay, yeah

fresh jetty
#

What we should be seeing now:

  1. No logs until the player first touches a wall
  2. Spams of 1 logs while the player is touching a wall
  3. Spams of 0 logs after the player leaves the wall
  4. 2 and 3 should not change after spawning the dogball
hidden osprey
#

Okay, dog touch wall, nothing in the console
Player touch wall, avoidance check called with 1 collision continuously
Player stops touching wall, avoidance called with 0 collision, once
If I move or delete the dog at this point, avoidancecheck called with 0 collisions, continuously

fresh jetty
#

Just to have it in the thread, can you put the top of CollisionAvoidance function? With our new log and your old if statement?

hidden osprey
#

If I then walk towards the wall, avoidance check calls with 1 collision, despite the player not colliding with the wall

#

after that final step

#

but only if the dog is colliding with the wall

fresh jetty
#

Do the player and dogball have any sort of parent/child relationship at all?

hidden osprey
#

None, no links what so ever

fresh jetty
#

Okay, so, there's some weird spaghetti happening here, and we can keep unravelling it, or try to solve the original problem a completely different and less convoluted way. Which do you want to do?

hidden osprey
#

I always like to know why something is breaking so I can avoid it happening again in the future
We could fix this instance in a less convoluted way, but then we wouldnt know what caused it in the first place?

#

It is interesting the wall returns 1 collsion, but never 2 collisions

#

it returns 1 collision when the player is not touching it but the ball is

#

or if the player is and the ball isnt

#

but never both 2

fresh jetty
#

Right. I do want to know what's happening here, but I do think the root cause is the use of OnCollisionStay and never clearing that data

#

So we might unravel this and find that the solution is "do this a completely different way"

hidden osprey
#

Yeah fair, I can set that stored thing to null on CollisionExit

#

I was just concerned if I did that, sometimes it would screw up

fresh jetty
#

Honestly, that could be a quick fix. If you want to try that

hidden osprey
#

I have been having weird issues with unity collisions in extremely hard to reproduce situations I will get a return of no collision, despite havin collision

#

Ill set it to null on exit now though

#

That did appear to fix it, but confuses me immensely why it was working without nulling that value back out before I added a second object to the scene that could collide

#

I will try adding like, five dogballs to see if anything changes

hidden osprey
#

I was intending to give the dogballs this same collisionavoidance method as well, I just hadnt gotten that far yet because of the weird behaviour i was getting from the player

fresh jetty
#

What we should be seeing is that after you exit the wall, you are spammed with 0 logs

#

Since it sets to 0 once, and the collision object still has a collider to pass that null check

surreal siren
#

What happens if you are colliding with 2 walls and you stop colliding with just one after this?

hidden osprey
#

Double collider, no dogballs in scene, never see a 0 return (expected)
adding one dogball back in now

#

also still setting to null on exit, didnt appear to mess up when leaving one collider but still touching the other

#

Still nothing return 0 with one dogball and null on exit

fresh jetty
#

Here's what I'd do:

  1. Make a Dictionary of Collider2D, Collision2D that will store what objects you are currently colliding with
  2. In OnCollisionStay, add the collision to the dictionary with that collision's collider as the key
  3. In OnCollisionExit, remove the collider from the dictionary (which will remove it's associated collision)
#

Then you can query that diction to find everything you're touching, and can operate on them all at once via currentCollisions.Values to get a list of Collisions

surreal siren
#

That's very clean

#

I aspire to reach digiholic's level of knowledge and patience someday

hidden osprey
#

let me see why it doesnt want those as key/value

#

cannot convert from collider2d to collision2d

#

oh I have them backwards I think

#

that fixed it

fresh jetty
#

Yeah, collider first, then collision

hidden osprey
fresh jetty
#

The Collision object each frame of OnCollisionStay will be different, but the Collider that generated them is the same

#

Yeah, that should do it

hidden osprey
#

Okay so now I should use the Dictionary in my If test for object avoidance?

fresh jetty
#

Yeah, now you have a convenient way to get every collision currently happening on this object

#

collisionDictionary conveniently has two things for you:
.Keys will get you a list of every collider object you are currently touching at all times, while .Values will get you a list of all of the collision events with all their data about your current collision state with that specific object

#

So, if the goal of CollisionAvoidance was "check if I am currently colliding with a thing", you can just iterate over .Values. If you aren't touching anything, the dictionary still exists but is empty, so it won't throw an NRE

hidden osprey
#

Okay so now instead of passing in the collision 2D, I pass in the Dictionary. The CricleCollider I am not sure if I still need

#

I have not used a Dictionary before, they always sounded interesting butI havent had the usecase until now

fresh jetty
#

You put in object A, and it gives you the corresponding object B

#

So, you can do collisionDictionary[someObjectCollider], and if there is a collision with that collider, it'll return it. Otherwise, it'll return null

hidden osprey
#

So now with the Dictionary<Collider2D, Collision2D> collisionDictionary being passed in..

#

I need to replace those with... check if the dictiionary has ANYTHING in it

#

and that should cover both those checks I think?

#
        if (inputAngle != new Vector2(0, 0) &&
            collisionDictionary.Count != 0)
        {```
#

and now I have to fix where I used that info

fresh jetty
#

Yep. That will pass if the angle is not 0,0 and you are currently colliding with anything, that'll pass

#

Then, if you need info about each individual collision object, you can use a foreach loop

hidden osprey
#

This is where I was using the collision data before, I was naievely just taking the first collision which seemed to be working in all test cases

surreal siren
#

Are you using a repository? Be cautious when refactoring like this

fresh jetty
#

Possible, although one issue with dictionaries is that they aren't ordered. The "first" collision could be different every frame you check it

hidden osprey
#

I am the only programmer on this project, its solo

fresh jetty
hidden osprey
#

There's no risk of push conflict since its just me

surreal siren
#

Even if you are a solo developer, you still need a repository :p

fresh jetty
#

Yeah, but having a checkpoint before doing all this, just to look at, is good

hidden osprey
#

Okay in that case I do have a repo on github

#

What's a checkpoint?

#

A branch?

#

A push that works before I make all these changes?

surreal siren
#

Imagine you accidentally deleted one block of code when refactoring this and you forgot what it was

hidden osprey
#

Ahh

surreal siren
#

A commit

fresh jetty
hidden osprey
#

Okay yes in that case I have a clean commit that works before doing this 👍 For exactly that reason, if I break something and dont remember what

#

I have not often broken my entire project that badly as to need the rollback, but Its happened enough that I do this commit thing

#

Okay so now I should replace
collisionPoint.contacts[0].point with the dictionary somehow

#

hmm

#

Can you not pull from a dictionary at [0]?

#

I can do contains key, or value, but I am unsure what to pass in

#

I am unsure how to replace that bit with the Dictionary's equivalent

#

oh I can just do Dictionary[0].thing

#

hmm

#

am I dictionarying the wrong thing?

#

I cant seem to find contacts[0].point

#

I should check the unity doccumentation on dictionaries

#

hm no page for that, maybe csharp then

#

@fresh jetty I'm stuck, I can't figure out how to actually retrieve what I need from the Dictionary after passing it in

#

I think I might be dictionarying the wrong thing

fresh jetty
#

Sorry, I stepped out for a bit. You can't get [0] from a dictionary because it doesn't actually have an order

hidden osprey
#

do I want a dictionary of collisions, or colliders?

#

"collisionPoint.contacts[0].point " is the info I need from the dictionary

fresh jetty
#

You can get a list of keys or values from a dictionary and get the first element there, but that won't always be the same one

#

So, you can do collisionDictionary.Values[0].contacts[0].point

#

But if you're touching multiple walls, that might be a different point each time

#

If that's not a deal-breaker, that should work

hidden osprey
#

Cannot Apply indexing to dictionary

#

I was just doing [0] because it was easy

#

I should really be using... uhh.. I dont want to check every single collision, I dont know how to resolve that

#

the first one I guess?

fresh jetty
#

Oh, it's not a list, it's a different kind of IEnumerable, hang on, checking some docs

#

That's what .Values gets

surreal siren
hidden osprey
#

I will try to make sense of this doc but I fear I am not programmer enough

fresh jetty
#

Yeah, it's basically just a list-like structure that doesn't actually have an indexer

hidden osprey
#

so Ideally I just want to do that again, because I would have to re-write like 300 lines of code to make it work with multiple simultanious collisions

fresh jetty
#

Ah, found it:

collisionDictionary.Values.ElementAt(0).contacts[0].point
hidden osprey
#

Does not contain definition for ElementAt

fresh jetty
#

Really? Maybe it's from a namespace? I just ran it in my VS and it worked

#

Does your IDE suggest anything?

hidden osprey
#

Oh

#

it will work if I "using System.Linq;"

#

thats its suggestion

fresh jetty
#

Yes, that makes sense

#

it seems Linq-like

#

That's also a good sign. Linq is hella fast

hidden osprey
#

oh really? I was literally just about to say "I heard linq was slow and never to use it"

#

So obviously I heard wrong

fresh jetty
#

some Linq things are slow

#

but they're the fastest way to do the thing

#

If it's slow, it's because it can't be fast

hidden osprey
#

Ah, I dont remember what I was not using it for before, maybe it was that thing that was slow, because it was not this thing for sure

fresh jetty
#

Like sorting a list is never going to be faster than n log(n), and in most cases will be n^2

Don't worry if that makes no sense, it just means Linq is usually the best algorithms available

hidden osprey
#

okay now that ive made these changes, let me fix all the wrong variables being passed around to get it to compile

fresh jetty
#

You might be able to make a specific case implementation better, but no one beats general-case speed of the mathematically determined best algorithm

hidden osprey
#

Good to know, I do like best in slot

#

I got it to compile, testing if the behaviour is unchanged

#

Null reference on my dictionary

#

I might have to initialize it in awake maybe?

fresh jetty
#

Oh, you gotta initialize it

hidden osprey
#

I figured

fresh jetty
#

You can just do it in the declaration

hidden osprey
fresh jetty
#

Since dictionaries aren't serialized, Unity doesn't do it for you like it does for public lists

hidden osprey
#

Dictionary is upset that im trying to add duplicate keys

fresh jetty
#

Oh, right, don't use add

#

use collisionDictionary[other.collider] = other

#

it'll add if it doesn't exist

#

or change it if it does

hidden osprey
#

Hmm, the behaviour has totally changed

#

the only lines different were replacements of

#

contacts[0].point with collisionDictionary.Values.ElementAt(0).contacts[0].point

#

so I guess they were not cleanly equivalent in this case

#

Give me a moment to debug how its returning weird

#

hmm none of my debug hooks tripped that's even more concerning, deeper I go

#

Ah

#

weird corner case is the thing thats going wrong in this weird situation, of course it is, now to debug it

#

actually this shouldnt being called at all

#

god its incredibly dificutl to debug this function

#

because it only works in real time

#

I cant just set a hook because it gets called every single frame

surreal siren
#

You can use Visual Studio's debugging tool

hidden osprey
#

I think I am but you must be refering to something I dont know about

#

I do hook to unity debug

surreal siren
#

Oh I see

hidden osprey
#

and set red dots to pause code

#

this method gets called every single frame and requires player input values so it pauses constantly

#

okay I have no idea whats going wrong, but i dont think it has anything to do with the dictionary

#

as far as I can tell, the dictionary is working

#

this will probably take me a few hours to debug what is going wrong

#

Something is completely FUBAR with my method now but I've figured out what

#

for some reason all my raycasts are just completely FUBAR and I have no idea why, all the values are completely wrong

#

Ill stop reporting this and keep trying to fix it

#

because its at least something I think i can fix myself

#

@fresh jetty @surreal siren Everything appears to be working. I rolled back to the previous version of this function before adding the dictionary, re-added JUST the dictionary to it, and all behaviour is normal. Just like you said it was good to have the backup before the changes. I will take some time to try to determine what differs between current version of the method and the previous version.