Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 /
  • Help Room /
avatar image
0
Question by GregPDesUGD · Aug 15, 2016 at 03:00 AM · triggervector3airaycastingpong

GPD Pong - Trouble with Raycasting for Opponent's Look-Ahead AI

I want to program the opponent AI where it can predict where the ball would be when it’s heading towards its paddle so that it can be moved to strike the ball at that spot. After posting a similar question on how the AI should behave, I tried programming this myself, figuring out some logic. But I’m running into trouble, because it seems that most of the time, the AI is not predicting in two of three specific cases I made.

This is simply a look-ahead raycasting approach, where the paddle would move to a specific position if the ball is heading straight towards the player’s goal zone (with no collisions on the walls whatsoever) or if the ball hits either the north or south walls exactly once before it reaches the opponent’s strike zone. In all other cases (where the ball hits the walls exactly more than once), the paddle does not react quite yet.

The code for this kind of AI is right here: (In a function called ballsPredictedZPositionInOpponentZone; there are debug statements currently. transform.position.x is the X position of the opponent’s paddle, as the script this function contains is attached to, and pongBall is simply an object of class Ball, which is attached to a game object comprising of a sphere, a rigidbody, and a collider. Tags and layers are used to filter the collisions and which decision the AI makes here.)

 float ballsPredictedZPositionInOpponentZone(out bool setPaddleIntoPosition)
 {
     /* 
         Logic:
         - Use raycasting to find the normal vectors if there are any collisions with the walls.
         - If a collision with a wall is past the opponent's strike zone (using absolute coordinate 
         values, on look-ahead, then we return both the Y position and a signal for the paddle 
         to get ahead.
         
         Base Cases:
         - If the first raycast hit is the opponent's goal zone, we simply use a scalar multiple 
         of the movement vector to find the position of the ball at that zone. Then we 
         return both the position and the flag to let the opponent get set.
         - In the case where what we hit in our first raycast is a wall, we perform one of 
         the following:
             - If in the next ray cast (after getting the normal) the collision detected is the
             goal zone or a paddle,
             use the same approach as the first to get the Y value the paddle should 
             move to to strike the ball.
             Return that, and output a true as well.
             - Otherwise, return 0.0f and false.

         Longest Ray Distance: 12.5 units (11.8 by Pythagoras from width and height of board
         plus a margin for detecting goal areas)
     */


     // Case 1 : Goal Zone from Primary Raycast
     // We simply notice that the collision this ray cast hits is a trigger zone representing the player's goal.
     RaycastHit collisionObject;
     float scalar;

     Debug.Log("Pong ball's position: " + pongBall.getPosition() + "\nPong ball's speed vector: " + pongBall.getSpeedVector());

     Debug.Log("Do we hit a collider? " + 
         Physics.Raycast(pongBall.getPosition(), pongBall.getSpeedVector(), out collisionObject, 12.5f, LayerMask.NameToLayer("Opponent AI")));
     Debug.Log("What's the collision object? " + collisionObject.collider);
     
     if (collisionObject.collider != null)
         Debug.Log("Is the collider object at the player's goal? " + collisionObject.collider.CompareTag("Player's Goal"));


     if (Physics.Raycast(pongBall.getPosition(), pongBall.getSpeedVector(), out collisionObject, 12.5f, LayerMask.NameToLayer("Opponent AI")) &&
         collisionObject.collider.CompareTag("Player's Goal"))
     {
         // Formula for scalar: absolute x position of paddle minus absolute x position of pong ball, 
         // divided by x value of speed vector

         Debug.Log("Case 1");

         scalar = (Mathf.Abs(transform.position.x) - Mathf.Abs(pongBall.getPosition().x)) / 
             Mathf.Abs(pongBall.getSpeedVector().x);
         setPaddleIntoPosition = true;
         return pongBall.getPosition().z + pongBall.getSpeedVector().z * scalar;
     }






     // Case 2 : Goal Zone / Paddle from Secondary Raycast
     // We extend the ray as two partial rays with one hitting the wall and another hitting a goal zone.

     Debug.Log("Case 2 Detect");

     RaycastHit collisionObject2;

     Debug.DrawRay(pongBall.getPosition(), pongBall.getSpeedVector() * 5, Color.red, 10.0f);
     if (Physics.Raycast(pongBall.getPosition(), pongBall.getSpeedVector(), out collisionObject, 12.5f, LayerMask.NameToLayer("Opponent AI")))
         Debug.Log(collisionObject.collider);


     if (Physics.Raycast(pongBall.getPosition(), pongBall.getSpeedVector(), out collisionObject, 12.5f, LayerMask.NameToLayer("Opponent AI")) &&
         (collisionObject.collider.CompareTag("North Wall") || collisionObject.collider.CompareTag("South Wall")))
     {

         Debug.DrawRay(pongBall.getPosition(), Vector3.Reflect(pongBall.getSpeedVector(), collisionObject.normal) * 5, Color.red, 10.0f);



         Debug.Log("Reflection Vector on Speed: " + Vector3.Reflect(pongBall.getSpeedVector(), collisionObject.normal) 
             + "\nPong ball's speed vector: " + pongBall.getSpeedVector());
         Debug.Log("Do we hit a secondary collider? " +
             Physics.Raycast(collisionObject.normal, Vector3.Reflect(pongBall.getSpeedVector(), collisionObject.normal),
             out collisionObject2, 12.5f, LayerMask.NameToLayer("Opponent AI")));
         Debug.Log("What's the other collider? " + collisionObject2);
         Debug.Log("Is the collider object at the player's goal? " + collisionObject2.collider.CompareTag("Player's Goal"));
     }


     if (Physics.Raycast(pongBall.getPosition(), pongBall.getSpeedVector(), out collisionObject, 12.5f, LayerMask.NameToLayer("Opponent AI")) &&
         (collisionObject.collider.CompareTag("North Wall") || collisionObject.collider.CompareTag("South Wall")) &&
         
         Physics.Raycast(collisionObject.normal, Vector3.Reflect(pongBall.getSpeedVector(), collisionObject.normal), 
         out collisionObject2, 12.5f, LayerMask.NameToLayer("Opponent AI")) &&
         (collisionObject2.collider.CompareTag("Player's Goal")))
     {

         Debug.Log("Case 2");

         // Similar to above, but with the normal surface this time.
         scalar = (Mathf.Abs(transform.position.x) - Mathf.Abs(collisionObject.normal.x)) /
             Mathf.Abs(Vector3.Reflect(pongBall.getSpeedVector(), collisionObject.normal).x);
         setPaddleIntoPosition = true;
         return pongBall.getPosition().z + pongBall.getSpeedVector().z * scalar;
     }







     // Case 3 : None of the above
     Debug.Log("Case 3");


     setPaddleIntoPosition = false;
     return 0.0f;

 }


What’s happening is, on my output, by the time the ball comes back and hits the opponent’s ball detector (which is a spherical trigger collider), even if the ball is definitely moving straight towards the player’s goal zone with no collisions along the way, Case 1 is omitted. Case 2 is also omitted as well when we see a collision has to be made with the north or south wall before the ball gets into the opponent’s strike zone.

For your convenience, here’s a photo of the different components I’m referring to: alt text

Below is some sample output for the two specific cases I’m trying to deal with: alt text

Please help me out here!

raycasting-components.png (60.0 kB)
case-1-and-2.png (72.3 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

1 Reply

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

Answer by GregPDesUGD · Aug 22, 2016 at 01:24 AM

I decided to go on about and implemented a different solution, which somewhat works. I said "somewhat" because what I didn't test is when the opponent is on the left side instead of the right side.

Basically, I use vector and scalar arithmetic to predict the Z position of the ball when its X matches the opponent's paddle, by simply extending the speed vector's Z component by some scalar that is how many times the x component of the speed vector needs to be so that by the next frame, the ball is exactly the same x position as the opponent's paddle.

 Debug.Log("Speed Vector: " + pongBall.getSpeedVector());
 
         // Distance to Player's Goal (X-component)
         float xDisplacementToPlayersGoal = Mathf.Abs(transform.position.x - pongBall.getPosition().x);
 
         // Scalar for Speed Vector
         float scalarForSpeedVector = xDisplacementToPlayersGoal / Mathf.Abs(pongBall.getSpeedVector().x);
 
         // Scaled Y-Value for speed vector
         float scaledZValueForSpeedVector = (scalarForSpeedVector * pongBall.getSpeedVector()).z;
 
 
         Debug.Log("X Displacement to Player's Goal: " + xDisplacementToPlayersGoal);
         Debug.Log("Scalar for Speed Vector: " + scalarForSpeedVector);
         Debug.Log("Scaled Z Value for Speed Vector: " + scaledZValueForSpeedVector);
 
 
         // Retrieve the Y value based on these float values
         if (scaledZValueForSpeedVector + pongBall.getPosition().z < 2.35f && scaledZValueForSpeedVector + pongBall.getPosition().z > -2.35f)
         {
             Debug.Log("Current predicted value [0]: " + (scaledZValueForSpeedVector + pongBall.getPosition().z));
             return scaledZValueForSpeedVector + pongBall.getPosition().z;
         }
 
         // The ball is moving downwards and has to traverse across the width of the board at least once.
         if (scaledZValueForSpeedVector < 0.0f && Mathf.Abs(scaledZValueForSpeedVector) >= 4.8f)
         {
             Debug.Log("Current predicted value [1]: " + (scaledZValueForSpeedVector + pongBall.getPosition().z));
             while (scaledZValueForSpeedVector + pongBall.getPosition().z <= -2.35f)
             {
                 scaledZValueForSpeedVector += 4.8f;
                 Debug.Log("Current predicted value [2]: " + (scaledZValueForSpeedVector + pongBall.getPosition().z));
             }
 
             return scaledZValueForSpeedVector + pongBall.getPosition().z;
         }
 
         // The ball is moving upwards and has to traverse across the width of the board at least once.
         if (scaledZValueForSpeedVector > 0.0f && Mathf.Abs(scaledZValueForSpeedVector) >= 4.8f)
         {
             Debug.Log("Current predicted value[3]: " + (scaledZValueForSpeedVector + pongBall.getPosition().z));
             while (scaledZValueForSpeedVector + pongBall.getPosition().z >= 2.35f)
             {
                 scaledZValueForSpeedVector -= 4.8f;
                 Debug.Log("Current predicted value[4]: " + (scaledZValueForSpeedVector + pongBall.getPosition().z));
             }
 
             return scaledZValueForSpeedVector + pongBall.getPosition().z;
         }
 
 
 
         displacementFromBallToWall = 2.35f - Mathf.Abs(pongBall.getPosition().z);
 
         if (scaledZValueForSpeedVector < 0.0f && scaledZValueForSpeedVector >= -4.8f)
         {
             scaledZValueForSpeedVector += displacementFromBallToWall;
             return -2.35f - scaledZValueForSpeedVector;
         }
 
 
         scaledZValueForSpeedVector -= displacementFromBallToWall;
         return 2.35f - scaledZValueForSpeedVector;


I do lose some accuracy because of floating-point decimal rounding, but it's adequate enough for this cause.

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

108 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

Related Questions

How to find nearby objects? 2 Answers

(SOLVED) Need help with Script that is supposed to get components of an AI and change them 1 Answer

AI Raycasting Question (Almost there!!!) 0 Answers

How to use isTrigger to spawn enemy with enemyAI script 0 Answers

How to find if there is any Gameobject between two Gameobjects (no Gameobject at vectors in the straight line joining)? 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