Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
6
Question by Sevdanski · Nov 15, 2013 at 08:24 AM · 2d collisionphysics 2dignore collisions

One way platform using 2D Colliders?

I am currently in the process of building a platform game and I am looking into porting it over to the new 2D physics engine that was added in 4.3. It looks like most of it should port over, but I have no idea how to platforms that can only be collided with from above.

My current solution using the 3D system is a script I altered that converts the current collider into a mesh collider that only has faces pointing upwards. This seems to work really well, but I can't seem to find a similar solution using the 2D colliders.

I know that Box2D has something like a pre-collision event you can intercept before the physics system handles a collision, effectively giving you the option to ignore the collision, but it doesn't look like that functionality exists in the Unity release.

Does anyone have a solution? Or perhaps know if an update may include the hooks that I am looking for?

Any help is much appreciated.

Cheers, Sev

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

11 Replies

· Add your reply
  • Sort: 
avatar image
4

Answer by dunenkoff · Jan 04, 2014 at 06:38 PM

I know this topic is a bit stale and I'm pretty new to Unity and Physics2D.IgnoreLayerCollision probably has been added not so long ago, but I solved one way platform with just one line in FixedUpdate().

Physics2D.IgnoreLayerCollision (playerLayer, platformLayer, rigidbody2D.velocity.y > 0);

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Alexrose12345 · Jan 05, 2014 at 08:50 PM 1
Share

That's not a solution.

Let's say $$anonymous$$ario jumps over a platform, but doesn't reach the top. Diagram:

     $$anonymous$$$$anonymous$$
 ----$$anonymous$$$$anonymous$$---
 |   $$anonymous$$$$anonymous$$   |
 |        |

After he reaches the apex of his jump, his y velocity is now negative. But he should /not/ collide with the platform, because he isn't above it. It isn't a valid solution.

avatar image koboldskeep · Feb 20, 2015 at 11:21 PM 1
Share

Good point $$anonymous$$rose, but you can work around that. If you make your character's floor collider be a flat rectangle at his feet, this would work. Just put one-way platforms all on their own collision layer separate from the rest of the world. However, this then makes wall and ceiling collisions all a special case (possibly solved by ray or sphere casts.)

avatar image
1

Answer by DavidDebnar · Nov 17, 2013 at 03:55 PM

I solved it by setting the platform's collider to trigger and it's tag to "OneWayPlatform" and then adding the script below to the Player.

What the script does is in OnTriggerEnter/Stay, if the player is above the platform and moving downwards, it stops the player, and stores and disables it's gravity.

Then, once the player exits this particular collider by going left/right, it sets it's gravity back.

Edit: I optimized the code a bit and also increased the readability ;)

Edit 2: Demo: OneWayPlatforms

 #pragma strict
 
 public var deadZone : float = 0.1;
 
 private var g = 0;
 private var touchingPlatforms : int = 0;
 private var body : Rigidbody2D;
 
 function Start () {
     g = rigidbody2D.gravityScale;
     body = rigidbody2D;
 }
 
 function OnTriggerEnter2D (c : Collider2D) {
     if(c.CompareTag("OneWayPlatform")) {

         touchingPlatforms++;

         var maxDistance = (c.transform.localScale.y + transform.localScale.y) / 2;
         if(body.velocity.y < 0 && transform.position.y - c.transform.position.y - body.velocity.y * Time.fixedDeltaTime > maxDistance - deadZone) {
             body.gravityScale = 0;
             body.velocity.y = 0;
             transform.position.y = c.transform.position.y + maxDistance;
         }
     }
 }
 
 function OnTriggerExit2D (c : Collider2D) {
     if(c.CompareTag("OneWayPlatform") && touchingPlatforms-- == 1)
          body.gravityScale = g;
 }

--David

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image PuneetK · Nov 17, 2013 at 04:07 PM 0
Share

I'd love to read your code and learn something from it, but it's horribly indented and not at all nice to read.

Could you upload a neater version please, as this seems like a winner?

avatar image aballif PuneetK · May 08, 2016 at 08:33 PM 0
Share

Upload a neater version or explain what everything does. You could do that with comments in the code or in your answer.

avatar image DavidDebnar · Nov 17, 2013 at 06:14 PM 0
Share

Actually, it does use the native unity physics, it's not computationally intesive at all, and I just dragged it into another project I'm working on to fully test it and it just worked. which means all your accusations are false.

avatar image DavidDebnar · Nov 17, 2013 at 07:23 PM 0
Share

I don't wanna argue, really, but there are no calculations, which are applied every frame. Also, stopping the rigibody and turning it's gravity off, when it lands, is 'the native way' in any platformer. Then, I didn't use an empty project, but a huge complex platformer. Also, movement states and such won't break anything. Next, denying gravity doesn't have to do anything with the character being grounded or not. I've been program$$anonymous$$g for the better part of my life, and I'm pretty sure I cut out most of my program$$anonymous$$g habits by now.

What are bad program$$anonymous$$g habits on the other hand: changing the player's layer. It's the worst idea, mainly in bigger projects, because Unity limits you to 16 layers, and having 2 layers dedicated solely to one-way playforms is very bad. It's also more computationally intensive, since PhysX has to change it's list of active rigidbodies.

avatar image Alexrose12345 · Nov 22, 2013 at 08:39 PM 1
Share

"Also, stopping the rigibody and turning it's gravity off, when it lands, is 'the native way' in any platformer."

If you do that with a trigger and an object is going very fast, for instance, because you aren't doing a proper verlet integration to test where it's going to be in a couple of frames, it's going to find itself completely buried in the middle of your platform.

Also, that is OnTriggerEnter. So if something falls on top of your object, it will set it in motion again. There's nothing keeping it from its geodesic once another object is involved. If you were using OnTriggerStay then.. you would have some really weird behaviour too with collisions.

Another problem is if you want a platform that e.g. moves up and down. For instance, I want to have characters be able to jump on each other's head. Using triggers won't solve that problem.

avatar image pixelone · Apr 12, 2014 at 06:22 PM 0
Share

So this worked some, but I have steps. Steps I would like to run pass and when I turn around to go up, I should walk up. SO I guess One Way Collision on Steps.

Show more comments
avatar image
1

Answer by zobot · Jan 06, 2014 at 05:57 PM

You can use Physics2D.IgnoreLayerCollision and Physics2D.OverlapCircle to achieve one-way platforms.

This script would go on your player game object, with an empty game object placed at the feet of the player, used for the groundCheck transform.

//in your player controller script

/** empty game object used to check for ground, placed at the bottom of your character, with a small radius */ public Transform groundCheck; public float groundCheckRadius = 0.1;

/** Layer mask to define what layers are walkable / public LayerMask walkableLayerMask;

void FixedUpdate() { //first check if the ground is below the player bool isOnGround = Physics2D.OverlapCircle( groundCheck.position, groundCheckRadius, walkableLayerMask );

 //Now ignore collisions between the Player and OneWayPlatform layers, 
 //unless you're on the ground or travelling up.
 Physics2D.IgnoreLayerCollision( LayerMask.NameToLayer("Player"), 
                                 LayerMask.NameToLayer("OneWayPlatform"), 
                                 !isOnGround || rigidbody2D.velocity.y > 0 
                                );

}

The condition for IgnoreLayerCollision needs both the ground and velocity conditions to prevent the player's position from shifting when passing through the platform.

This assumes you have two layers (Player and OneWayPlatform) defined in Project Settings -> Tags and Layers. I also use EdgeCollider2D components on the one way platforms.

Also, if you wanted to allow the player to fall through the playform if they are holding a down button, you could change your condition to something like: (!isOnGround || rigidbody2D.velocity.y > 0 || Input.GetButton("Down") )

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Alexrose12345 · Jan 07, 2014 at 12:12 AM 2
Share

Uhh.. if your y velocity is positive you should be able to jump through platforms. Otherwise you'll hit your head on the tops of platforms, which defeats the whole point.

Obviously to do one way platforms all you need are the two conditions:

  • The player's feet are above the platform.

  • The player has a y velocity less or equal to 0.

You don't need OverlapCircle for that, you can just check the y position of the GameObject attached to the player's foot against the y position vertex of the top edge collider on the platform. If it's higher, he's above it.

But using a single layer doesn't work if you have two one way platforms like "steps" like this:

      CC
 .----CC---.
 |    CC   |
 |  .---------.
 |  |         |
 |  |         |

Where C is your character and the rest are the two platforms (the bottom of which he's standing on). If your character is standing on the bottom platform, he is "grounded", so he will collide with the top platform, even though he's in front of it.

Another example where it doesn't work: say you have projectiles like grenades that should bounce off the top of objects. Each one has to have its own check to see if it's on the platform. You can't assign a layer to every enemy, character, projectile, box etc. in the entire scene. There's a limited number of layers, and it would be extremely convoluted and a waste of resources.

There should be an IgnoreCollision function so you can choose two specific objects.

avatar image zobot · Jan 07, 2014 at 02:53 PM 0
Share

Yes, its very limited until IgnoreCollision or OnPreCollision2D is implemented. Hopefully that is soon.

avatar image lazerlars · Mar 02, 2014 at 06:37 PM 0
Share

This helped me a lot, i tried a bunch of diffrent things - but nothing worked out before i tried this. Remember to $$anonymous$$ake new layers, and assign a layer for the player, and one for the oneway platforms, and then assign the oneway playform to the layers you want the player to go through.

avatar image
0

Answer by Alexrose12345 · Nov 22, 2013 at 08:35 PM

This won't work yet because there isn't a Physics2D.IgnoreCollision yet, but it could be done with multiple layers. Add an EdgeCollider2D at the top. Define its height above the transform of the sprite it's attached to as platformheight.

Then:

 void FixedUpdate () {
         foreach (Rigidbody2D Object in FindObjectsOfType(typeof(Rigidbody2D)) as Rigidbody2D[])
         {
             float lowestpoint = Mathf.Infinity;
             foreach (Transform blah in Object.transform)
             {
                 if (blah.name == "Edge")
                 {
                     if(blah.transform.position.y<lowestpoint) lowestpoint = blah.transform.position.y;  
                 }
             }
             if (lowestpoint > transform.position.y + platformheight)
             {
                 Physics2D.IgnoreCollision(collider2D, Object.collider2D);
             }
         }
     }

Then stick four empty GameObjects called "Edge" on each side of your objects. If you're just using square hitboxes for everything though you can just use lossyscale to work out whether they're above or below. This will make the colliders only work if the object is above the platform.

But, again, Physics2D.IgnoreCollision isn't an option yet, so Physics2D.IgnoreLayer could be used as a temporary fix.

e.g. You could put different platforms on different layers, and then snap the player's height to the layer of the platform he's in, and forbid collisions on the same layer. Which is a pain for now, and a bad idea in general.

But I would also say that just simply using triggers and killing velocity and gravity is a bad idea too - very fast objects will be able to bury themselves into walls and objects will float slightly above your platforms instead of resting on them.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DavidDebnar · Nov 22, 2013 at 08:51 PM 0
Share

I wanted to use Physics2D.IgnoreCollision too, but I guess we'll have to wait until Unity implements it.

avatar image Alexrose12345 · Nov 22, 2013 at 09:03 PM 1
Share

I just requested it here:

http://feedback.unity3d.com/suggestions/a-physics2d-dot-ignorecollision-function-is-vital-for-proper-one-way-platformers-in-unity2d

If you feel like throwing a few votes towards it.

avatar image Sevdanski · Nov 23, 2013 at 04:27 AM 0
Share

Thanks for that - I've thrown a bunch of votes behind it.

I've got a temporary solution implemented that is a bit messy, but it won't be hard to swap it out to something like this if/when Physics2D.IgnoreCollision becomes available.

avatar image
0

Answer by nicloay · Mar 17, 2014 at 12:45 PM

Here is my workaround, because of bug (OnTriggerEnter2D call multiple times, i use 2 triggers, one for OnTriggerEnter, another for OnTriggerExit.

For triggers, i use EdgeColliders and on scene it looks like this alt text

Here is a full prefab structure

alt text

This code for enter Trigger

 public class OneWayPlatformTriggerEnterController : MonoBehaviour {
     public int playerLayerId = 8;
     public int enabledPlatformId = 9;
     public int disabledPlatformId = 10;
     GameObject parentGO;
 
     void Start(){
         parentGO = gameObject.transform.parent.gameObject;
     }
 
     void OnTriggerEnter2D(Collider2D other){
         if (other.gameObject.layer == playerLayerId && parentGO.layer == enabledPlatformId){
 
             parentGO.layer = disabledPlatformId;
         }
     }
 }
 

and this for exit

 public class OneWayPlatformTriggerExitController : MonoBehaviour {
     public int playerLayerId = 8;
     public int enabledPlatformId = 9;
     public int disabledPlatformId = 10;
     GameObject parentGO;
     
     void Start(){
         parentGO = gameObject.transform.parent.gameObject;
     }
 
     void OnTriggerExit2D(Collider2D other){
         if (other.gameObject.layer == playerLayerId){
             parentGO.layer = enabledPlatformId;
         }
     }
 }

As you can guess, my player has one layer Id, and oneWayPlatoform has 2 layer, one Layer when platform active and player can walk on it, and another layer which does not interact with player because of switched off in LayerCollision Matrix (Kevin is my player layer)

alt text


screen shot 2014-03-17 at 16.35.53.png (16.1 kB)
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
  • 1
  • 2
  • 3
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

31 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

2d colliders on 3d colliders 0 Answers

How can I avoid collisions between the same objects? 3 Answers

Make object stay on the Terrain, while the isTrigger is checked 0 Answers

Polygon Collider 2D has no edit collider? 1 Answer

Is there any way to disable Box collider 2d collision? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges