Collision Weirdness

BlitzMax Forums/MiniB3D Module/Collision Weirdness

TheTophatDemon(Posted 2014) [#1]
I can't really wrap my head around this.
OK, so I'm trying to make some stereotypical fps game, and I'm trying to implement jumping. Well, I tried to detect whether the player was on the ground or not, so I used Raycasting (LinePick) to detect that. Most people just use EntityCollided, but I always thought that would trigger if the player was against a wall, too, and thus the player would be able to wall-jump.
Anyways, when I used LinePick() I got some very weird results. First of all, you can't jump anywhere in the map except for one specified area. Secondly, when you are in said specified area, you can somehow jump in midair. And also, the player is apparently spiderman. If you jump up against a wall and hold w, you won't fall to the ground at all. I have no idea what's going on here.

Here's the code (Assets included) :

https://drive.google.com/file/d/0BzyMN5S2kRTHM0tmUm5MS0dBWnc/edit?usp=sharing

*And yes, I DID search the forums, but I never found anything.*


Kryzon(Posted 2014) [#2]
Most people just use EntityCollided, but I always thought that would trigger if the player was against a wall, too, and thus the player would be able to wall-jump.

EntityCollided provides only partial information on a collision. If you want to have sophisticated physical interaction, you need more information than that.

On each frame (or on each time you call UpdateWorld), an entity may be colliding against one or more entities.
Therefore, to have an appropriate reactive behaviour, on each frame you need to cycle through all the collisions that an entity was involved in and retrieve information about them. The amount of collisions for an entity for the current frame is given by CountCollisions.

Once you have this amount, you can use a For-Next loop and retrieve the point of contact and the normal of the surface that the entity collided with for all the collisions for the current frame.
How you use this information is up to you, but a suggestion would be to use the normal information for applying (or damping) the forces that should influence your entity:
If you are jumping, you have a force moving your entity up (the jump force that it started with) and you have a smaller force moving it down (gravity).
- If the normal of one of the collisions points down (that is, its CollisionNY component is less than zero), you know that the entity collided with some sort of ceiling, so you can nullify the jump force as the entity should only fall from that point on (that is, it should only have the gravity influencing it).
- If the normal of one of the collisions points up (the CollisionNY value is greater than the steepest slope CollisionNY that you can walk on), you know that the entity collided with some sort of ground or platform, so you can stop applying gravity to it for the time being. Consequently, if the entity is not colliding with any surface pointing up, it should be under the influence of the gravity force.

Note that all of this can be done with a single "collision hull" for an entity. As of now, you can only set up ellipsoid hulls for "source" entities, and "destination" entities can have an ellipsoid, a box or their own mesh as hulls.
An entity with a single hull is as responsive as an entity with many child colliders, since the points and the normals of each contact can be separately retrieved even when a single hull is being used.

This is a more physics-oriented approach, so you need to study how vectors (vector maths and operations), velocities and accelerations (or forces) work. The final direction that the entity will be translated by is the resultant of all the forces influencing it.


RemiD(Posted 2014) [#3]
Kryzon>>Let's imagine CountCollisions returns 2 or more (which i have never seen yet), how do you decide which collision informations to use ? I always use the informations of the first collision (CollisionEntity(ColliderEmitter,1)) because, to me, this means this is the first collision which has been detected and therefore the collider must react to this collision, not to the others which may have happened after.

Can you please explain what you do if CountCollisions() returns 2 or more ? And why ? I am curious.

Thanks,


Kryzon(Posted 2014) [#4]
Hello.
I agree that more than 2 simultaneous collisions will be rare. They are a possibility, however.
The engine must check a source entity against all the destination entities progressively, so any of the detected collisions for the source entity will be listed in the order that the system detected them. They should be equally important nonetheless, since they were all found in the same call to UpdateWorld: on the same frame, the source entity is colliding against more than one obstacle.

Consider two destination entities: a level and a moving platform. Each has a distinct collision type.
Consider that the player is jumping (moving up and sideways) and that he collided against both the level and the moving platform. But we don't know in what way he collided against these entities.

We don't know if he has collided with his sides or with his head (considering a single hull for the entire player), but if you retrieve the normals for all the collisions that he was involved in, you can check if one of these collisions was against something pointing down: The player may have collided against the ceiling of the level, or he may have collided against the bottom of the platform. Either way, he has collided against something pointing down, so you know that he hit an obstacle to his upwards movement and so he should fall from that point on, since the only force acting upon him should be the gravity and not the jump force anymore since it was reset.
If none of the collision normals indicate that he has collided with a vertical obstacle then there's no need to change anything and he will keep moving up with his jump force.
For (all the collisions of the player on the current frame)

	If CollisionNY() < 0.0 Then jumpForce = 0 ;Reset the jump force of the player when he collides against at least one vertical obstacle.
	
	If CollisionNY() > 0.5 Then playerOnGround = True ;Consider the player on the ground if he collided against a point that faces up (so don't move him down with gravity, later).

Next
We should check all the collisions that an entity has participated in on an UpdateWorld call since at least one of these collisions may have the information that we're looking for to change the forces that we're moving or turning the entity with.


RemiD(Posted 2014) [#5]
I agree with what you say but this does not answer my question.

Let's imagine that a character has one collider "emitter" (entityradius) and there are 4 groups of colliders "receiver" (mesh) : the terrain, the buildings, the crates, the ladders.

Let's imagine that there is a ladder positionned against the wall of the building and that there is a crate positionned against the wall near the ladder (at left or at right)

Let's imagine that after you turn/move the character and call updateworld, countcollisions returns 3 (i don't know if this is possible but let's imagine)
The collision 1 is with the building wall
The collision 2 is with the ladder
The collision 3 is with the crate

In this game, a character can grab and climb on ledges if they are in range (and thus on the ledges of buildings walls and on the ledges of crates) and can grab and climb on ladders.

In this case, how will you choose what is the "right" collision to consider.

I understand that the developer has to decide in which order he wants to consider a collision but if this scenario happens, it can be come confusing.

Fortunately, the way Blitz3d collisions works with the response slide will prevent a collider "emitter" to go through a collider "receiver" so even if i consider only the first collision, there should be no errors.

Have you done some tests to know if the collisions index CollisionEntity(ColliderEmitter,index) corresponds with the nearest farest collision detected or if it corresponds to the order in which the colliders receiver have been tested and thus can not be trusted ?

Thanks,


Kryzon(Posted 2014) [#6]
As you can see from the source code, the collisions are listed as they are detected.
The order with which collisions are tested is defined when you call the Collisions function:
https://github.com/si-design/minib3d/blob/master/inc/TCollision.bmx#L171

Regarding the context that you have described, you need to have priorities.
Consider that the worst case scenario is when you have collided with all the three objects and that you're in a position and orientation that is favourable for grabbing all the three at the same time: grab the ladder, grab the ledge of the wall or grab the ledge of the crate.

To prevent the game from trying to do all of these three actions at the same time, you should program that climbing ladders is more important (has a higher priority) than grabbing ledges.
If one of the detected collisions is with a ladder and the conditions for grabbing it are positive given your current position and orientation (the point of impact, the normal of the impact etc.), then disregard the other grabbable objects even if the conditions for grabbing them are also positive.

Without taking the ladder in consideration, having several grabbable ledges close to each other (the crate and the wall) could be considered as a bad practice, as it can lead to erratic behaviour. So we need to address this with clever level design and avoid having ledges of different objects close enough so that the player won't collide with both at the same time.
If I'm not mistaken some engines allow you to 'tag' which ledges the player is able to grab, so you have further control over this issue.


RemiD(Posted 2014) [#7]

To prevent the game from trying to do all of these three actions at the same time, you should program that climbing ladders is more important (has a higher priority) than grabbing ledges.
If one of the detected collisions is with a ladder and the conditions for grabbing it are positive given your current position and orientation (the point of impact, the normal of the impact etc.), then disregard the other grabbable objects even if the conditions for grabbing them are also positive.


Yes i understand what you mean.
This discussion has been useful to me because now i will consider the others possible collisions which may have happened. Thanks for the explanations


Without taking the ladder in consideration, having several grabbable ledges close to each other (the crate and the wall) could be considered as a bad practice, as it can lead to erratic behaviour. So we need to address this with clever level design and avoid having ledges of different objects close enough so that the player won't collide with both at the same time.


Yes i agree.