Search Unity

Curving a ball in motion using physics

Discussion in 'Physics' started by Migzro, Feb 15, 2015.

  1. Migzro

    Migzro

    Joined:
    Mar 19, 2014
    Posts:
    9
    I am trying to create a soccer game where the user should draw a line/curve on the screen, and the ball should follow that path to score a goal.
    It is working as intended, but If the the path is curved, the ball should follow that curved path using physics, but I am not able to achieve this effect.

    First, I capture the touches from the user, interpolate them to make a smooth line/curve. I tried using splines and bezier curves, but found out that interpolation was the easiest and most accurate way for me as it was hard to determine the control points accurately for the spline and bezier curves.

    Screen Shot 2015-02-15 at 8.11.22 PM.png

    The line in pink is the path the user drew, and the line blue is the line is the interpolated touches I calculated (All the touches data are accurate and tested).

    Secondly, I send all the touches data (interpolated and non interpolated) in both screen and world space to a script that adds all the forces required to shoot the ball.

    I tried everything possible in order to make the ball curve in a realistic way, the most promising result came from applying Magnus effect to the ball by using its angular velocity. When using preset values for the angular velocity, the ball does curve. I tried adding torque to rigid body of the ball, and then calculate the Magnus effect from the resulting angular velocity but its not curving correctly.

    This is the code for the PhysicsShooter script

    Code (CSharp):
    1. public class PhysicsShooter2 : MonoBehaviour {
    2.  
    3.     // Use this for initialization
    4.     private bool startShoot = true;
    5.     private Rigidbody rb;
    6.     private static float INITIAL_BALL_VELOCITY = 10.0f;
    7.     private Vector3 initialPosition;
    8.  
    9.     public List <Vector2> allTouches;
    10.     public List <Vector2> allTouchesInterpolated;
    11.     public List <Vector3> worldTouches;
    12.     public List <Vector3> worldTouchesInterpolated;
    13.  
    14.     [Range (0, 1)]
    15.     public float VELOCTIY_FACTOR = 0.2f;
    16.  
    17.     [Range (0, 500)]
    18.     public float TORQUE_FACTOR = 400f;
    19.  
    20.     public Vector3 angularV;
    21.     private float magnusConst = 0.005f;
    22.  
    23.     void Start ()
    24.     {
    25.         startShoot = false;
    26.         rb = gameObject.rigidbody;
    27.         initialPosition = transform.position;
    28.     }
    29.  
    30.     // Update is called once per frame
    31.     void FixedUpdate()
    32.     {
    33.         if(startShoot)
    34.         {
    35.             for (int i = 1; i<worldTouchesInterpolated.Count; i++)
    36.             {
    37.                 Vector3 forceDirection = worldTouchesInterpolated[i] - worldTouchesInterpolated[i-1];
    38.  
    39.                 rigidbody.AddTorque (new Vector3 (0, forceDirection.magnitude * TORQUE_FACTOR * Time.fixedDeltaTime, 0));
    40.  
    41.                 Vector3 magnusVector = magnusConst * Vector3.Cross (rigidbody.velocity, rigidbody.angularVelocity) ;
    42.                 rigidbody.AddForce (magnusVector, ForceMode.Force);
    43.             }
    44.             startShoot = false;
    45.         }
    46.     }
    47.  
    48.     public void SetData (List<Vector2> allTouches, List<Vector2> allTouchesInterpolated, List<Vector3> worldTouches, List<Vector3> worldTouchesInterpolated)
    49.     {
    50.         this.allTouches = allTouches;
    51.         this.allTouchesInterpolated = allTouchesInterpolated;
    52.         this.worldTouches = worldTouches;
    53.         this.worldTouchesInterpolated = worldTouchesInterpolated;
    54.  
    55.         // add a vertical force on the ball dependant on the flick length (need to calculate the flick length in relation to screen)
    56.         rb.AddForceAtPosition (new Vector3 (0, 200, 0), transform.position, ForceMode.Force);
    57.  
    58.         // Adding initial velocity to the ball according to the flick angle to ensure it always reaches the goal
    59.         Vector3 shotDirection = worldTouchesInterpolated [3] - worldTouchesInterpolated [0];
    60.         shotDirection = shotDirection.normalized;
    61.         shotDirection *= INITIAL_BALL_VELOCITY;
    62.         shotDirection.y = 0;
    63.         rb.velocity = shotDirection;
    64.         startShoot = true;
    65.     }
    66.  
    67.     public void ResetShot()
    68.     {
    69.         transform.position = initialPosition;
    70.         startShoot = false;
    71.         rb.velocity = Vector3.zero;
    72.         rb.angularVelocity = Vector3.zero;
    73.     }
    74.  
    75.     public void StopShot()
    76.     {
    77.         startShoot = false;
    78.     }
    79. }
    All the forces added on the ball take place in the SetData function and the Magnus force is applied in the FixedUpdate function.

    Any help/guidance would be appreciated.
    Thanks

    P.S. this script is completely experimental, I only uploaded it to show how I am trying to calculate the torque/angular velocity which is completely bonkers in its current state :D
     
    Last edited: Feb 15, 2015