//this function will adjust the position of the 2 points connected by this Link to keep the distance between them
        //as the restingDistance (constraint of this link)
        public void solve()
        {
            float diffX = point1.getPosition().x - point2.getPosition().x;
            float diffY = point1.getPosition().y - point2.getPosition().y;
            //get the current distance between those 2 points
            float distance = CollisionCalculation.getDistance(point1.getPosition().x, point1.getPosition().y, point2.getPosition().x, point2.getPosition().y);

            //find the ratio of how far between the actual distance and the resting distance
            float ratioDiff = (restingDistance - distance) / distance;

            //an multiplier to make the adjustment more natural
            float stiffness = 1f;
            float scalarP1  = (0.5f) * stiffness; // mass1/(mass1+mass2) = 0.5, since for our task point have same mass
            float scalarP2  = stiffness - scalarP1;

            //move the point1 toward point2 to attain the resting distance constraint
            float newPosX = point1.getPosition().x + scalarP1 * ratioDiff * diffX;
            float newPosY = point1.getPosition().y + scalarP1 * ratioDiff * diffY;

            point1.setPosition(new Vector3(newPosX, newPosY));
            //move the point2 toward point1 to attain the resting distance constraint
            newPosX = point2.getPosition().x - scalarP2 * ratioDiff * diffX;
            newPosY = point2.getPosition().y - scalarP2 * ratioDiff * diffY;
            point2.setPosition(new Vector3(newPosX, newPosY));
        }
    //function for changing the string motion after it's collided with cannon ball (the string shouldn't intersect will cannon ball)
    //the paramters are the cannon ball and the balloon whose string is collided with, and also the position of the two end of the line segment of the string
    void movingAfterCannonBallCollision(CannonBall ball, Balloon balloon, Vector3 startPoint, Vector3 endPoint)
    {
        //find the 2 Point objects of the balloon string according to the startPoint and endPoint
        //Balloon.Point point1 = null;
        Balloon.Point point2    = null;
        ArrayList     strPoints = balloon.getStringPoints();

        for (int i = 0; i < strPoints.Count; i++)
        {
            /*
             * if( ((Balloon.Point) strPoints[i]).getPosition().Equals(startPoint))
             * {
             *  point1 = (Balloon.Point) strPoints[i];
             * }*/
            if (((Balloon.Point)strPoints[i]).getPosition().Equals(endPoint))
            {
                point2 = (Balloon.Point)strPoints[i];
            }
        }


        Vector2 unitNormal = CollisionCalculation.getNormal(startPoint.x, startPoint.y, point2.getPosition().x, point2.getPosition().y); //calculate the unit normal of the line
        float   epsilon    = 0.1f;                                                                                                       //the coefficient of restitution (0~1, when it's 1 we have perfect bouncing)
        float   mass       = 1f;                                                                                                         //mass of the string

        float VnCollided = unitNormal.x * ball.getVelocity().x + unitNormal.y * ball.getVelocity().y;                                    //Vn-: the normal component of collided velocity = dot product of normal and velocity

        float   j       = -(1 + epsilon) * mass * VnCollided;                                                                            //the impulse scalar j = -(1+epsilon) * m * Vn-
        Vector2 impulse = -j * unitNormal;                                                                                               //the force will apply to the line, not the cannon ball, so we use negative of the impulse

        point2.setAcceleration((impulse / mass));                                                                                        //update the acceleration based on the impulse
    }
    //this function will handle the collision between terrain and ballon
    void handleBalloonTerrainCollision(Balloon b, Vector3[] terrainLinePoints)
    {
        Vector3[] bodyPositions   = b.getBodyLinePositions();
        Vector3[] stringPositions = b.getStringLinePositions();
        for (int j = 0; j < terrainLinePoints.Length - 1; j++)
        {
            //iterate through the Points to check if the cannon ball collided any line segment of the balloon body
            for (int i = 0; i < bodyPositions.Length - 1; i++)
            {
                //check if the Point of balloon is collided with any terrain line segment

                //if the balloon is collided with terrain
                //if (CollisionCalculation.isPointOnLine(bodyPositions[i].x, bodyPositions[i].y, terrainCollisionPoints[j].x, terrainCollisionPoints[j].y, terrainCollisionPoints[j + 1].x, terrainCollisionPoints[j + 1].y))
                if (CollisionCalculation.isCircleCollidesLine(terrainCollisionPoints[j].x, terrainCollisionPoints[j].y, terrainCollisionPoints[j + 1].x, terrainCollisionPoints[j + 1].y, bodyPositions[i].x, bodyPositions[i].y, 0.05f))
                {
                    //handle the collision
                    movingAfterLineCollision(b, bodyPositions[i], terrainCollisionPoints[j], terrainCollisionPoints[j + 1]);
                }
            }

            //check if the Point of string is collided with any terrain line segment
            for (int i = 0; i < stringPositions.Length - 1; i++)
            {
                //if the string is collided with terrain
                if (CollisionCalculation.isCircleCollidesLine(terrainCollisionPoints[j].x, terrainCollisionPoints[j].y, terrainCollisionPoints[j + 1].x, terrainCollisionPoints[j + 1].y, stringPositions[i].x, stringPositions[i].y, 0.05f))
                {
                    //handle the collision
                    movingAfterLineCollision(b, stringPositions[i], terrainCollisionPoints[j], terrainCollisionPoints[j + 1]);
                }
            }
        }
    }
    //function for changing the balloon point motion after it's collided with line (the balloon Point shouldn't intersect will terrain)
    //the paramters are the balloon and the points of a line which the balloon is collided with, and also the position of the two end of the line segment
    void movingAfterLineCollision(Balloon balloon, Vector3 collidedPoint, Vector3 lineStart, Vector3 lineEnd)
    {
        //find the 2 Point objects of the balloon string according to the startPoint and endPoint
        //Balloon.Point point1 = null;
        Balloon.Point cPoint     = null;
        ArrayList     strPoints  = balloon.getStringPoints();
        ArrayList     bodyPoints = balloon.getBodyPoints();

        //iterate to find the contact point
        for (int i = 0; i < strPoints.Count; i++)
        {
            if (((Balloon.Point)strPoints[i]).getPosition().Equals(collidedPoint))
            {
                cPoint = (Balloon.Point)strPoints[i];
            }
        }
        for (int i = 0; i < bodyPoints.Count; i++)
        {
            if (((Balloon.Point)bodyPoints[i]).getPosition().Equals(collidedPoint))
            {
                cPoint = (Balloon.Point)bodyPoints[i];
            }
        }


        Vector2 unitNormal = CollisionCalculation.getNormal(lineStart.x, lineStart.y, lineEnd.x, lineEnd.y);            //calculate the unit normal of the line segment
        float   epsilon    = 1f;                                                                                        //the coefficient of restitution (0~1, when it's 1 we have perfect bouncing)
        float   mass       = 0.1f;                                                                                      //mass of the string

        float VnCollided = unitNormal.x * cPoint.getMovingDirection().x + unitNormal.y * cPoint.getMovingDirection().y; //Vn-: the normal component of collided velocity = dot product of normal and velocity
        float multiplier = 30f;

        float   j       = -(1 + epsilon) * mass * -VnCollided * multiplier; //the impulse scalar j = -(1+epsilon) * m * Vn-
        Vector2 impulse = -j * unitNormal;                                  //the force will apply to the line, not the cannon ball, so we use negative of the impulse

        foreach (Balloon.Point p in bodyPoints)
        {
            p.setAcceleration((impulse / mass));  //update the acceleration based on the impulse
        }
        foreach (Balloon.Point p in strPoints)
        {
            p.setAcceleration((impulse / mass));  //update the acceleration based on the impulse
        }

        //cPoint.setAcceleration((impulse / mass));  //update the acceleration based on the impulse
    }
    //function for the bouncing solution of collison, taking a ball and a line represented by two points
    //as parameters
    void bouncingAfterTerrainCollision(CannonBall ball, float x1, float y1, float x2, float y2)
    {
        //calculate bouncing velocity using the formula V+ = V- + dotProduct(j,n)/m,
        //where V- is the velocity when colliding, V+ is the velocity after colliding,
        //dotProduct(j,n) = J which is the impulse, and j = -(1+epsilon) * m * Vn- where
        //Vn- = dotProduct(V-,n).

        Vector2 unitNormal = CollisionCalculation.getNormal(x1, y1, x2, y2);                          //calculate the unit normal of the line
        float   epsilon    = 0.55f;                                                                   //the coefficient of restitution (0~1, when it's 1 we have perfect bouncing)
        float   mass       = 1f;                                                                      //mass of the ball

        float VnCollided = unitNormal.x * ball.getVelocity().x + unitNormal.y * ball.getVelocity().y; //Vn-: the normal component of collided velocity = dot product of normal and velocity

        float   j       = -(1 + epsilon) * mass * VnCollided;                                         //the impulse scalar j = -(1+epsilon) * m * Vn-
        Vector2 impulse = j * unitNormal;                                                             //J

        ball.addVelocity(impulse / mass);                                                             //update the velocity based on the impulse (V+ = V- + impulse/mass)
    }
    //function to detect and handle collision bewtween cannon ball and collision lines (water, terrain and balloons)
    //taking one cannon ball and an array of points of the line (line with corners) as paramters, detect the collsion
    void handleCannonBallCollision(CannonBall ball, Vector3[] linePoints, ColliderType type)
    {
        GameObject ballObject = ball.GetGameObject();

        //check that if any line segment of the line is collided with the cannon ball
        for (int i = 0; i < linePoints.Length - 1; i++)
        {
            //if the line which the ball is colliding with is terrain
            if (type == ColliderType.TERRAIN)
            {
                // if the cannon ball is collided with the line
                if (CollisionCalculation.isCircleCollidesLine(linePoints[i].x, linePoints[i].y, linePoints[i + 1].x, linePoints[i + 1].y, ballObject.transform.position.x, ballObject.transform.position.y, ball.getRadius()))
                {
                    //if the ball is colliding with horizontal ground
                    if (linePoints[i].y - linePoints[i + 1].y == 0)
                    {
                        //apply an inverse acceleration to the gravity to cancel out the gravity
                        ball.updateVelocity(Time.deltaTime, new Vector2(0, -gravity));
                        //apply a friction to the ball when rolling on horizontal ground
                        applyFrictionOfGround(ball);
                    }
                    else  //when the ball is not colliding with the horizontal terrain, push it back by a small amount to avoid triggering continuous collision detection
                    {
                        //push the ball away from the terrain line in its normal vector direction by a small
                        //amount to avoid penetration
                        Vector2 unitNormal = CollisionCalculation.getNormal(linePoints[i].x, linePoints[i].y, linePoints[i + 1].x, linePoints[i + 1].y);
                        ball.translatePosition(Time.deltaTime, unitNormal * 1);
                    }

                    //handle the collision on terrain
                    bouncingAfterTerrainCollision(ball, linePoints[i].x, linePoints[i].y, linePoints[i + 1].x, linePoints[i + 1].y);
                }
            }
            else  //if the line which the ball is colliding with is water
            {
                // if the cannon ball is collided with the line
                if (CollisionCalculation.isCircleCollidesLine(linePoints[i].x, linePoints[i].y, linePoints[i + 1].x, linePoints[i + 1].y, ballObject.transform.position.x, ballObject.transform.position.y, ball.getRadius()))
                {
                    //handle the collision on water
                    disappearAfterWaterCollision(ball, cannonBallsList);
                }
            }
        }
    }
    //this function will handle the collision between cannon ball and any ballon body
    void handleBalloonCollision(CannonBall cb, ArrayList balloonList)
    {
        //vectors that store the position of points that construct the balloons
        Vector3[] bodyPositions;
        Vector3[] stringPositions;
        //get every ballon as line segment
        for (int k = 0; k < balloonsList.Count; k++)
        {
            bodyPositions   = ((Balloon)balloonsList[k]).getBodyLinePositions();
            stringPositions = ((Balloon)balloonsList[k]).getStringLinePositions();

            //iterate through the Points to check if the cannon ball collided any line segment of the balloon string
            for (int i = 0; i < stringPositions.Length - 1; i++)
            {
                // if the cannon ball is collided with the line segment of a balloon string
                if (CollisionCalculation.isCircleCollidesLine(stringPositions[i].x, stringPositions[i].y, stringPositions[i + 1].x, stringPositions[i + 1].y, cb.GetGameObject().transform.position.x, cb.GetGameObject().transform.position.y, cb.getRadius()))
                {
                    //handle the collision by moving the string to avoid intersecting with the cannon ball
                    movingAfterCannonBallCollision(cb, ((Balloon)balloonsList[k]), stringPositions[i], stringPositions[i + 1]);
                }
            }

            //iterate through the Points to check if the cannon ball collided any line segment of the balloon body
            for (int i = 0; i < bodyPositions.Length - 1; i++)
            {
                // if the cannon ball is collided with the line segment of a balloon body
                if (CollisionCalculation.isCircleCollidesLine(bodyPositions[i].x, bodyPositions[i].y, bodyPositions[i + 1].x, bodyPositions[i + 1].y, cb.GetGameObject().transform.position.x, cb.GetGameObject().transform.position.y, cb.getRadius()))
                {
                    //handle the collision by destroy the balloon which has been collided
                    destroyAfterCannonBallCollision(((Balloon)balloonsList[k]), balloonList);

                    break; //break since the balloon with current positions array is destroyed, so no further check has to be made
                }
            }
        }
    }
    //the Balloon class will take a Line gameObject and a spawnPosition for the balloon as parameter
    public Balloon(GameObject balloonBodyLine, GameObject balloonStringLine, Vector3 spawnPosition)
    {
        balloonBody   = balloonBodyLine;
        balloonString = balloonStringLine;

        //our balloon will have six points for the body (one point is connecting to the string)
        //and 4 points for the string (one point is the body-string connecting point)
        //The spawnPosition will be the position of the top motorPoint of this balloon.
        //      w1=w2
        //       |
        //       v
        //        .
        // h1->  / \
        // h2-> |   |
        // h1->  \ /
        //        |
        //        |
        //        |
        //
        // The invisible Links between points to keep the balloon in shape are designed in a separate PDF file

        //Create Points:
        //define some distance for the balloon shape
        float h1     = 0.125f; //0.0625f  0.125f  0.10525f
        float h2     = 0.25f;
        float w1     = 0.2105f;
        float strLen = 0.15f;
        //balloon body points
        Point topP = new Point(spawnPosition);

        motorPoint = topP;
        Point leftP1  = new Point(new Vector3(spawnPosition.x - w1, spawnPosition.y - h1));
        Point rightP1 = new Point(new Vector3(spawnPosition.x + w1, spawnPosition.y - h1));
        Point leftP2  = new Point(new Vector3(leftP1.getPosition().x, leftP1.getPosition().y - h2));
        Point rightP2 = new Point(new Vector3(rightP1.getPosition().x, rightP1.getPosition().y - h2));
        Point botP    = new Point(new Vector3(spawnPosition.x, spawnPosition.y - 2 * h1 - h2));
        //string points
        Point str1 = new Point(new Vector3(spawnPosition.x, botP.getPosition().y - strLen));
        Point str2 = new Point(new Vector3(spawnPosition.x, str1.getPosition().y - strLen));
        Point str3 = new Point(new Vector3(spawnPosition.x, str2.getPosition().y - strLen));
        Point str4 = new Point(new Vector3(spawnPosition.x, str3.getPosition().y - strLen));


        //Add all body points into array list in loop order, first element will connected with the last element later
        //the first element is the connecting point between balloon body and the string
        balloonBodyPoints.Add(botP);
        balloonBodyPoints.Add(leftP2);
        balloonBodyPoints.Add(leftP1);
        balloonBodyPoints.Add(topP);
        balloonBodyPoints.Add(rightP1);
        balloonBodyPoints.Add(rightP2);
        //Add all string points into array list, the first point in the arrayList will be connected to the first point in the
        //balloon body arrayList
        balloonStringPoints.Add(str1);
        balloonStringPoints.Add(str2);
        balloonStringPoints.Add(str3);
        balloonStringPoints.Add(str4);


        //Use Line object to draw the ballon shape:
        Vector3[] bodyPoints = new Vector3[6];
        for (int i = 0; i < balloonBodyPoints.Count; i++)
        {
            bodyPoints[i] = ((Point)balloonBodyPoints[i]).getPosition();
        }
        //we have to connect the last point with the fist point
        //bodyPoints[6] = ((Point)balloonBodyPoints[0]).getPosition();
        bodyLineRenderer = balloonBodyLine.GetComponent <LineRenderer>();
        bodyLineRenderer.positionCount     = bodyPoints.Length; //set the number of vertices this line have, including two end of the line
        bodyLineRenderer.numCornerVertices = 6;                 //higher value will smooth the corner
        //draw the balloon body
        bodyLineRenderer.SetPositions(bodyPoints);

        //Use Line object to draw the string shape attached to the balloon:
        Vector3[] stringPoints = new Vector3[5];
        //the first point of the string is the connecting point to the balloon body
        stringPoints[0] = ((Point)balloonBodyPoints[0]).getPosition();
        for (int i = 1; i < stringPoints.Length; i++)
        {
            stringPoints[i] = ((Point)balloonStringPoints[i - 1]).getPosition();
        }
        stringLineRenderer = balloonStringLine.GetComponent <LineRenderer>();
        stringLineRenderer.positionCount     = stringPoints.Length; //set the number of vertices this line have, including two end of the line
        stringLineRenderer.numCornerVertices = 6;                   //higher value will smooth the corner
        //draw the string
        stringLineRenderer.SetPositions(stringPoints);


        //add constraints as links to keep the hexagon convex
        float crossLength = h2 / Mathf.Sin(30 * Mathf.PI / 180);  //the length between two opposite angles of this hexagon

        leftP1.addLink(rightP2, crossLength);
        leftP2.addLink(rightP1, crossLength);
        topP.addLink(botP, crossLength);
        botP.addLink(topP, crossLength);
        rightP2.addLink(leftP1, crossLength);
        rightP1.addLink(leftP2, crossLength);

        //add constraints as links for the length between each vertices of the balloon (hexagon)
        topP.addLink(leftP1, h2);
        leftP1.addLink(topP, h2);
        leftP1.addLink(leftP2, h2);
        leftP2.addLink(leftP1, h2);
        leftP2.addLink(botP, h2);
        botP.addLink(leftP2, h2);
        botP.addLink(rightP2, h2);
        rightP2.addLink(botP, h2);
        rightP2.addLink(rightP1, h2);
        rightP1.addLink(rightP2, h2);
        rightP1.addLink(topP, h2);
        topP.addLink(rightP1, h2);


        //add constraints as Links for the points of this balloon string (constraints are shown in the separate PDF file)
        float str_balloonAngle = 120 * Mathf.PI / 180;

        //str1.addLink(leftP2, CollisionCalculation.cosineFormula(str1.getPosition(), botP.getPosition(), leftP2.getPosition(), str_balloonAngle));
        botP.addLink(str1, strLen);
        str1.addLink(botP, strLen);
        str1.addLink(str2, strLen);
        str2.addLink(str1, strLen);
        str2.addLink(str3, strLen);
        str3.addLink(str2, strLen);
        str3.addLink(str4, strLen);
        str4.addLink(str3, strLen);

        //botP.addLink(str2, 2*strLen);
        //str2.addLink(botP, 2*strLen);


        str2.addLink(leftP2, CollisionCalculation.cosineFormula(str2.getPosition(), botP.getPosition(), leftP2.getPosition(), str_balloonAngle));
        leftP2.addLink(str2, CollisionCalculation.cosineFormula(str2.getPosition(), botP.getPosition(), leftP2.getPosition(), str_balloonAngle));

        str2.addLink(rightP2, CollisionCalculation.cosineFormula(str2.getPosition(), botP.getPosition(), rightP2.getPosition(), str_balloonAngle));
        rightP2.addLink(str2, CollisionCalculation.cosineFormula(str2.getPosition(), botP.getPosition(), rightP2.getPosition(), str_balloonAngle));
    }