/// <summary> /// Evalute sphere physics, generate new velocities based on collisions, and update /// sphere positions /// </summary> protected void UpdateSpheres(GameTime gameTime) { Vector3 gravity = Vector3.UnitY * -4.0f; float shakeForce = 1.0f; // Tilt limit const float limit = 0.85f; // Tilt offset that determines where 'flat' const float tiltoffset = 0.76f; double accelReadingZ; double accelReadingY; float elapsedGameTime = (float)gameTime.ElapsedGameTime.TotalSeconds; // Read the current state of the accelerometer Vector3 currentAccelerometerReading = Accelerometer.GetState().Acceleration; // We need to reverse the accelerometer reading for the y axis depending on orientation if (Window.CurrentOrientation == DisplayOrientation.LandscapeLeft) { currentAccelerometerReading.Y = -currentAccelerometerReading.Y; } // Compute accelerometer magnitude Vector3 accelMag = Vector3.Zero; accelMag = currentAccelerometerReading; float newMag = accelMag.Length(); // Detect a shake gesture. Search for a peak that is > 1.3f in magnitude. if (accelhistory[1] > 1.3f && accelhistory[0] < accelhistory[1] && accelhistory[1] > newMag) { // Compute shake force shakeForce += 10.0f * (accelhistory[1] - 1.3f) / 3.5f; } // MRU cache for accelerometer magnitudes accelhistory[0] = accelhistory[1]; accelhistory[1] = newMag; // Read accelerometer Z and Y, which will be used for modifying gravity accelReadingZ = currentAccelerometerReading.Z; accelReadingY = currentAccelerometerReading.Y; // Limit the rotation based on accelerometer float rotateX = Math.Max(Math.Min((float)-(accelReadingZ + tiltoffset), limit), -limit); float rotateY = Math.Max(Math.Min((float)accelReadingY, limit), -limit); // Rotate gravity vector based on accelerometer input Matrix rotationToBeDone = Matrix.CreateRotationX(rotateX * MathHelper.PiOver2); Matrix rotationToBeDone2 = Matrix.CreateRotationZ(rotateY * MathHelper.PiOver2); gravity = Vector3.Transform(gravity, rotationToBeDone); gravity = Vector3.Transform(gravity, rotationToBeDone2); // Update positions, add air friction and gravity for (int i = 0; i < numSpheres; i++) { Sphere mySphere = spheres[i]; mySphere.Position += mySphere.Velocity * elapsedGameTime * 0.99f; // Apply accelleration due to gravity mySphere.Velocity += gravity * elapsedGameTime; } // Resolve sphere-sphere collisions for (int i = 0; i < numSpheres; i++) { for (int j = i + 1; j < numSpheres; j++) { SphereCollisionImplicit(spheres[i], spheres[j]); } } // Resolve collisions with floor for (int i = 0; i < numSpheres; i++) { Sphere mySphere = spheres[i]; if (mySphere.Position.Y < floorPlaneHeight + mySphere.Radius) { // subtract out pre-accelerated gravity first mySphere.Velocity -= gravity * elapsedGameTime; // apply shake force if (shakeForce > 1.0f) { // Add some upward momentum mySphere.Velocity.Y += 0.1f; // Compute current speed float speed = mySphere.Velocity.Length(); // Limit new speed float speedadjust = speed; speedadjust = Math.Min(speed, 4.0f); speedadjust = Math.Max(speed, 2.0f); // normalize mySphere.Velocity *= 1.0f / speed; // accellerate based on shake force mySphere.Velocity *= speedadjust * shakeForce; } mySphere.Position.Y = floorPlaneHeight + mySphere.Radius; if (mySphere.Velocity.Y < 0) { // Determine "complete rest" if (mySphere.Velocity.Y > (gravity.Y * elapsedGameTime * 2.0f) && mySphere.Velocity.LengthSquared() < (0.5 * 0.5)) { mySphere.Velocity.Y = 0.0f; } else // Otherwise, bounce. { mySphere.Velocity.Y = -mySphere.Velocity.Y * collisionDamping; } } } // Resolves collisions with walls if (mySphere.Position.X < -worldSize + mySphere.Radius) { mySphere.Position.X = -worldSize + mySphere.Radius; if (mySphere.Velocity.X < 0) { mySphere.Velocity.X = -mySphere.Velocity.X * collisionDamping; } } if (mySphere.Position.X > worldSize - mySphere.Radius) { mySphere.Position.X = worldSize - mySphere.Radius; if (mySphere.Velocity.X > 0) { mySphere.Velocity.X = -mySphere.Velocity.X * collisionDamping; } } if (mySphere.Position.Z < -worldSize + mySphere.Radius) { mySphere.Position.Z = -worldSize + mySphere.Radius; if (mySphere.Velocity.Z < 0) { mySphere.Velocity.Z = -mySphere.Velocity.Z * collisionDamping; } } if (mySphere.Position.Z > worldSize - mySphere.Radius) { mySphere.Position.Z = worldSize - mySphere.Radius; if (mySphere.Velocity.Z > 0) { mySphere.Velocity.Z = -mySphere.Velocity.Z * collisionDamping; } } } }