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
0
Question by 2d4Games · Jul 28, 2013 at 08:47 PM · 2derrorraycastcharacterplatformer

Player sinking into walls and floor with Raycasts

I'm pretty new to Unity, and I've been trying to make a basic 2D platformer using 2d Toolkit. I tried using the Character Controller, but I need the precision of a box collider, I can't use the capsule collider that is built into it.

I found a blog post about how to make a 2D Platformer using raycasts to simulate collisions, and I've tweaked the code considerably to get it working (the code from the blog post simply doesn't work at all, variables are missing and all sorts of stuff is wrong).

The edited code kind of works, but I'm having some problems with it. The character sometimes "sinks" into the ground more than others, and sometimes just flat out ignores the wall raycasts. In addition, whenever the wall raycast does block the character, it gives me the error "NullReferenceException: Object reference not set to an instance of an object" in the console, pointing at lines 95, 56, 79, and 36.

Does anyone have any idea what my problem might be? I've been trying to get this working for days.

 var velocity = Vector2(0, 0);
 var maxVelocity = Vector2(0.35, 2.35);
 var gravity : float;
 var onGround = false;
 var onLeftWall = false;
 var onRightWall = false;
 
 
 
 function FixedUpdate () {
     //Limits the speed to the maxVelocity
     if (velocity.x > maxVelocity.x) velocity.x = maxVelocity.x;
     else if (velocity.x < -maxVelocity.x) velocity.x = -maxVelocity.x;
     
     if (velocity.y < -maxVelocity.y) velocity.y = -maxVelocity.y;
     
     //Instatiate the raycast variables
     var LFloorRay = new Ray(collider.bounds.center - collider.bounds.extents + Vector3(0,1,0), Vector3.down);
     var LFloorHit : RaycastHit;
     var LFloorWallRay = new Ray(collider.bounds.center - collider.bounds.extents + Vector3(0,1,0), Vector3.left);
     var LFloorWallHit : RaycastHit;
     var RFloorRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y, collider.bounds.extents.z) + Vector3(0,1,0), Vector3.down);
     var RFloorHit : RaycastHit;
     var RFloorWallRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y, collider.bounds.extents.z) + Vector3(0,1,0), Vector3.right);
     var RFloorWallHit : RaycastHit;
     var player : Transform;
     
     //check to see if the Bottom Left Floor raycast hits a "Solid" platform
     if (Physics.Raycast (LFloorRay.origin, Vector3.down, LFloorHit, 1))
 {
     
     if (LFloorHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (LFloorRay.origin, LFloorHit.point, Color.red);
         if (onGround == false)
         {
             onGround = true;
             velocity.y = 0; //If it hits a "Solid" platform, then make its vertical speed 0
             //and place the object ontop of the platform, but only if it wasn't already on a solid platform
             player.position = Vector3(player.position.x, LFloorHit.point.y - (collider.bounds.center.y + collider.bounds.extents.y), player.position.z);
         }
         
     }
     else //if the object is not "Solid", then ignore it
     {    
         onGround = false;
         velocity.y -= gravity * Time.deltaTime;
         
     }//If bottom left doesn't hit, check the bottom right
 } else if (Physics.Raycast (RFloorRay.origin, Vector3.down, RFloorHit, 1))
 {
     
     if (RFloorHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (RFloorRay.origin, RFloorHit.point, Color.red);
         if (onGround == false)
         {
             onGround = true;
             velocity.y = 0; //same as above
             player.position = Vector3(player.position.x, RFloorHit.point.y - (collider.bounds.center.y + collider.bounds.extents.y), player.position.z);
         }
         
     }
     else
     {
         onGround = false;
         velocity.y -= gravity * Time.deltaTime;
         
     }
 } else { //if nothing is hit by either raycast, apply gravity.
 onGround = false;
 velocity.y -= gravity * Time.deltaTime;
 }
 
     //Wall collision, checks to see if the player has touched a wall on their left side
     if (Physics.Raycast (LFloorWallRay.origin, Vector3.left, LFloorWallHit, 0.3))
 {
     if (LFloorWallHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (LFloorWallRay.origin, LFloorWallHit.point, Color.red);
         if (onLeftWall) {if (velocity.x < 0) velocity.x = 0;} else //if they are touching a wall, don't allow them to go
                                                                     //any further in that direction
         if (onLeftWall == false){
         onLeftWall = true; //If they aren't touching a wall, place them beside the wall.
         player.position = Vector3(LFloorWallHit.point.x + (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
         }
         
     } else {
         onLeftWall = false;
     }        
 } else onLeftWall = false;
 
     //same as above except for the right side instead of the left
     if (Physics.Raycast (RFloorWallRay.origin, Vector3.right, RFloorWallHit, 0.3))
 {
     if (RFloorWallHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (RFloorWallRay.origin, RFloorWallHit.point, Color.red);
         if (onRightWall) {if (velocity.x > 0) velocity.x = 0;} else
         if (onRightWall == false){
         onRightWall = true;
         player.position = Vector3(RFloorWallHit.point.x - (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
         }
         
     } else {
         onRightWall = false;
     }
 } else onRightWall = false;
 
     //change the player's position depending on the calculated velocities
     transform.position.x += velocity.x;
     transform.position.y += velocity.y;
 }
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

1 Reply

· Add your reply
  • Sort: 
avatar image
0
Best Answer

Answer by 2d4Games · Aug 04, 2013 at 01:47 PM

I have figured out the problem! It turns out that the collider.bounds.center is a vector relative to the world origin (it goes from 0,0 in the world to the center of the character), while collder.bounds.extents is a vector relative to the collider origin (it goes from 0,0 in the world to something diagonally above 0,0 , not actually to the model). This made me change a few things.

First, in line 26, I moved the declaration of the player variable to the top of the script. Doing this stopped the error from happening.

Second, I created a variable called AbsVelocityY, which is the absolute value of the Y direction of the velocity, and I made the raycast use this value as its distance. This makes it so that the raycast will essentially detect the object 1 frame before the character would hit it.

Third, I changed line 40 and line 60 to change the players position to FloorHit.point.y + collider.bounds.extents (because extents is relative to the character, not to the origin).

Here is the updated working code. I hope this helps anyone who might be having the same problem (I commented out the wall colliders for the time being):

 var velocity = Vector2(0, 0);
 var maxVelocity = Vector2(0.35, 1.0);
 var gravity : float;
 var onGround = false;
 var onLeftWall = false;
 var onRightWall = false;
 var player : Transform;
 
 
 
 function FixedUpdate () {
     //Limits the speed to the maxVelocity
     if (velocity.x > maxVelocity.x) velocity.x = maxVelocity.x;
     else if (velocity.x < -maxVelocity.x) velocity.x = -maxVelocity.x;
     
     if (velocity.y < -maxVelocity.y) velocity.y = -maxVelocity.y;
     
     //Instatiate the raycast variables
     var LFloorRay = new Ray(collider.bounds.center - collider.bounds.extents + Vector3(0,1,0), Vector3.down);
     var LFloorHit : RaycastHit;
     var LFloorWallRay = new Ray(collider.bounds.center - collider.bounds.extents, Vector3.left);
     var LFloorWallHit : RaycastHit;
     var RFloorRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y,0) + Vector3(0,1,0), Vector3.down);
     var RFloorHit : RaycastHit;
     var RFloorWallRay = new Ray(collider.bounds.center - Vector3(-collider.bounds.extents.x, collider.bounds.extents.y,0), Vector3.right);
     var RFloorWallHit : RaycastHit;
     var AbsVelocityY = Mathf.Abs(velocity.y) + 1;
     //Debug.DrawLine (LFloorRay.origin, Vector3(LFloorRay.origin.x, LFloorRay.origin.y - AbsVelocityY, LFloorRay.origin.z), Color.red);
     //check to see if the Bottom Left Floor raycast hits a "Solid" platform
     if (Physics.Raycast (LFloorRay, LFloorHit, AbsVelocityY))
 {
     
     if (LFloorHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (LFloorRay.origin, LFloorHit.point, Color.red);
         if (onGround == false)
         {
             onGround = true;
             velocity.y = 0; //If it hits a "Solid" platform, then make its vertical speed 0
             //and place the object ontop of the platform, but only if it wasn't already on a solid platform
             player.position = Vector3(player.position.x, LFloorHit.point.y + collider.bounds.extents.y, player.position.z);
         }        //LFloorHit.point.y + (-collider.bounds.center.y + collider.bounds.extents.y)
         
     }
     else //if the object is not "Solid", then ignore it
     {    
         onGround = false;
         velocity.y -= gravity * Time.deltaTime;
         
     }//If bottom left doesn't hit, check the bottom right
 } else if (Physics.Raycast (RFloorRay, RFloorHit, AbsVelocityY))
 {
     
     if (RFloorHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (RFloorRay.origin, RFloorHit.point, Color.red);
         if (onGround == false)
         {
             onGround = true;
             velocity.y = 0; //same as above
             player.position = Vector3(player.position.x, RFloorHit.point.y + collider.bounds.extents.y, player.position.z);
         }
         
     }
     else
     {
         onGround = false;
         velocity.y -= gravity * Time.deltaTime;
         
     }
 } else { //if nothing is hit by either raycast, apply gravity.
 onGround = false;
 velocity.y -= gravity * Time.deltaTime;
 }
 
     /*//Wall collision, checks to see if the player has touched a wall on their left side
     if (Physics.Raycast (LFloorWallRay.origin, Vector3.left, LFloorWallHit, 0.3))
 {
     if (LFloorWallHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (LFloorWallRay.origin, LFloorWallHit.point, Color.red);
         if (onLeftWall) {if (velocity.x < 0) velocity.x = 0;} else //if they are touching a wall, don't allow them to go
                                                                     //any further in that direction
         if (onLeftWall == false){
         onLeftWall = true; //If they aren't touching a wall, place them beside the wall.
         player.position = Vector3(LFloorWallHit.point.x + (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
         }
         
     } else {
         onLeftWall = false;
     }        
 } else onLeftWall = false;
 
     //same as above except for the right side instead of the left
     if (Physics.Raycast (RFloorWallRay.origin, Vector3.right, RFloorWallHit, 0.3))
 {
     if (RFloorWallHit.collider.gameObject.CompareTag("Solid"))
     {
         Debug.DrawLine (RFloorWallRay.origin, RFloorWallHit.point, Color.red);
         if (onRightWall) {if (velocity.x > 0) velocity.x = 0;} else
         if (onRightWall == false){
         onRightWall = true;
         player.position = Vector3(RFloorWallHit.point.x - (collider.bounds.center.x + collider.bounds.extents.x),player.position.y, player.position.z);
         }
         
     } else {
         onRightWall = false;
     }
 } else onRightWall = false;*/
 
     //change the player's position depending on the calculated velocities
     transform.position.x += velocity.x;
     transform.position.y += velocity.y;
 }
 
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

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

15 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

Related Questions

Another Double Jump Question 0 Answers

Background & sprites are smearing towards the player during movement. Help determine the cause and solution? 0 Answers

How to determine if the player can jump, without using raycasts. (2D) 1 Answer

2D jump with Raycast 1 Answer

2D platformer- getting errors I don't understand (c#) 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