void Update()
 {
     if (parachuteIsOpened)
     {
         if (parachute.localScale.magnitude < parachuteStrSqale.magnitude)
         {
             parachute.localScale *= 1.0f + 5.0f * Time.deltaTime;
             for (i = 5; i < 11; i++)
             {
                 joints [i].frequency = 0f;
             }
         }
         else
         {
             parachute.localScale = parachuteStrSqale;
         }
     }
     time += Time.deltaTime;
     if (time > 100000.0f)
     {
         time = 0.0f;
     }
     for (int i = 0; i < hipSuitPoints.Length; i++)
     {
         hipSuitPoints [i].localRotation = Quaternion.Euler(hipSuitRotations [i] + suitMagnitude * Mathf.Sin(suitFrequency * time + ((float)i)) * (Mathf.PI / 2.0f) * Vector3.right);
     }
     for (int i = 0; i < armSuits.Length; i++)
     {
         armSuits [i].localRotation = Quaternion.Euler(armSuitRotations [i] + 0.75f * suitMagnitude * Mathf.Sin(suitFrequency * time + ((float)i)) * (Mathf.PI / 2.0f) * Vector3.right);
     }
     if (!posController.inAnimate)
     {
         foreach (var item in joints)
         {
             item.AnimateJoint();
         }
     }
     VelocityControl();
     if (posController.NewPoseName == "Salto" || posController.NewPoseName == "From Salto")
     {
         velocity = velocityY * Vector3.up + velocityZ * VectorOperator.getProjectXZ(velocity.normalized, true);
     }
     else if (posController.NewPoseName == "Open parachute" || (parachuteIsOpened && posController.NewPoseName == "ParachuteDown") || (parachuteIsOpened && posController.NewPoseName == "ParachuteUp") || (parachuteIsOpened && posController.NewPoseName == "Parachute right") || (parachuteIsOpened && posController.NewPoseName == "Parachute left"))
     {
         velocity = velocityY * Vector3.up - velocityZ * root.up;
         if (posController.NewPoseName == "ParachuteDown")
         {
             velocity = velocityY * Vector3.up - velocityZ * root.up * 2f;
         }
     }
     else
     {
         velocity = velocityY * Vector3.up + velocityZ * root.forward;
     }
     velocity           *= 9.0f;
     transform.position += velocity * Time.deltaTime;
     transform.Rotate(rotationY * Time.deltaTime * Vector3.up);
 }
Exemple #2
0
    // this function is doing awefully little, only works some sounds and work with the main ball
    // in here, we use reserve velocity all we want but NEVER set it
    void OnCollisionEnter(Collision collision)
    {
        // dajiang physics 2
        // we need angular velocity and real velocity for both items before.
        // we need frictions of the 2 contact surfaces (this is already known through the layerName).

        // reserveVelocity stuff is the backup, which I will NOT change in this function but only change in fixedupdate

        // we need to make sure the exit velocities of the 2 balls are perpendicular to each other
        // you can and do have an initial angular velocity, and in some cases it immediately matches with your real velocity

        // we can set a flag so we know if the real rigidbody.velocity is modified upon impact or not at each frame
        // if it has not been impacted, we will swap in the new values
        // if it has been impacted, we will apply the new value on top of it

        // velocity of the rigidbody right now is already calculated by unity for after the collision
        // if we want to update it any further (or in case of wall, not updated), we can do our calculation here.

        // angular is immediately reconciled for wall collisions and should be reconciles quickly for normal hits except for skidding (which can last some time).

        string layerName = LayerMask.LayerToName(collision.collider.gameObject.layer);

        // An important pre-condition
        // If we get a stationary ball to ball or ball to wall collision due to initial game setting, we need to ignore those collisions because they do crazy things
        if ((layerName == "Wall" || layerName == "Ball" || layerName == "MainBall") && collision.relativeVelocity.magnitude > 0.01f)
        {
            if (layerName == "Ball" || layerName == "MainBall") // ballllzzz
            {
                BallController otherBall = collision.collider.gameObject.GetComponent <BallController>();

                if (otherBall && otherBall.id < id)
                {
                    // sound portion for ball on ball
                    float b_b_volume = Mathf.Clamp01(collision.relativeVelocity.magnitude / cueController.ballMaxVelocity);
                    int   b_b_index  = 0;

                    if (b_b_volume > 0.66f)
                    {
                        b_b_index = Random.Range((int)MusicClip.B_B_Hard_0, (int)MusicClip.B_B_Hard_2 + 1);
                    }
                    else if (b_b_volume > 0.33f)
                    {
                        b_b_index = Random.Range((int)MusicClip.B_B_Mid_0, (int)MusicClip.B_B_Mid_1 + 1);
                    }
                    else
                    {
                        b_b_index = Random.Range((int)MusicClip.B_B_Weak_0, (int)MusicClip.B_B_Weak_1 + 1);
                    }

                    GameManager_script.Instance().PlaySound(b_b_index, false, b_b_volume);
                }

                // real physics stuff starts here
                if (inMove && cueController && collision.collider.GetComponent <Rigidbody>())
                {
                    Vector3 exitVelocity   = Vector3.zero;
                    float   energyRetained = 0.0f;

                    // object ball with a spline attached (risky but necessary for a successful game)
                    // has to be the first contact
                    if (otherBall.isMain && cueController.CurrentBallID == id && cueController.TargetPocketDirection != Vector3.zero)
                    {
                        // assign collision normal
                        exitVelocity = cueController.TargetPocketDirection;

                        // zero out stuff so there is no next use
                        cueController.TargetPocketDirection = Vector3.zero;
                        cueController.CurrentBallID         = -1;

                        // calculate energy retained
                        energyRetained = Vector3.Dot((cueController.currentHitBallController.reserveVelocity + cueController.cueBallController.reserveVelocity).normalized, exitVelocity.normalized);

                        //  the following are all copied from ball controller, make them into a function
                        if (energyRetained < 0.0f)
                        {
                            energyRetained += 1;
                        }

                        if (!cueController.currentHitBallController.GetComponent <Rigidbody>().isKinematic)
                        {
                            cueController.currentHitBallController.GetComponent <Rigidbody>().velocity = exitVelocity.normalized * energyRetained * (cueController.cueBallController.reserveVelocity.magnitude + cueController.currentHitBallController.reserveVelocity.magnitude);
                        }
                    }
                    // cue ball with its spline, this will always check out
                    else if (isMain && cueController.CurrentBallID == otherBall.id && cueController.CueBallBounceDirection != Vector3.zero)
                    {
                        // assign collision normal
                        exitVelocity = cueController.CueBallBounceDirection;

                        // zero out the spline
                        cueController.CueBallBounceDirection = Vector3.zero;

                        // calculate energy retained
                        energyRetained = Vector3.Dot((cueController.currentHitBallController.reserveVelocity + cueController.cueBallController.reserveVelocity).normalized, exitVelocity.normalized);

                        //  the following are all copied from ball controller, make them into a function
                        if (energyRetained < 0.0f)
                        {
                            energyRetained += 1;
                        }

                        if (!cueController.cueBallController.GetComponent <Rigidbody>().isKinematic)
                        {
                            cueController.cueBallController.GetComponent <Rigidbody>().velocity = exitVelocity.normalized * energyRetained * (cueController.cueBallController.reserveVelocity.magnitude + cueController.currentHitBallController.reserveVelocity.magnitude);
                        }
                    }
                    // all other cases of ball to ball collision
                    else
                    {
                        // we use unity built in engine for this purpose
                        exitVelocity = GetComponent <Rigidbody>().velocity;

                        // zero out stuff so there is no next use
                        cueController.TargetPocketDirection  = Vector3.zero;
                        cueController.CurrentBallID          = -1;
                        cueController.CueBallBounceDirection = Vector3.zero;

                        // calculate energy retained
                        energyRetained = exitVelocity.magnitude / (reserveVelocity.magnitude + otherBall.reserveVelocity.magnitude);

                        //  guard against negative numbers
                        if (energyRetained < 0.0f)
                        {
                            energyRetained += 1;
                        }

                        if (!GetComponent <Rigidbody>().isKinematic)
                        {
                            GetComponent <Rigidbody>().velocity = exitVelocity.normalized * energyRetained * (reserveVelocity.magnitude + otherBall.reserveVelocity.magnitude);
                        }
                    }
                }

                // some game rules, you can only first hit the current first ball
                if (cueController.firstBallBallCollisionSinceShot && otherBall != null)
                {
                    if (isMain || otherBall.isMain)
                    {
                        int tempId = 0;

                        if (isMain)
                        {
                            tempId = otherBall.id;
                        }
                        else
                        {
                            tempId = id;
                        }

                        if (cueController.currentBallControllers.Count > 1)
                        {
                            if (tempId != cueController.currentBallControllers[1].id) // first ball remaining
                            {
                                cueController.hittingTheRightFirstBall = false;
                            }
                            else
                            {
                                cueController.hittingTheRightFirstBall = true;
                            }
                        }

                        cueController.firstBallBallCollisionSinceShot = false;
                    }
                }

                cueController.contactedAtLeastOneRealBall = true;
            }

            if (layerName == "Wall" && !GetComponent <Rigidbody>().isKinematic&& !ballIsPocketed) // walllllz, should include pocket walls
            {
                // choose sound
                float b_w_volume = Mathf.Clamp01(collision.relativeVelocity.magnitude / cueController.ballMaxVelocity);
                int   b_w_index  = Random.Range((int)MusicClip.B_W_0, (int)MusicClip.B_W_1 + 1);

                // play sound
                GameManager_script.Instance().PlaySound(b_w_index, false, b_w_volume);

                // take half a ball back to avoid the risk of running into the other side of the wall before our wall, vectoroperator has things that does this as well
                Ray        ray = new Ray(GetComponent <Rigidbody>().position - cueController.ballRadius * reserveVelocity.normalized * 1.25f, reserveVelocity.normalized);
                RaycastHit hit;

                // use a common angular velocity bullshit
                Vector3 reserveXZVelocity        = VectorOperator.getProjectXZ(reserveVelocity, false);
                Vector3 reserveXZAngularVelocity = VectorOperator.getProjectXZ(reserveAngularVelocity, false);

                if (Physics.SphereCast(ray, cueController.ballRadius, out hit, 20.0f * cueController.ballRadius, cueController.wallMask))
                {
                    // make sure we only have a bounce but no pocket direction, meaning it is not a ball hit
                    if (isMain && cueController.CueBallBounceDirection != Vector3.zero && cueController.TargetPocketDirection == Vector3.zero)
                    {
                        // set the straight velocity up
                        GetComponent <Rigidbody>().velocity = Vector3.Magnitude(reserveVelocity) * Vector3.Normalize(cueController.CueBallBounceDirection);

                        // reset everything just to be sure
                        cueController.TargetPocketDirection  = Vector3.zero;
                        cueController.CurrentBallID          = -1;
                        cueController.CueBallBounceDirection = Vector3.zero;
                    }
                    else
                    {
                        // calculate linear velocity
                        GetComponent <Rigidbody>().velocity = reserveXZVelocity - 2.0f * Vector3.Project(reserveXZVelocity, VectorOperator.CleanYAxis(-hit.normal));
                        GetComponent <Rigidbody>().velocity = VectorOperator.getProjectXZ(GetComponent <Rigidbody>().velocity, true);
                    }

                    if (true)
                    {
                        // calculate angular velocity
                        Vector3 XZHitNormal = VectorOperator.CleanYAxis(-hit.normal);

                        // this declaration is f*****g retarded
                        float XAngular = reserveXZAngularVelocity.x;
                        float ZAngular = reserveXZAngularVelocity.z;

                        // z is NOT flat, so x needs to be re-calculated. Since reserve velocity x is always negative of the reserve angular z, so we add.
                        if (Mathf.Abs(XZHitNormal.x) > 0.01f)
                        {
                            ZAngular += Mathf.Abs(XZHitNormal.x) * reserveVelocity.x * 2.0f * 2.0f;                                                         // 2.0f for twice the angular, 2.0f for negation
                            ZAngular  = Mathf.Clamp(ZAngular, Mathf.Abs(reserveXZAngularVelocity.z) * -1.0f, Mathf.Abs(reserveXZAngularVelocity.z) * 1.0f); // dajiang hack, i omitted the other component, make sure ZAngular doesn't exceed the total magnitude it previously had
                        }

                        // x is NOT flat, so z needs to be re-calculated. Since reserve velocity z is always in sync with reserve angluar x, so we subtract.
                        if (Mathf.Abs(XZHitNormal.z) > 0.01f)
                        {
                            XAngular -= Mathf.Abs(XZHitNormal.z) * reserveVelocity.z * 2.0f * 2.0f;                                                         // 2.0f for twice the angular, 2.0f for negation
                            XAngular  = Mathf.Clamp(ZAngular, Mathf.Abs(reserveXZAngularVelocity.x) * -1.0f, Mathf.Abs(reserveXZAngularVelocity.x) * 1.0f); // dajiang hack, i omitted the other component, make sure XAngular doesn't exceed the total magnitude it previously had
                        }

                        GetComponent <Rigidbody>().angularVelocity = new Vector3(XAngular, 0.0f, ZAngular);
                    }

                    // add Y component of angular velocity to linear velocity and subtract itself from the angular component, dajiang hack? Donno what this is no more
                    Vector3 YAngularVelocityOnly = new Vector3(0.0f, reserveAngularVelocity.y, 0.0f);

                    // actually add and subtract angular velocities
                    GetComponent <Rigidbody>().velocity        += 0.36f * Vector3.Magnitude(YAngularVelocityOnly * 0.5f) * Vector3.Cross(VectorOperator.CleanYAxis(-hit.normal), YAngularVelocityOnly.normalized);
                    GetComponent <Rigidbody>().angularVelocity -= new Vector3(0.0f, 0.36f * reserveAngularVelocity.y, 0.0f); // this line checks out

                    // calculate restitution cooef, 1 is straight, 0 is slice
                    float impactAngle = Mathf.Clamp01(Vector3.Dot(reserveXZVelocity.normalized, VectorOperator.CleanYAxis(-hit.normal).normalized));

                    // restitution, choose wisely
                    GetComponent <Rigidbody>().velocity        = (0.96f - impactAngle * 0.24f) * GetComponent <Rigidbody>().velocity;
                    GetComponent <Rigidbody>().angularVelocity = (0.96f - impactAngle * 0.24f) * GetComponent <Rigidbody>().angularVelocity;
                }

                // only start counting the wall hits after a good ball hit, otherwise all wall hits are pointless
                if (cueController.contactedAtLeastOneRealBall)
                {
                    cueController.wallHitCount += 1;
                }
            }
        }
    }