Problem: Rather than use confusing words, let me try to give an illustrated example for what I’m trying to do. In a classic 2d platformer, say Mario, you can often walk in front of/through an object (mushroom enemy is doing so in the colored rectangles below), but if you jump to the top of it, you can land on it (as Mario is in the pic):
To describe the above picture In more Unity terms, it’s as if the rectangles either had no collision or were ignoring collision… until Mario’s foot height exceeds that of the rectangle. If Mario’s foot height > Rectangle height, then collision only along the top edge of rectangle.
I’m baffled about how to accomplish this without a ton of hacks in a 2.5d platformer. Here is my simple 2.5d platformer example, where I have a collision box extending out towards the camera that the ball can easily rest on.
As is, if I try to jump up from below, I’ll obviously hit it. I’d like to accomplish what seems so easy in a 2d platformer, but in 2.5d.
Goal: Allow player (ball) to jump through the collision if below, but interact with it if above.
Attempts: Before someone says to put them on a separate layer, or put an empty object on the base of my character that on CollisionEnter turns the ledge’s collision on etc., I did try. The issue becomes then how to turn it on/off and always ensure that only interaction from above ever collides.
Help: I thought of some convoluted ways to accomplish this using a ton of really bad collision hacks and ray casts and timers, but I figure I must be thinking about it wrong. Anyone know of an easy way to accomplish this?
I did something similar recently for door detection… I wanted to see which side of the door the player is on… If they are on one side allow for options to lock… if on the other side. Pick lock. Just as an example.
Here is the detection code:
public bool CheckIfPlayerInFront()
{
hit = Physics.OverlapSphere(frontLocation.position, frontViewRange, playerLayer);
foreach (Collider c in hit)
{
if (Vector3.Angle(frontLocation.forward, c.transform.position - frontLocation.position) <= angle)
{
//Change this script if needed..
if(c.GetComponent<InputHandler>() != null)
{
playerControl = c.GetComponent(typeof(InputHandler)) as InputHandler;
playerAnimation = playerControl.GetPlayerAnimations();
UIOptions = playerControl.optionMenu;
pInput = playerControl.controls;
return true;
}
}
}
return false;
}
–Added an image of editor with this code from above.
I have to admit I’m not familiar with OverlapSphere and the docs are a bit sparse on explaining it. I’m also not completely following how your example determines the side of the door it’s on.
How is determining the angle defining for you which side of the door you’re on?
In my mind I thought of OverlapSphere as working like SphereCast, but apparently not? Is it essentially creating a collision sphere that you define a vector and radius for then returning any colliders in that sphere?
Your image looks almost more like a circle slice than a sphere if I’m interpreting what is going on in your image correctly (white cone is your player, the alpha’d circle is the overlapsphere?).
Appreciate the help! I’ll muddle through it as best I can.
I’m going to re-try my initial thought using an attached hidden collision-as-trigger before I try anything fancier again. This should work… here’s a visualization of what I’m going to try. Green is player, Red is attached hidden collider, Black is the ledge’s collision. Keep in mind the black ledge would be thinner, the red collider is a bit further below the Green ball than shown so as u jump up through it, it doesn’t turn on until you’re above it. If anyone has any other ideas for overall approaches, let me know!
Mostly replying to myself here, but in case anyone searches for Platform and Collision and comes across this thread, here’s how I solved it relatively easily.
Somewhat like my picture above, except instead of 1 red collision detector at the bottom, I ended up having 2 collision detectors. One detector above the character, one below. Make them both children of the parent object character so they always follow.
The collision detector can be anything (small cubes), but the collider on the detectors need to have Trigger checked ON (so it doesn’t otherwise collide).
Then the script itself is relatively simple, two variants. Attached to top collider turns collision off, attached to bottom collider turns collision on.
The script below turns collision OFF by turning whatever it hit into a Trigger (which is a cheap way to turn collision off):
function OnTriggerEnter (other : Collider)
{
if (other.gameObject.name == "Ledge_Test") //obviously change this to whatever name you give your objects
{
//Debug.Log("Hit " + other.gameObject.name);
other.gameObject.collider.isTrigger = true;
}
}
You can quite simply use a plane for this task. Collision is one way on planes, so make the plane face upward. When mario jumps it will look as if he slides through the bottom of the plane, but lands on it when landing on the top side of it.
Interesting, that’s the kind of simple solution I was looking for! I knew there had to be an easier way, time to go try it.
EDIT: So I tried it, definitely works, but the player sort of “pops through” the collider, it’s kind of jarring. Is there an easy way around this? It basically goes not colliding, not colliding, oh wait we’re colliding, POP. Thanks for the suggestion!
Hmmm I solved this problem in my project using a trigger under the collider, if the object is too fast the plane solution won’t work well right? Or the plane collision algorithm works well with high speed objects?
you can make if the player jump from below and hit the collider you set the collider too false and if its exit the collider you set it back to true so when the player exit the collider will be true again and player will not fall down.
That’s essentially what I’ve done, I’m just making them Triggers (which don’t collide) rather than ignoring. I was just hoping I could use the above suggested Plane solution, but when I try it, it causes an awful “pop” when the collision turns on.