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 sovalopivia · Jul 25, 2010 at 08:59 PM · collisionraycastboxcollider

Raycasting Collision for player movement in a maze

I'm using various methods for movement physics in a Pacman clone, to learn some different techniques (yes i know its probably overkill but its all for the sake of learning ;) ).

I am using 4 Rays for determining where the player can and cannot move, and when they can change direction.

The effect I am aiming for is best explained with an example:

Pacman is in a horizontal corridor which has T junctions at both ends, if the user presses right or left theyll start travelling along, and if they then press up or down this will be stored till they actual reach a valid turning point, then start moving in the new direction. alt text

I have extended the draw of the above rays for debugging purposes, their actual length reaches the edge of the Players Collider.

I have got this mostly working, the only problem I have encountered is that at corners it seems to count it as a valid turning when only one of the Rays has passed the corner; as shown in the picture above, rather than waiting till both Rays are clear and Pacman is fully in the vertical corridor. My position correcting means that when this happens pacman will just halt rather than actually clipping the wall.

here is Update()

void Update() { #region Controls

 // Set what the next direction the player intends to move next
 if (Input.GetButtonDown("Up"))
 {
     nextDirection = Vector3.up;
 }
 if (Input.GetButtonDown("Right"))
 {
     nextDirection = Vector3.right;
 }
 if (Input.GetButtonDown("Down"))
 {
     nextDirection = Vector3.down;
 }
 if (Input.GetButtonDown("Left"))
 {
     nextDirection = Vector3.left;
 }
 // If pressing the direction youre already going in cancel it
 if (nextDirection != Vector3.zero && nextDirection == currDirection)
 {
     nextDirection = Vector3.zero;
 }

 #endregion
 #region Reposition

 // If moving in a direction
 if (currDirection != Vector3.zero)
 {
     // Check if reached a wall
     wallAhead = AnyWalls(currDirection);

     // if im travelling and there are walls ahead stop
     if (wallAhead)
     {
         // correct position to prevent sinking into wall
         if (currDirection == Vector3.left || currDirection == Vector3.right)
         {
             myTransform.position = new Vector3(Mathf.Round(myTransform.position.x), myTransform.position.y);
         }
         if ((currDirection == Vector3.up || currDirection == Vector3.down))
         {
             myTransform.position = new Vector3(myTransform.position.x, Mathf.Round(myTransform.position.y));
         }
         // then stop moving
         nextDirection = Vector3.zero;
         currDirection = Vector3.zero;
     }

     // Move in Direction
     if (currDirection != Vector3.zero)
     {
         myTransform.position = Vector3.Lerp(myTransform.position, myTransform.position + currDirection * speed, Time.deltaTime);
     }

     // Correct minor misplacement
     if (currDirection == Vector3.left || currDirection == Vector3.right)
     {
         myTransform.position = new Vector3(myTransform.position.x, Mathf.Round(myTransform.position.y));
     }
     if ((currDirection == Vector3.up || currDirection == Vector3.down))
     {
         myTransform.position = new Vector3(Mathf.Round(myTransform.position.x), myTransform.position.y);
     }
 }

 #endregion
 #region Turning

 // Has user pressed a direction
 if (nextDirection != Vector3.zero)
 {
     // Check for walls when Player wants to turn
     wallInNextDirection = AnyWalls(nextDirection);

     // If not moving and walls in pressed direction ignore the direction
     if (wallInNextDirection && currDirection == Vector3.zero)
     {
         nextDirection = Vector3.zero;
     }

     // Check if it is possible to change direction
     if (!wallInNextDirection)
     {
         Debug.Log("Turning");
         currDirection = nextDirection;
     }
     else Debug.Log("Cant Turn");
 }

 #endregion

}

And this is the function called to cast rays

bool AnyWalls(Vector3 dir) { Vector3 origin1 = new Vector3(); Vector3 origin2 = new Vector3();

 if (dir == Vector3.up | dir == Vector3.down)
 {
     origin1.x = (myTransform.position.x + ( (myCollider.size.x / 2)) - 0.05f);
     origin1.y = myTransform.position.y;
     origin2.x = (myTransform.position.x - ( (myCollider.size.x / 2)) + 0.05f);
     origin2.y = myTransform.position.y;
 }
 else /* Direction == Left / Right */
 {
     origin1.x = myTransform.position.x;
     origin1.y = (myTransform.position.y + ( (myCollider.size.x / 2)) - 0.05f);
     origin2.x = myTransform.position.x;
     origin2.y = (myTransform.position.y - ( (myCollider.size.x / 2)) + 0.05f);
 }

 Debug.DrawRay(origin1,dir * myCollider.size.x);
 Debug.DrawRay(origin2,dir * myCollider.size.x);
 return (Physics.Raycast(origin1, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers) &&
         Physics.Raycast(origin2, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers));

}

As you can see that should return True when both rays are clear. It is likely I have just made some stupid mistake in there, and simply need a fresh pair of eyes to find it.

Again theres probably an approach more suitable for Pacman, but I'm just trying to learn all the different methods of doing things using simple projects.

Thanks for any replies!

Edit 1: Corrected typos and updated the variable names in the Update() snippet to be more easily readable Edit 2: I have included in the Update() snippet some of the Debug messages I am using which output "Can't Turn" and "Turning" these demonstrated to me that it was indeed attempting to turn early when a corner is reached.

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

3 Replies

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

Answer by Magnus Wolffelt · Jul 25, 2010 at 10:05 PM

Looking at the code briefly, I was unable to find an apparent error in your implementation. The AnyWalls() function looks correct.

However, some thoughts:

Thought #1: Comparing Vectors with == is risky at best, and can result in really annoying bugs. This is due to floating point errors that arise in computations and/or values defined that don't necessarily reflect an exact representable 32-bit float value. Even more subtle, is that 32-bit floats are put in high precision CPU registers, so you can have different results depending on whether the value goes by memory or not during computation.

This can generate VERY weird bugs, because usually what happens, when you don't get the results you expect, is that you add logging to track the value. This potentially alters the results of the computation because the value goes through memory and back into registers at lower precision. When you remove your debug logging, computation is probably performed in high precision registers all the way, which gives subtly different results. While Unity probably implements == operator with some sort of epsilon, you can still end up with it returning false for very similar vectors. I recommend you write a little function to make a coarse equality check, so that you can be confident that it isn't flaky for your needs.

Thought #2: I recommend you always put {} brackets around if/while/else/etc blocks. Not doing so can result in mistakes, resulting in bugs that are usually subtle and/or hard to find.

I'm sorry I couldn't help you more with the specific bug.

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 sovalopivia · Jul 25, 2010 at 11:24 PM 0
Share

Thanks for the advice, I know missing out brackets is a bit questionable, I was trying to cut down the conde length to make it reasonable to embed here ;)

Also how would I go about overloading the == operator for Vector3, in the cleanest way?

avatar image Magnus Wolffelt · Jul 26, 2010 at 05:30 PM 0
Share

Just use a local function to compare:

void IsAlmostEqual(Vector3 v0, Vector3 v1) { return $$anonymous$$ath.Abs(v0.x - v1.x) < 0.1f && ... (for all components) }

avatar image sovalopivia · Jul 26, 2010 at 10:01 PM 0
Share

Didn't think of that, I actually looked into overriding the == operator of the Vector3 class, but i guess thats unnecessary thanks again...

I doubt it will make any difference to this project, the only Vector3 comparisons I'm currently doing are using single unit directional vectors, eg Vector3.up but I will keep this in $$anonymous$$d for the future.

avatar image
0
Best Answer

Answer by sovalopivia · Jul 27, 2010 at 01:02 PM

There should be a wall if either ray is true not if both are true facepalm

fixed by changing the return line in the AnyWalls() function && to a ||

Before:

return (Physics.Raycast(origin1, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers) &&
        Physics.Raycast(origin2, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers));

After:

return (Physics.Raycast(origin1, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers) ||
        Physics.Raycast(origin2, dir, (myCollider.size.x / 2) + 0.1f, kDefaultRaycastLayers));
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
avatar image
-1

Answer by Vincent 1 · Oct 13, 2010 at 06:10 PM

probably a faster way to determin colission like this would be to us an array map of 0s and 1s 0 beign no wall 1 beign a wall

Comment
Add comment · Show 1 · 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 sovalopivia · Oct 14, 2010 at 03:47 PM 0
Share

I wasn't looking for an ideal method for collision detection this was an exercise for myself on doing raycasting.

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

No one has followed this question yet.

Related Questions

Custom Collision Detection 4 Answers

Have falling object exit from a collider after collision? 2 Answers

Easy Way To Enable A Certain BoxCollider2D? 0 Answers

Raycast collision detection on a 2d game 1 Answer

The name 'Joystick' does not denote a valid type ('not found') 2 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