• 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
0
Question by iblis_eifer · Feb 28 at 10:29 AM · 2d game2d-platformer2d-sidescroller

How do you make a one-way slope?


I am trying to help a friend who is making an action game. My friend is making an action game based on Sebastian Lague's Platformer source. He's lost his way trying to figure out how to make a one-way slope like in Super Mario World, and this has stalled his development. I'll send you the following source code and a file that depicts what I want to do, and I hope you'll let me know.


Player.cs :

 using UnityEngine;
 using System.Collections;
 
 [RequireComponent (typeof (Controller2D))]
 public class Player : MonoBehaviour {
 
     [Header("Basic Settings")]
     public float maxJumpHeight = 4;
     public float minJumpHeight = 1;
     public float timeToJumpApex = .4f;
     float accelerationTimeAirborne = .2f;
     float accelerationTimeGrounded = .1f;
     float moveSpeed = 6;
 
     [Header("Movement Settings")]
     public bool fastAirStraff;
 
     public float maxRunX;
     public float maxWalkX;
     public float walkAcc;
     public float runAcc;
 
     public float skidPower;
     public float releaseDeAcc;
 
     public float airStrafeBorder;
     public float airStrafeFast;
 
     [Header("Wall Jump Settings")]
     public Vector2 wallJumpClimb;
     public Vector2 wallJumpOff;
     public Vector2 wallLeap;
 
     public float wallSlideSpeedMax = 3;
     public float wallStickTime = .25f;
     float timeToWallUnstick;
 
     [Header("Gravity Settings")]
     float gravity;
     float maxJumpVelocity;
     float minJumpVelocity;
     Vector3 velocity;
     float velocityXSmoothing;
 
     [Header("Player status")]
     public bool isGrounded;
 
     Controller2D controller;
 
     Vector2 directionalInput;
     bool wallSliding;
     int wallDirX;
 
     void Start() {
         controller = GetComponent<Controller2D> ();
 
         gravity = -(2 * maxJumpHeight) / Mathf.Pow (timeToJumpApex, 2);
         maxJumpVelocity = Mathf.Abs(gravity) * timeToJumpApex;
         minJumpVelocity = Mathf.Sqrt (2 * Mathf.Abs (gravity) * minJumpHeight);
     }
 
     public bool Right, Left, Sprint;
 
     void Update() {
         Right = Input.GetAxisRaw("Horizontal") > 0;
         Left = Input.GetAxisRaw("Horizontal") < 0;
         Sprint = Input.GetButton("Sprint");
 
         if (controller.collisions.below)
         {
             isGrounded = true;
         }
         else
         {
             isGrounded = false;
         }
 
         #region Basic Settings
         CalculateVelocity ();
         HandleWallSliding ();
 
         controller.Move (velocity * Time.deltaTime, directionalInput);
 
         if (controller.collisions.above || controller.collisions.below) {
             if (controller.collisions.slidingDownMaxSlope) {
                 velocity.y += controller.collisions.slopeNormal.y * -gravity * Time.deltaTime;
             } else {
                 velocity.y = 0;
             }
         }
         #endregion
     }
 
     public void SetDirectionalInput (Vector2 input) {
         directionalInput = input;
     }
 
     void FixedUpdate()
     {
         CustomMovement();
 
         if(controller.collisions.left || controller.collisions.right)
         {
             velocity.x = 0;
             if(Left || Right)
             {
                 CustomMovement();
             }
         }
     }
 
     void CustomMovement()
     {
         bool moving = false;
         bool skidding = false;
         if (Right)
         {
             if (!isGrounded)
             {
                 if (velocity.x >= 0)
                 {
                     if (velocity.x >= airStrafeBorder)
                     {
                         velocity.x += runAcc;
                     }
                     else
                     {
                         velocity.x += walkAcc;
                     }
                 }
                 else if (velocity.x < 0)
                 {
                     if (-velocity.x >= airStrafeBorder)
                     {
                         velocity.x += runAcc;
                     }
                     else
                     {
                         if (fastAirStraff)
                         {
                             velocity.x += releaseDeAcc;
                         }
                         velocity.x += walkAcc;
                     }
                 }
             }
             else
             {
                 moving = true;
                 if(velocity.x >= 0)
                 {
                     if (Sprint)
                     {
                         velocity.x += runAcc;
                     }
                     else velocity.x += walkAcc;
                 }else if(velocity.x < 0)
                 {
                     velocity.x += skidPower;
                     skidding = true;
                 }
             }
         }
 
         if (Left)
         {
             if (!isGrounded)
             {
                 if(velocity.x <= 0)
                 {
                     if(-velocity.x >= airStrafeBorder)
                     {
                         velocity.x -= runAcc;
                     }
                     else
                     {
                         velocity.x -= walkAcc;
                     }
                 }else if(velocity.x > 0)
                 {
                     if(velocity.x >= airStrafeBorder)
                     {
                         velocity.x -= runAcc;
                     }
                     else
                     {
                         if (fastAirStraff)
                         {
                             velocity.x -= releaseDeAcc;
                         }
                         velocity.x -= walkAcc;
                     }
                 }
             }
             else
             {
                 moving = true;
                 if(velocity.x <= 0)
                 {
                     if (Sprint)
                     {
                         velocity.x -= runAcc;
                     }
                     else velocity.x -= walkAcc;
                 }else if(velocity.x > 0)
                 {
                     velocity.x -= skidPower;
                     skidding = true;
                 }
             }
         }
 
         if(!moving && isGrounded)
         {
             if(velocity.x > 0)
             {
                 velocity.x -= releaseDeAcc;
                 if (velocity.x < 0) velocity.x = 0;
             }
             else
             {
                 velocity.x += releaseDeAcc;
                 if (velocity.x > 0) velocity.x = 0;
             }
         }
 
         float maxSpeed = Sprint ? maxRunX : maxWalkX;
         if(velocity.x > maxSpeed)
         {
             velocity.x = maxSpeed;
         }else if(velocity.x < -maxSpeed)
         {
             velocity.x = -maxSpeed;
         }
     }
 
     public void OnJumpInputDown() {
         if (wallSliding) {
             if (wallDirX == directionalInput.x) {
                 velocity.x = -wallDirX * wallJumpClimb.x;
                 velocity.y = wallJumpClimb.y;
             }
             else if (directionalInput.x == 0) {
                 velocity.x = -wallDirX * wallJumpOff.x;
                 velocity.y = wallJumpOff.y;
             }
             else {
                 velocity.x = -wallDirX * wallLeap.x;
                 velocity.y = wallLeap.y;
             }
         }
         if (controller.collisions.below) {
             if (controller.collisions.slidingDownMaxSlope) {
                 if (directionalInput.x != -Mathf.Sign (controller.collisions.slopeNormal.x)) { // not jumping against max slope
                     velocity.y = maxJumpVelocity * controller.collisions.slopeNormal.y;
                     velocity.x = maxJumpVelocity * controller.collisions.slopeNormal.x;
                 }
             } else {
                 velocity.y = maxJumpVelocity;
             }
         }
     }
 
     public void OnJumpInputUp() {
         if (velocity.y > minJumpVelocity) {
             velocity.y = minJumpVelocity;
         }
     }
         
 
     void HandleWallSliding() {
         wallDirX = (controller.collisions.left) ? -1 : 1;
         wallSliding = false;
         if ((controller.collisions.left || controller.collisions.right) && !controller.collisions.below && velocity.y < 0) {
             wallSliding = true;
 
             if (velocity.y < -wallSlideSpeedMax) {
                 velocity.y = -wallSlideSpeedMax;
             }
 
             if (timeToWallUnstick > 0) {
                 velocityXSmoothing = 0;
                 velocity.x = 0;
 
                 if (directionalInput.x != wallDirX && directionalInput.x != 0) {
                     timeToWallUnstick -= Time.deltaTime;
                 }
                 else {
                     timeToWallUnstick = wallStickTime;
                 }
             }
             else {
                 timeToWallUnstick = wallStickTime;
             }
 
         }
 
     }
 
     void CalculateVelocity() {
         velocity.x = Mathf.SmoothDamp (velocity.x, velocity.x, ref velocityXSmoothing, (controller.collisions.below)?accelerationTimeGrounded:accelerationTimeAirborne);
         velocity.y += gravity * Time.deltaTime;
     }
 }


Controller2D.cs :

 using UnityEngine;
 using System.Collections;
 
 public class Controller2D : RaycastController {
 
     public float maxSlopeAngle = 80;
 
     public CollisionInfo collisions;
     [HideInInspector]
     public Vector2 playerInput;
 
     public override void Start() {
         base.Start ();
         collisions.faceDir = 1;
 
     }
 
     public void Move(Vector2 moveAmount, bool standingOnPlatform) {
         Move (moveAmount, Vector2.zero, standingOnPlatform);
     }
 
     public void Move(Vector2 moveAmount, Vector2 input, bool standingOnPlatform = false) {
         UpdateRaycastOrigins ();
 
         collisions.Reset ();
         collisions.moveAmountOld = moveAmount;
         playerInput = input;
 
         if (moveAmount.y < 0) {
             DescendSlope(ref moveAmount);
         }
 
         if (moveAmount.x != 0) {
             collisions.faceDir = (int)Mathf.Sign(moveAmount.x);
         }
 
         HorizontalCollisions (ref moveAmount);
         if (moveAmount.y != 0) {
             VerticalCollisions (ref moveAmount);
         }
 
         transform.Translate (moveAmount);
 
         if (standingOnPlatform) {
             collisions.below = true;
         }
     }
 
     void HorizontalCollisions(ref Vector2 moveAmount) {
         float directionX = collisions.faceDir;
         float rayLength = Mathf.Abs (moveAmount.x) + skinWidth;
 
         if (Mathf.Abs(moveAmount.x) < skinWidth) {
             rayLength = 2*skinWidth;
         }
 
         for (int i = 0; i < horizontalRayCount; i ++) {
             Vector2 rayOrigin = (directionX == -1)?raycastOrigins.bottomLeft:raycastOrigins.bottomRight;
             rayOrigin += Vector2.up * (horizontalRaySpacing * i);
             RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.right * directionX, rayLength, collisionMask);
 
             Debug.DrawRay(rayOrigin, Vector2.right * directionX,Color.red);
 
             if (hit) {
 
                 if (hit.distance == 0) {
                     continue;
                 }
 
                 float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
 
                 if (i == 0 && slopeAngle <= maxSlopeAngle) {
                     if (collisions.descendingSlope) {
                         collisions.descendingSlope = false;
                         moveAmount = collisions.moveAmountOld;
                     }
                     float distanceToSlopeStart = 0;
                     if (slopeAngle != collisions.slopeAngleOld) {
                         distanceToSlopeStart = hit.distance-skinWidth;
                         moveAmount.x -= distanceToSlopeStart * directionX;
                     }
                     ClimbSlope(ref moveAmount, slopeAngle, hit.normal);
                     moveAmount.x += distanceToSlopeStart * directionX;
                 }
 
                 if (!collisions.climbingSlope || slopeAngle > maxSlopeAngle) {
                     moveAmount.x = (hit.distance - skinWidth) * directionX;
                     rayLength = hit.distance;
 
                     if (collisions.climbingSlope) {
                         moveAmount.y = Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Abs(moveAmount.x);
                     }
 
                     collisions.left = directionX == -1;
                     collisions.right = directionX == 1;
                 }
             }
         }
     }
 
     void VerticalCollisions(ref Vector2 moveAmount) {
         float directionY = Mathf.Sign (moveAmount.y);
         float rayLength = Mathf.Abs (moveAmount.y) + skinWidth;
 
         for (int i = 0; i < verticalRayCount; i ++) {
 
             Vector2 rayOrigin = (directionY == -1)?raycastOrigins.bottomLeft:raycastOrigins.topLeft;
             rayOrigin += Vector2.right * (verticalRaySpacing * i + moveAmount.x);
             RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);
 
             Debug.DrawRay(rayOrigin, Vector2.up * directionY,Color.red);
 
             if (hit) {
                 if (hit.collider.tag == "Through") {
                     if (directionY == 1 || hit.distance == 0) {
                         continue;
                     }
                     if (collisions.fallingThroughPlatform) {
                         continue;
                     }
                     if (playerInput.y == -1) {
                         collisions.fallingThroughPlatform = true;
                         Invoke("ResetFallingThroughPlatform",.5f);
                         continue;
                     }
                 }
 
                 moveAmount.y = (hit.distance - skinWidth) * directionY;
                 rayLength = hit.distance;
 
                 if (collisions.climbingSlope) {
                     moveAmount.x = moveAmount.y / Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign(moveAmount.x);
                 }
 
                 collisions.below = directionY == -1;
                 collisions.above = directionY == 1;
             }
         }
 
         if (collisions.climbingSlope) {
             float directionX = Mathf.Sign(moveAmount.x);
             rayLength = Mathf.Abs(moveAmount.x) + skinWidth;
             Vector2 rayOrigin = ((directionX == -1)?raycastOrigins.bottomLeft:raycastOrigins.bottomRight) + Vector2.up * moveAmount.y;
             RaycastHit2D hit = Physics2D.Raycast(rayOrigin,Vector2.right * directionX,rayLength,collisionMask);
 
             if (hit) {
                 float slopeAngle = Vector2.Angle(hit.normal,Vector2.up);
                 if (slopeAngle != collisions.slopeAngle) {
                     moveAmount.x = (hit.distance - skinWidth) * directionX;
                     collisions.slopeAngle = slopeAngle;
                     collisions.slopeNormal = hit.normal;
                 }
             }
         }
     }
 
     void ClimbSlope(ref Vector2 moveAmount, float slopeAngle, Vector2 slopeNormal) {
         float moveDistance = Mathf.Abs (moveAmount.x);
         float climbmoveAmountY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;
 
         if (moveAmount.y <= climbmoveAmountY) {
             moveAmount.y = climbmoveAmountY;
             moveAmount.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign (moveAmount.x);
             collisions.below = true;
             collisions.climbingSlope = true;
             collisions.slopeAngle = slopeAngle;
             collisions.slopeNormal = slopeNormal;
         }
     }
 
     void DescendSlope(ref Vector2 moveAmount) {
 
         RaycastHit2D maxSlopeHitLeft = Physics2D.Raycast (raycastOrigins.bottomLeft, Vector2.down, Mathf.Abs (moveAmount.y) + skinWidth, collisionMask);
         RaycastHit2D maxSlopeHitRight = Physics2D.Raycast (raycastOrigins.bottomRight, Vector2.down, Mathf.Abs (moveAmount.y) + skinWidth, collisionMask);
         if (maxSlopeHitLeft ^ maxSlopeHitRight) {
             SlideDownMaxSlope (maxSlopeHitLeft, ref moveAmount);
             SlideDownMaxSlope (maxSlopeHitRight, ref moveAmount);
         }
 
         if (!collisions.slidingDownMaxSlope) {
             float directionX = Mathf.Sign (moveAmount.x);
             Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomRight : raycastOrigins.bottomLeft;
             RaycastHit2D hit = Physics2D.Raycast (rayOrigin, -Vector2.up, Mathf.Infinity, collisionMask);
 
             if (hit) {
                 float slopeAngle = Vector2.Angle (hit.normal, Vector2.up);
                 if (slopeAngle != 0 && slopeAngle <= maxSlopeAngle) {
                     if (Mathf.Sign (hit.normal.x) == directionX) {
                         if (hit.distance - skinWidth <= Mathf.Tan (slopeAngle * Mathf.Deg2Rad) * Mathf.Abs (moveAmount.x)) {
                             float moveDistance = Mathf.Abs (moveAmount.x);
                             float descendmoveAmountY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;
                             moveAmount.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign (moveAmount.x);
                             moveAmount.y -= descendmoveAmountY;
 
                             collisions.slopeAngle = slopeAngle;
                             collisions.descendingSlope = true;
                             collisions.below = true;
                             collisions.slopeNormal = hit.normal;
                         }
                     }
                 }
             }
         }
     }
 
     void SlideDownMaxSlope(RaycastHit2D hit, ref Vector2 moveAmount) {
 
         if (hit) {
             float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
             if (slopeAngle > maxSlopeAngle) {
                 moveAmount.x = Mathf.Sign(hit.normal.x) * (Mathf.Abs (moveAmount.y) - hit.distance) / Mathf.Tan (slopeAngle * Mathf.Deg2Rad);
 
                 collisions.slopeAngle = slopeAngle;
                 collisions.slidingDownMaxSlope = true;
                 collisions.slopeNormal = hit.normal;
             }
         }
 
     }
 
     void ResetFallingThroughPlatform() {
         collisions.fallingThroughPlatform = false;
     }
 
     public struct CollisionInfo {
         public bool above, below;
         public bool left, right;
 
         public bool climbingSlope;
         public bool descendingSlope;
         public bool slidingDownMaxSlope;
 
         public float slopeAngle, slopeAngleOld;
         public Vector2 slopeNormal;
         public Vector2 moveAmountOld;
         public int faceDir;
         public bool fallingThroughPlatform;
 
         public void Reset() {
             above = below = false;
             left = right = false;
             climbingSlope = false;
             descendingSlope = false;
             slidingDownMaxSlope = false;
             slopeNormal = Vector2.zero;
 
             slopeAngleOld = slopeAngle;
             slopeAngle = 0;
         }
     }
 
 }


PS: The first part of the two programs I just mentioned is difficult to read. I apologize for that.


alt text alt text


q1.png (119.9 kB)
q2.png (47.2 kB)
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

0 Replies

· Add your reply
  • Sort: 

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.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

146 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 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 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 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 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

How do i Flip a 2d game object that is facing towards the cursor 0 Answers

2D EndlessRunner Spike Placing 0 Answers

2D Openworld transport game. How to generate the tracks? 0 Answers

Default Contact Offset Problems 1 Answer

My Scene View is Fine but my Game View is just black but the Camera Works 0 Answers


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