Using Contact Point normals to allow for player jumping through platforms?

Anybody know a better way to do this? I’d love to hear your idea. Here’s how I’m doing it:

I’ve got a script that causes my player object’s rigidbody to be able to pass through platforms that he’s jumping up to. Basically, it works by checking to see if the player’s y position is less than or greater than the platform. It’s a simple fix. But because a platform’s position is technically at the center of it’s bounding box, and a rigidbody’s position is technically the center of ITS bounding box, my script doesn’t work properly when my player attempts to jump into the platform from the upper corner–since the script detects that the y position of the rigidbody is higher, and therefore the platform should be solid.

So, I think my problem is that I can’t use contact point normals to detect a player’s point of entry to a trigger because you can’t get those when you’re just using OnTriggerEnter. Is this correct?

Help!

Here’s my script:

var floorOfPlatform;
var playerObject;
function Start()
{
 	    if(gameObject == "puzzlePlatformTrigger")
	{
		floorOfPlatform = gameObject.transform.parent.gameObject.transform.Find("puzzleFloor");
	}
	if(gameObject == "jumpThroughTrigger")
	{
		floorOfPlatform = gameObject.transform.parent.gameObject.transform.Find("basicPlatform");
	} 
	if(floorOfPlatform == null)
	{
		floorOfPlatform = gameObject.transform.parent.gameObject.transform.Find("Puzzle Platform Floor");
	}
	playerObject = GameObject.Find("playerRigidBody");
}

function OnTriggerEnter(other: Collider)
{
	if(playerObject.transform.position.y < floorOfPlatform.transform.position.y) 
	{
		Physics.IgnoreCollision(playerObject.collider, floorOfPlatform.collider, true);
	}
}

function OnTriggerExit()
{
	Physics.IgnoreCollision(playerObject.collider, floorOfPlatform.collider, false);
}

I’m a little confused from the code whether your platform is using a solid collider or a collider set as a trigger. If it is a solid collider, you could use OnCollisonEnter/Exit to get the contact points and normals. The problem I see there is that the collision itself would slow down the moving character, so you’d probably have to manually adjust the rigidbody velocity to account for that.

Another possibility might be, assuming you have this script attached to all your platforms, is to have the platform script check in Update or FixedUpdate what the current bounds of the player is and, if they are above the platform, make it solid. This way, all platforms above the player will always be possible to jump through. You could have a flag for platforms without this characteristic or vise-versa.

(Sorry for the C#, but my Javascript is very rusty. Concepts are the same.)

GameObject player;
void Update()
{
    /* if the player is made up of more than one collider, you'd
       need to iterate over the colliders and use playerBounds.Encapsulate()*/
    Bounds playerBounds = player.collider.bounds;

    //check bottom of player to see if it is above the platform
    if(playerBounds.min.y >= collider.bounds.max.y)
    {
        //make the platform solid
    }
    else
    {
        //turn off platform collision
    }
}

This code is untested, just me thinking through the problem, but I think it would work.

A good way to do this would be to collide if Vector3.Dot (or Vector2.Dot) of Player.velocity && rayInfo.normal (for a simple raycast) is less than 0. In order for this to work you need to go into Edit–>Project Settings–>Physics and turn on the toggle for “raycast hits triggers.”

var Trans : Transform;

//or alternatively use:

private var Trans : Transform;

Trans = transform; //will not work with #pragma strict

    function FixedUpdate ()
        {
        var rayInfo : RaycastHit;
        var halfHeight : float = 1; //One half the player's height
        if(Physics.Raycast(Trans.position + (0.05 - halfHeight)*Vector2.up, -Vector2.up, rayInfo, 0.05)
            {
            Collide(Vector2(0,0)); //collide with a motionless platform if the dot is zero
            //INSERT Disable gravity code here
            }
        }

My collide code will help. It takes in a platform relative velocity variable, so if you want moving platforms, you can.

You can not just plug in these functions and see everything magically work. Personally, I think you should work to understand this code. I presume you are working in 2D, if not then should read up on 3D dot products.

Learn Dot Products, they essentially check if two vectors (such as velocity vectors and normal vectors (in this case) are facing in the same direction). For two normalized vectors, if the dot product is 1, they are parallel (0 degrees), dot product of -1 means the vectors are going away from each other (180 degrees)[which is what we are checking for], 0 means perpendicular (90 degrees or 270 degrees)

        function Collide (relVel : Vector2)
        	{
            Cross(controller.perceivedNormal);
        	if(Vector2.Dot(controller.perceivedNormal,Vector3(controller.velocity.x - relVel.x,controller.velocity.y -relVel.y,0)) < 0)
        		{
        		controller.velocity = relVel + Vector3.Project(Vector3(controller.velocity.x - relVel.x,controller.velocity.y  - relVel.y,0),Vector3(controller.moveDir.x,controller.moveDir.y,0));
        		}
        	}
    
    function Cross () //this is a Cross Product that is optimized for 2D
//it finds "rightward" and thus might be irrelevant in your game
//if platforms are not slanted
        {
        controller.moveDir = Vector2(normal.y,-normal.x);
        }

This is a makeshift post which has not been catered to the variables in the OP, so you will have to change the functions a little (who knows maybe a lot).