void OnCollisionEnter2D(Collision2D collision)
    {
        foreach (ContactPoint2D contact in collision.contacts)
            Debug.DrawRay (contact.point, contact.normal, Color.white);
        foreach (ContactPoint2D contact in collision.contacts)
        {
            if (collision.gameObject.GetComponent<Spring>() != null) {
                //must initiate from here to avoid some race condition
                collision.gameObject.GetComponent<Spring>().SpringCollide(gameObject);
                return;
            }
            if (collision.gameObject.GetComponent<Treadmill>() != null)
                return;
            if (collision.gameObject.GetComponent<Death>() != null)
                return;
            if (collision.gameObject.GetComponent<BounceAbsorption>() != null)
                absorptionFactor = collision.gameObject.GetComponent<BounceAbsorption>().absorptionFactor;
            else
                absorptionFactor = 0f;

            //more hacky code to get spiderball with moving platform working
            if (spiderball && (collision.collider.GetComponent<MovingPlatform>() != null ||
                               (collision.collider.transform.childCount > 0 &&
             				    collision.collider.transform.GetChild(0).GetComponent<MovingPlatform>() != null)))
            {
                spiderOnMovingPlatform = true;
                platformParent = collision.collider.transform;
            }

            if (Mathf.Abs(Vector2.Angle(-Physics2D.gravity, contact.normal)) < groundedThresholdAngle)
                grounded = true;

            //Determine if ball should deform
            float velocityToCheck = boostThresholdVelocity;
            if(wasGrounded)
                velocityToCheck += groundedThresholdBonus;

            if(Mathf.Abs(Vector2.Angle(contact.normal,-Physics2D.gravity)) <= boostThresholdAngle
               && Mathf.Abs (Vector2.Dot (collision.relativeVelocity,contact.normal)) > velocityToCheck
               && dState == DeformationState.Normal)
            {
                dState = DeformationState.Deforming;
                Vector2 collisionNormal = contact.normal;
                Vector2 originalVelocity = -prevVelocity;
                float originalAngularVelocity = prevAngularVelocity;
                this.rigidbody2D.isKinematic = true;//Disable normal physics
                scaleObject = new GameObject("ScaleObject");//Create a gameObject to scale the ball along an axis
                Quaternion rot = Quaternion.LookRotation(collisionNormal);//Rotate the gameObject so that z+ is towards the collision normal
                scaleObject.transform.rotation = rot;

                scaleObject.transform.position = contact.point;//Center the scaleObject at the contact point so that the ball scales from one end

                //Debug.Log ("deforming");
                //deforming onto a moving platform logic - in this case, the scale object should be child of platform
                //if (collision.gameObject.GetComponent<MovingPlatform>() != null)
                //	scaleObject.transform.parent = collision.gameObject.transform;
                if ((onMovingPlatform && Vector2.Angle(contact.normal, -Physics2D.gravity) <= 5f) || spiderOnMovingPlatform)	//odd angles cause screwiness
                {
                    //Debug.Log ("reparenting scale object");
                    scaleObject.transform.parent = platformParent;
                }
                else if (collision.gameObject.transform.childCount > 0
                         && collision.gameObject.transform.GetChild(0).GetComponent<MovingPlatform>() != null
                           && Vector2.Angle(contact.normal, -Physics2D.gravity) <= 2f)	//super-hard-coding
                {
                    //this is cheating a bit - relying on a straight collision with a horizontal platform
                    //we probably won't have any exeptional cases in the game, though, so it should be fine..(?)
                    scaleObject.transform.parent = collision.gameObject.transform;
                }

                //Parent the ball to the scaleObject
                transform.parent.parent = scaleObject.transform;
                originalScale = scaleObject.transform.localScale;
                deformTimer = 0.0f;

                originalMagnitude = originalVelocity.magnitude;
                //Calculate the reflection of originalVelocity about the collision normal to get the ball's new velocity vector
                Vector2 reflection = (2 * Vector2.Dot(originalVelocity,collisionNormal) * collisionNormal - originalVelocity);
                //Create a normalized vector representing the difference between the reflection and the original velocity
                //Vector2 bounceModifier = new Vector2(originalVelocity.x-reflection.x, -originalVelocity.y-reflection.y);
                //bounceModifier.Normalize();

                //Set the rigidbody velocity to the reflection vector and modify it to make the collision inelastic
                //outVelocity = reflection + bounceModifier/bounciness;
                outVelocity = reflection * bounciness * (1f-absorptionFactor);

                //Decrease/Reverse the angular velocity based on whether the ball changed direction on the x axis
                float angleMod = 0.5f*Mathf.Sign(-originalVelocity.x)*Mathf.Sign (outVelocity.x);

                outAngularVelocity = originalAngularVelocity*angleMod;
                //Set the scaleChange based on collision force
                deformScaleChange = Mathf.Clamp(Mathf.Abs (Vector2.Dot (collision.relativeVelocity,contact.normal))*deformScaleFactor,0.2f, 0.8f);
                deformTime = Mathf.Clamp(Mathf.Abs (Vector2.Dot (collision.relativeVelocity, contact.normal)) * deformTimeFactor, 0.02f, 0.08f);
                return;
            }
            //else if (collision.gameObject.GetComponent<MovingPlatform>() != null)
            //	transform.parent.parent = collision.gameObject.transform;	//if we aren't deforming, just do normal parenting
            //else if (onMovingPlatform)
            //	transform.parent.parent = platformParent;	//if we aren't deforming, just do normal parenting

        }
        hasContact = true;
    }
 public void ForceUndoDeformation()
 {
     if (dState == DeformationState.Deforming || dState == DeformationState.Reforming)
     {
         this.transform.parent.parent = null;
         GameObject.Destroy (scaleObject);
         this.transform.parent.localScale = Vector3.one;
         this.rigidbody2D.isKinematic = false;
     }
     dState = DeformationState.Normal;
 }
    /*
    private void recordButtonDelay()
    {
        timeSinceJump += Time.fixedDeltaTime;
        timeSinceLeft += Time.fixedDeltaTime;
        timeSinceRight += Time.fixedDeltaTime;

        if(Input.GetButtonDown("Jump"))
            timeSinceJump = 0;
        if(Input.GetButtonDown("Left"))
            timeSinceLeft = 0;
        if(Input.GetButtonDown("Right"))
            timeSinceRight = 0;
    }
    */
    void FixedUpdate()
    {
        if (grounded)
            wasGrounded = true;
        float h = Input.GetAxis ("Horizontal");

        //locks the player
        if (playerLock == true) {
            h = 0;
            jumpTimer = 0;
        }

        if(dState == DeformationState.Normal)
        {
            ListenForJump ();
            if(h != 0)
            {
                //recordButtonDelay();
                //translational movement
                if (!spiderball && !balloonActive) {
                    Vector2 relativeRight = new Vector2(-Physics2D.gravity.y, Physics2D.gravity.x).normalized;
                    if(Mathf.Sign(h) != Mathf.Sign (this.rigidbody2D.velocity.x))
                    {
                        this.rigidbody2D.AddForce(relativeRight * h * moveForce * translationStoppingMultiplier);
                    }
                    else if (Mathf.Abs(this.rigidbody2D.velocity.x) < maxPlayerGeneratedSpeed)
                    {
                        this.rigidbody2D.AddForce(relativeRight * h * moveForce);
                    }
                }
                //rotational movement
                if (Mathf.Sign (h) == Mathf.Sign (rigidbody2D.angularVelocity) && !hasContact)
                {
                    this.rigidbody2D.AddTorque(-h * moveTorque * rotationStoppingMultiplier);
                }
                else if(Mathf.Abs (this.rigidbody2D.angularVelocity) < maxAngularVelocity && !hasContact)
                {
                    this.rigidbody2D.AddTorque(-h * moveTorque);
                }
            }
        }
        else if(dState == DeformationState.Deforming)
        {// Scale ball down along z axis of scale object at deformSpeed until it's scale has changed more than the intended change
            //recordButtonDelay();
            checkJumpBoosted();

            if(deformTimer < deformTime)
            {
                deformTimer += Time.deltaTime;
                float compressScale = deformScaleChange * Mathf.Clamp (deformTimer / deformTime, 0.0f, 1.0f);
                //scaleObject.transform.localScale = new Vector3(scaleObject.transform.localScale.x,
                //                                               scaleObject.transform.localScale.y,
                //                                               1.0f - compressScale);
                scaleObject.transform.localScale = new Vector3(originalScale.x, originalScale.y, originalScale.z * (1.0f - compressScale));
            }else{
                dState = DeformationState.Reforming;
                deformTimer = 0.0f;
                //baseScale = scaleObject.transform.localScale.z;
                baseScale = scaleObject.transform.localScale;
            }
        }
        else if(dState == DeformationState.Reforming)
        {//Scale ball up along z axis of scale object at deformSpeed until it's scale has changed more than the intended change

            //recordButtonDelay();
            checkJumpBoosted();
            if(deformTimer < deformTime)
            {
                deformTimer += Time.deltaTime;
                float compressScale = deformScaleChange * Mathf.Clamp (deformTimer / deformTime, 0.0f, 1.0f);
                //scaleObject.transform.localScale = new Vector3(scaleObject.transform.localScale.x,
                //                                               scaleObject.transform.localScale.y,
                //                                               baseScale + compressScale);
                scaleObject.transform.localScale = baseScale + new Vector3(0f, 0f, originalScale.z * compressScale);
            }else{
                //Unparent from scaleObject and destroy scaleObject
                this.transform.parent.parent = null;
                GameObject.Destroy (scaleObject);
                this.transform.parent.localScale = Vector3.one;

                this.rigidbody2D.isKinematic = false;//Re-enabled rigidbody physics
                jumpLastTime = Time.timeSinceLevelLoad;

                if(jumpBoosted)
                {
                    jumpBoosted = false;
                    //timeSinceJump = boostForgiveness;
                    //timeSinceLeft = boostForgiveness;
                    //timeSinceRight = boostForgiveness;
                    //Debug.Log ("Boosted bounce");
                    outVelocity = outVelocity.normalized * originalMagnitude * boostedBounciness * (1f-absorptionFactor);

                    if(outVelocity.magnitude < (jumpForce/this.rigidbody2D.mass)*Time.fixedDeltaTime)
                    {
                        //Debug.Log("Back to original height");
                        outVelocity.Normalize();
                        outVelocity*=(jumpForce/this.rigidbody2D.mass)*Time.fixedDeltaTime;
                    }
                }
                if(jumpDepressed)
                {
                    jumpDepressed = false;
                    outVelocity = outVelocity.normalized*originalMagnitude*depressedBounciness * (1f-absorptionFactor);
                }
                if (GetComponent<Spiderball>().enabled)
                {
                    outVelocity = Vector2.zero;	//super sticky!
                }

                this.rigidbody2D.angularVelocity = outAngularVelocity;
                this.rigidbody2D.velocity = outVelocity;
                dState = DeformationState.Reformed;
                GetComponent<PlayerSoundManager>().PlaySound("Bounce");
            }
        }
        else if(dState == DeformationState.Reformed)
        {//Allow an extra tick before the ball is allowed to deform again
            dState = DeformationState.Normal;
        }

        if (!spiderball && spiderOnMovingPlatform)
        {
            spiderOnMovingPlatform = false;
        }
        if ((onMovingPlatform || spiderOnMovingPlatform) && transform.parent.parent == null)
            transform.parent.parent = platformParent;
        else if (!onMovingPlatform && !spiderOnMovingPlatform && platformParent != null)
        {
            transform.parent.parent = null;
            platformParent = null;
        }

        grounded = false;
        jumpTimer += Time.fixedDeltaTime;
        prevVelocity = this.rigidbody2D.velocity;
        prevAngularVelocity = this.rigidbody2D.angularVelocity;
        //Debug.Log (rigidbody2D.velocity.y);
    }