// Copy the Current Settings to the Current Profiles Settings private void CopyCurrentSettingsToCurrentProfilesSettings() { // Update the Current Profiles Settings CProfiles.Instance().mcCurrentProfile.iLowerPitch = CSoundInput.Instance().iLowerPitchRange; CProfiles.Instance().mcCurrentProfile.iUpperPitch = CSoundInput.Instance().iUpperPitchRange; CProfiles.Instance().mcCurrentProfile.sName = CSoundInput.Instance().sProfileName; }
// Function to Automatically Update the Pitch Meter public void AutoDetectPitchAndUpdateMeter() { // If some Pitch Input was received if (CSoundInput.Instance().bInputReceived) { // Update the Pitch Indicators Position mfPitchIndicatorUnitPosition = (float)(CSoundInput.Instance().fPitch - CSoundInput.Instance().iLowerPitchRange) / (float)(CSoundInput.Instance().iUpperPitchRange - CSoundInput.Instance().iLowerPitchRange); // Make sure the new value is valid if (mfPitchIndicatorUnitPosition < 0.0f) { mfPitchIndicatorUnitPosition = 0.0f; } else if (mfPitchIndicatorUnitPosition > 1.0f) { mfPitchIndicatorUnitPosition = 1.0f; } // Record that some Pitch Input was received mbInputReceived = true; } // Else no Pitch Input was received else { mbInputReceived = false; } }
// Copy a Profiles Settings to the Current Settings public void CopyCurrentProfileSettingsToCurrentSoundInputSettings() { // Copy the given Profiles info to the Current Settings CSoundInput.Instance().iLowerPitchRange = mcCurrentProfile.iLowerPitch; CSoundInput.Instance().iOneThirdOfPitchRange = mcCurrentProfile.iLowerPitch + (int)((mcCurrentProfile.iUpperPitch - mcCurrentProfile.iLowerPitch) / 3.0f); CSoundInput.Instance().iTwoThirdsOfPitchRange = mcCurrentProfile.iLowerPitch + (int)(((mcCurrentProfile.iUpperPitch - mcCurrentProfile.iLowerPitch) / 3.0f) * 2.0f); CSoundInput.Instance().iMiddlePitchRange = mcCurrentProfile.iLowerPitch + (int)((mcCurrentProfile.iUpperPitch - mcCurrentProfile.iLowerPitch) / 2.0f); CSoundInput.Instance().iUpperPitchRange = mcCurrentProfile.iUpperPitch; CSoundInput.Instance().sProfileName = mcCurrentProfile.sName; }
// If the Low Pitch value is changed private void numericLowPitch_ValueChanged(object sender, EventArgs e) { // Get the New Low Pitch value int iNewLowPitch = (int)numericLowPitch.Value; // If the New Low Pitch is valid if ((CSoundInput.Instance().iUpperPitchRange - iNewLowPitch) >= 10) { // Record the change CSoundInput.Instance().iLowerPitchRange = iNewLowPitch; } }
// When the Detect Pitch button is pressed private void buttonDetectPitch_Click(object sender, EventArgs e) { // If we are not currently Detecting Pitch if (!mbDetectingPitch) { // Start Detecting Pitch mbDetectingPitch = true; // Reset the High and Low Pitch Values CSoundInput.Instance().iUpperPitchRange = 10; CSoundInput.Instance().iLowerPitchRange = 0; // Change Button Text buttonDetectPitch.Text = "Stop Detecting Pitch"; // Make the other controls inaccessible numericLowPitch.Enabled = false; numericHighPitch.Enabled = false; comboProfiles.Enabled = false; buttonClose.Enabled = false; buttonNewProfile.Enabled = false; buttonDeleteProfile.Enabled = false; buttonPitchTransitionExample.Enabled = false; // Reset the Pitch array to all zeros for (int i = 0; i < miaPitchHits.Length; i++) { miaPitchHits[i] = 0; } } // Else we are currently Detecting Pitch already else { // So stop Detecting Pitch mbDetectingPitch = false; // Change Button Text buttonDetectPitch.Text = "Detect Pitch"; // Make High and Low Pitch values accessible numericLowPitch.Enabled = true; numericHighPitch.Enabled = true; comboProfiles.Enabled = true; buttonClose.Enabled = true; buttonNewProfile.Enabled = true; buttonDeleteProfile.Enabled = true; buttonPitchTransitionExample.Enabled = true; } }
// Return the singleton Instance of this class public static CSoundInput Instance() { // Lock the Instance so only one thread can use it at a time lock (Lock) { // If this class Instance hasn't been created yet if (mcInstance == null) { // Create the Instance mcInstance = new CSoundInput(); } return(mcInstance); } }
// Get input from the player public void GetPDInput(bool bKeepPitchInRange) { // Clear any previous sound input, but save the Pitch from the last frame float fPreviousPitch = CSoundInput.Instance().fPitch; CSoundInput.Instance().Reset(); CSoundInput.Instance().fPitchLastFrame = fPreviousPitch; try { // Get any PD messages that might have been sent Ventuz.OSC.OscBundle cOSCBundle = mcUDPReader.ReceiveBundle(); // If there are no messages to retrieve if (cOSCBundle == null || cOSCBundle.Elements == null || cOSCBundle.Elements.Count <= 0) { // Exit the function return; } // If valid pitch input was not received yet AND there are more OSC Bundles to read while (cOSCBundle != null && !CSoundInput.mcInstance.bInputReceived) { // Read in and Store this OSC Bundles Contents ReadAndStoreOSCBundleContents(cOSCBundle, bKeepPitchInRange); // Get the next OSC Bundle in the queue cOSCBundle = mcUDPReader.ReceiveBundle(); } // Read in the any remaining Bundles to empty the queue while (cOSCBundle != null) { cOSCBundle = mcUDPReader.ReceiveBundle(); } } // Catch all exceptions catch (Exception e) { // Display the error message MessageBox.Show(e.ToString(), "ERROR"); } // Calculate how much the Pitch changed between frames CSoundInput.Instance().fPitchChange = CSoundInput.Instance().fPitch - CSoundInput.Instance().fPitchLastFrame; }
// Function to Read in and Store an OSC Bundles Contents private void ReadAndStoreOSCBundleContents(Ventuz.OSC.OscBundle cOSCBundle, bool bKeepPitchInRange) { string sInfo = ""; // Temp variable try { // Get the Elements from the PD Bundle System.Collections.ArrayList cElementList = (System.Collections.ArrayList)cOSCBundle.Elements; // Loop through all Elements recieved from PD foreach (Ventuz.OSC.OscElement cElement in cElementList) { // Loop through each of the Elements Arguments foreach (object cObject in cElement.Args) { // Check which type of message this is and store its value appropriately switch (cElement.Address.ToString()) { case "/Pitch": // Read in the Pitch float fPitch = float.Parse(cObject.ToString()); // If the Pitch is valid if (fPitch > 1.0f) { // Save that some input was received CSoundInput.Instance().bInputReceived = true; // If the Pitch should be kept in range if (bKeepPitchInRange) { // Make sure the given Pitch is within range if (fPitch < CSoundInput.Instance().iLowerPitchRange) { fPitch = CSoundInput.Instance().iLowerPitchRange; } else if (fPitch > CSoundInput.Instance().iUpperPitchRange) { fPitch = CSoundInput.Instance().iUpperPitchRange; } } // Save the Pitch value CSoundInput.Instance().fPitch = fPitch; } break; case "/Amplitude": // If this Elements Pitch was valid if (CSoundInput.Instance().bInputReceived) { // Read in and save the Amplitude value CSoundInput.Instance().fAmplitude = float.Parse(cObject.ToString()); } break; case "/Attack": // If this Elements Pitch was valid if (CSoundInput.Instance().bInputReceived) { // Read in and save the Attack value CSoundInput.Instance().bAttack = (int.Parse(cObject.ToString()) == 1) ? true : false; } break; default: MessageBox.Show("Unknown PD Address: " + cElement.Address.ToString(), "ERROR"); break; } sInfo += cElement.Address.ToString() + ":" + cObject.ToString() + " "; } } } // Catch all exceptions catch (Exception e) { // Display the error message MessageBox.Show(e.ToString(), "ERROR"); } // If valid pitch input was received if (CSoundInput.mcInstance.bInputReceived) { // Output the found values for debugging purposes // int iRow = listBox1.Items.Add(sInfo); // listBox1.SetSelected(iRow, true); Console.WriteLine(sInfo); } }
// Update the Bow And Arrow and the Arrow private void UpdateGameObjects(float fTimeSinceLastUpdateInSeconds, Graphics cBackBuffer) { // If the Player is Aiming if (meTargetPracticeState == ETargetPracticeGameStates.Aiming) { // Use the Players current Pitch as the Bow And Arrow Rotation Amount mcPitchMeter.AutoDetectPitchAndUpdateMeter(); miBowAndArrowRotation = (int)(mcPitchMeter.mfPitchIndicatorUnitPosition * -45.0f); // Save the amount of Power being used mfUnitBowAndArrowPower = ((CSoundInput.Instance().fAmplitude - 90.0f) / 20.0f); // Make sure the Power is in a valid range of Zero to One if (mfUnitBowAndArrowPower < 0.0f) { mfUnitBowAndArrowPower = 0.0f; } else if (mfUnitBowAndArrowPower > 1.0f) { mfUnitBowAndArrowPower = 1.0f; } } // Else the Arrow has been fired else { // If the Arrow is not "dead" yet if (mfResetArrowWaitTime <= 0.0f) { // Update the Arrows Velocity by Gravity mcArrowVelocity += (mcGRAVITY_ACCELERATION * fTimeSinceLastUpdateInSeconds); // Calculate the Arrows new Position mrArrow.X += (mcArrowVelocity.X * fTimeSinceLastUpdateInSeconds); mrArrow.Y += (mcArrowVelocity.Y * fTimeSinceLastUpdateInSeconds); // Get the Rotation angle of the Arrow so that it faces the direction it is travelling float fArrowRotationInRadians = 0.0f; bool bChangeRotation = true; if (mcArrowVelocity.Y < 0.0f) { fArrowRotationInRadians = (float)(Math.PI + Math.Atan(mcArrowVelocity.X / mcArrowVelocity.Y)); } else if (mcArrowVelocity.Y > 0.0f) { fArrowRotationInRadians = (float)(Math.Atan(mcArrowVelocity.X / mcArrowVelocity.Y)); } // Else the Arrow has no Y Velocity else { if (mcArrowVelocity.X > 0.0f) { fArrowRotationInRadians = (float)(Math.PI / 2.0f); } else if (mcArrowVelocity.X < 0.0f) { fArrowRotationInRadians = (float)((3.0f * Math.PI) / 2.0f); } // Else the Arrow has no X Velocity else { // Rotation is undefined, so leave rotationa as is bChangeRotation = false; } } // If the Rotation should be updated if (bChangeRotation) { // Convert the Radians to Degrees and store the result miArrowRotation = 90 - (int)(fArrowRotationInRadians * (180.0f / Math.PI)); } } // If the Arrow should be reset if (mrArrow.IntersectsWith(mrTarget) || mrArrow.X > 800 || mrArrow.Y > 485) { // If the Arrow just "died" if (mfResetArrowWaitTime == 0.0f) { // If the Arrow hit the Target if (mrArrow.IntersectsWith(mrTarget)) { // Record it as a hit mbArrowHitTarget = true; // Update the Players Score miScore++; // If the Players Score is more than their current High Score if (miScore > CProfiles.Instance().mcCurrentProfile.iScoreTargetPractice) { // Update the Players High Score and Save CProfiles.Instance().mcCurrentProfile.iScoreTargetPractice = miScore; CProfiles.Instance().SaveProfilesToFile(); } // Play the Hit sound CFMOD.PlaySound(msSoundHit, false); } // Else if the Arrow did not hit anything else if (mrArrow.X > 800 || mrArrow.Y > 485) { // Record that it was not a hit mbArrowHitTarget = false; // Reset the Players Score miScore = 0; // Play the Miss sound CFMOD.PlaySound(msSoundMiss, false); } // Reset the Arrows Velocity to zero mcArrowVelocity *= 0.0f; } // Update how long we have waited for mfResetArrowWaitTime += fTimeSinceLastUpdateInSeconds; // If we have waited long enough since the Arrow "died" if (mfResetArrowWaitTime > 1.0f) { // Reset the Arrows Position MoveArrowToBow(); // If the Arrow hit the Target if (mbArrowHitTarget) { // Create a new Target to hit MoveTargetToNewRandomLocation(); } // Reset the Arrow Wait Time mfResetArrowWaitTime = 0.0f; // Change the Game State to Aiming meTargetPracticeState = ETargetPracticeGameStates.Aiming; } } } }
// Update this form private void UpdateForm(object sender, PaintEventArgs e) { // Get a handle to this forms Graphics object so we can draw to it Graphics cGraphics = e.Graphics; // Get input from PD (audio input from player), without keeping the Pitch within range CSoundInput.Instance().GetPDInput(false); // If we should be Detecting the Pitch if (mbDetectingPitch) { // Get the Players current Pitch int iPitch = (int)CSoundInput.Instance().fPitch; // Increment the Hits on the Players current Pitch miaPitchHits[iPitch]++; // If this is the lowest Pitch heard so far and it's been hit at least 10 times if ((CSoundInput.Instance().fPitch < CSoundInput.Instance().iLowerPitchRange || CSoundInput.Instance().iLowerPitchRange <= 10) && CSoundInput.Instance().fPitch > 1.0f && miaPitchHits[iPitch] >= 10) { // Record this as the new lowest Pitch CSoundInput.Instance().iLowerPitchRange = iPitch; // If the Pitch is too low if (CSoundInput.Instance().iLowerPitchRange < 0) { CSoundInput.Instance().iLowerPitchRange = 0; } } // If this is the highest Pitch heard so far if ((CSoundInput.Instance().fPitch > CSoundInput.Instance().iUpperPitchRange || CSoundInput.Instance().iUpperPitchRange <= 10) && CSoundInput.Instance().fPitch > 1.0f && miaPitchHits[iPitch] >= 10) { // Record this as the new highest Pitch CSoundInput.Instance().iUpperPitchRange = iPitch; // If the High Pitch isn't at least 10 Pitches louder than the low if ((CSoundInput.Instance().iUpperPitchRange - CSoundInput.Instance().iLowerPitchRange) < 10) { // Increase the High Pitch to 10 Pitches louder CSoundInput.Instance().iUpperPitchRange = CSoundInput.Instance().iLowerPitchRange + 10; // If the Pitch is too high if (CSoundInput.Instance().iUpperPitchRange > 130) { CSoundInput.Instance().iUpperPitchRange = 130; } } } } // Else we are not Detecting the Pitch else { // Draw the Pitch Meter mcPitchMeter.AutoDetectPitchAndUpdateMeter(); mcPitchMeter.Draw(cGraphics); } // Show the Current Pitch textCurrentPitch.Text = CSoundInput.Instance().fPitch.ToString(); // Show the High and Low Pitch Values numericHighPitch.Value = CSoundInput.Instance().iUpperPitchRange; numericLowPitch.Value = CSoundInput.Instance().iLowerPitchRange; }
// Function to Update all of the Game Objects private void UpdateGameObjects(float fTimeSinceLastUpdateInSeconds, Graphics cBackBuffer) { // Loop through Midi Data and create new Targets if necessary int iMidiIndex = 0; int iNumberOfMidiNotes = CMidiInput.Instance().cMidiInfoList.Count; for (iMidiIndex = 0; iMidiIndex < iNumberOfMidiNotes; iMidiIndex++) { // Create a handle to the current Midi Info for readability CMidiInfo cMidiInfo = CMidiInput.Instance().cMidiInfoList[iMidiIndex]; // Filter Midi Notes based on which Music is playing // If this Midi Note is not on the Channel we want if (cMidiInfo.iChannel != mcCurrentMusic.iChannelToUse && cMidiInfo.iChannel > 0) { // Move to the next Midi Note (only keep Notes on the desired Channel) continue; } // Create a new Target CTarget cNewTarget = new CTarget(); // Specify Target Width and Height cNewTarget.rRect.Width = 70; cNewTarget.rRect.Height = 80; // Determine which Row the Target should be in // If it should be in the bottom Row if (cMidiInfo.iNote < mcCurrentMusic.iLowPitchCeiling) { cNewTarget.rRect.Y = miBOTTOM_ROW_Y; } // Else if it should be in the middle Row else if (cMidiInfo.iNote < mcCurrentMusic.iMiddlePitchCeiling) { cNewTarget.rRect.Y = miMIDDLE_ROW_Y; } // Else it should be in the top Row else { cNewTarget.rRect.Y = miTOP_ROW_Y; } // Calculate the Targets velocity based on the Midi Note's Velocity cNewTarget.sVelocity.X = cMidiInfo.iVelocity + 140; cNewTarget.sVelocity.Y = 0.0f; // 50/50 chance of Target approaching from left/right side bool bApproachFromRight = (mcRandom.Next(0, 2) == 0) ? true : false; bApproachFromRight = false; // If this Target is approaching from the Right if (bApproachFromRight) { // Reverse it's X Velocity cNewTarget.sVelocity.X = -cNewTarget.sVelocity.X; // Record that it should be Facing Left cNewTarget.bFacingLeft = true; } // Save the Targets Starting Velocity cNewTarget.sStartingVelocity = cNewTarget.sVelocity; // Calculate the Time when the Target should reach the center of the screen cNewTarget.cTimeToBeAtCenter = cMidiInfo.cTime.AddSeconds(3.0); // Calculate how long between the current Time and the time the target // should be in the middle of the screen TimeSpan cTimeSpanToReachCenter = cNewTarget.cTimeToBeAtCenter - DateTime.Now; float fTimeToReachCenter = (float)(cTimeSpanToReachCenter.TotalMilliseconds / 1000.0f); // Calculate where it should be placed to reach the middle of the screen at the desired time cNewTarget.rRect.X = (int)(miCENTER_OF_SCREEN_X - (cNewTarget.sVelocity.X * fTimeToReachCenter)) + (cNewTarget.rRect.Width / 2.0f); // Add the new Target to the Target List mcTargetList.Add(cNewTarget); } // Temp variable to keep track of which Row the Players Pitch is in ETargetRows ePlayersPitchRow; // If the Player is making a sound if (CSoundInput.Instance().bInputReceived) { // If the Song is not still loading if (mcWindowsMediaPlayer.status != "Connecting...") { // Duduct from their Score (so they don't make sounds the whole time) miScore--; } // Save which Row their Pitch corresponds to // If the Pitch corresponds to the Bottom Row if (CSoundInput.Instance().fPitch < CSoundInput.Instance().iOneThirdOfPitchRange) { ePlayersPitchRow = ETargetRows.Bottom; } // Else if the Pitch corresponds to the Middle Row else if (CSoundInput.Instance().fPitch < CSoundInput.Instance().iTwoThirdsOfPitchRange) { ePlayersPitchRow = ETargetRows.Middle; } // Else the Pitch corresponds to the Top Row else { ePlayersPitchRow = ETargetRows.Top; } } // Else no input was recieved else { ePlayersPitchRow = ETargetRows.None; } // Loop though all Targets in the Target List int iTargetIndex = 0; int iNumberOfTargets = mcTargetList.Count; for (iTargetIndex = 0; iTargetIndex < iNumberOfTargets; iTargetIndex++) { // Save a handle to this Target for readability CTarget cTarget = mcTargetList[iTargetIndex]; // Make sure the Targets Velocity will still put them at the // center of the screen at the correct time // If this target has not passed the middle of the screen yet if (cTarget.cTimeToBeAtCenter > DateTime.Now) { // Calculate how long between the current Time and the time the target // should be in the middle of the screen TimeSpan cTimeSpanToReachCenter = cTarget.cTimeToBeAtCenter - DateTime.Now; float fTimeToReachCenter = (float)(cTimeSpanToReachCenter.TotalMilliseconds / 1000.0f); // Calculate the Distance this Target is from the Center of the screen float fDistanceToCenter = miCENTER_OF_SCREEN_X - (cTarget.rRect.X + (cTarget.rRect.Width / 2.0f)); // Calculate where it should be placed to reach the middle of the screen at the desired time cTarget.sVelocity.X = fDistanceToCenter / fTimeToReachCenter; // If the Velocity should be negative and it isn't, or it should be positive and it isn't if ((cTarget.sStartingVelocity.X < 0.0f && cTarget.sVelocity.X > 0.0f) || (cTarget.sStartingVelocity.X > 0.0f && cTarget.sVelocity.X < 0.0f)) { // Make the Velocity cTarget.sVelocity.X *= -1; } } // Else it has passed the middle of the screen else { // So make sure it is using it's original velocity cTarget.sVelocity = cTarget.sStartingVelocity; } // Update the Position of this Target cTarget.rRect.X += (cTarget.sVelocity.X * fTimeSinceLastUpdateInSeconds); cTarget.rRect.Y += (cTarget.sVelocity.Y * fTimeSinceLastUpdateInSeconds); // Store which Row this Target is in ETargetRows eTargetRow; // If the Target is in the Top Row if (cTarget.rRect.Y == miTOP_ROW_Y) { eTargetRow = ETargetRows.Top; } // Else if the Target is in the Middle Row else if (cTarget.rRect.Y == miMIDDLE_ROW_Y) { eTargetRow = ETargetRows.Middle; } // Else the Target is in the Bottom Row else { eTargetRow = ETargetRows.Bottom; } // Calculate the middle position of the Target float fMiddlePosition = cTarget.rRect.X + (cTarget.rRect.Width / 2.0f); // If the Player is making a Pitch correspond to the Row this Target is in // AND the Target is in the shooting area if (ePlayersPitchRow == eTargetRow && fMiddlePosition >= miSHOOT_TARGET_AREA_LEFT && fMiddlePosition <= miSHOOT_TARGET_AREA_RIGHT) { // Give the Player some Points for hitting this Target miScore += 25; // Kill this Target by moving it off the screen cTarget.rRect.X += (cTarget.sVelocity.X * 10.0f); } } // Remove all Targets from the List which have moved off the screen mcTargetList.RemoveAll(delegate(CTarget cTarget) { // Return if the Target has moved off the screen or not yet return((cTarget.sVelocity.X > 0.0f && cTarget.rRect.X > 800) || (cTarget.sVelocity.X < 0.0f && (cTarget.rRect.X + cTarget.rRect.Width) < 0)); }); // If the Song is finished playing if (mcWindowsMediaPlayer.status == "Stopped") { // Sum the amount of time passed since the song finished playing mfSecondsSongHasBeenCompleteFor += fTimeSinceLastUpdateInSeconds; // If the Song has been finished for 7 seconds if (mfSecondsSongHasBeenCompleteFor >= 7.0f) { // Check which Song is being played switch (mcCurrentMusic.eMusic) { default: case EMusic.Simple: // Save the Players Score if it's better than their old one if (miScore > CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong1) { // Save the Players new High Score CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong1 = miScore; CProfiles.Instance().SaveProfilesToFile(); } break; case EMusic.DansMario: // Save the Players Score if it's better than their old one if (miScore > CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong2) { // Save the Players new High Score CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong2 = miScore; CProfiles.Instance().SaveProfilesToFile(); } break; case EMusic.Mario: // Save the Players Score if it's better than their old one if (miScore > CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong3) { // Save the Players new High Score CProfiles.Instance().mcCurrentProfile.iScoreShootingGallerySong3 = miScore; CProfiles.Instance().SaveProfilesToFile(); } break; } // Restart the game Reset(); } } }
// Update the Ball and Paddle private void UpdateGameObjects(float fTimeSinceLastUpdateInSeconds, Graphics cBackBuffer) { // Temp local variables int iBallXDistanceTravelled = 0; // How far the Ball has moved in the X direction int iBallYDistanceTravelled = 0; // How far the Ball has moved in the Y direction Rectangle rBallOldPosition = mrBall; // Rectangle used to test Ball against collisions Rectangle rBallCollisionRect; // Rectangle used to test Ball against collisions // Move the Pitch Meter according to any Input Pitch mcPitchMeter.AutoDetectPitchAndUpdateMeter(); // If some Pitch Input was received if (CSoundInput.Instance().bInputReceived) { // Calculate what Percent of force should be used to move the Paddle float fPercentToMove = mcPitchMeter.mfPitchIndicatorUnitPosition - 0.5f; fPercentToMove *= 2.0f; // Calculate how many pixels to move the Paddle float fAmountToMove = fPercentToMove * (-miPADDLE_MAX_SPEED_PER_SECOND * fTimeSinceLastUpdateInSeconds); // Move the Paddle mrPaddle.Y += (int)fAmountToMove; } // Calculate how far the Ball should move iBallXDistanceTravelled = (int)(mcBallDirection.X * fTimeSinceLastUpdateInSeconds); iBallYDistanceTravelled = (int)(mcBallDirection.Y * fTimeSinceLastUpdateInSeconds); // Move the Ball mrBall.X += iBallXDistanceTravelled; mrBall.Y += iBallYDistanceTravelled; // Test for collision between the Ball and the Walls // Rectangle to use to test collisions against the Ball rBallCollisionRect = mrBall; // If the Ball has travelled further than it's width or height in the last frame if (Math.Abs(iBallXDistanceTravelled) >= mrBall.Width || Math.Abs(iBallYDistanceTravelled) >= mrBall.Height) { // If the Ball is moving right if (iBallXDistanceTravelled > 0) { // If the Ball is moving down if (iBallYDistanceTravelled > 0) { rBallCollisionRect.Location = rBallOldPosition.Location; rBallCollisionRect.Width = mrBall.Right - rBallOldPosition.Left; rBallCollisionRect.Height = mrBall.Bottom - rBallOldPosition.Top; } // Else the Ball is moving up else { rBallCollisionRect.X = rBallOldPosition.X; rBallCollisionRect.Y = mrBall.Top; rBallCollisionRect.Width = mrBall.Right - rBallOldPosition.Left; rBallCollisionRect.Height = rBallOldPosition.Bottom - mrBall.Top; } } // Else the Ball is moving left else { // If the Ball is moving down if (iBallYDistanceTravelled > 0) { rBallCollisionRect.X = mrBall.Left; rBallCollisionRect.Y = rBallOldPosition.Top; rBallCollisionRect.Width = rBallOldPosition.Right - mrBall.Left; rBallCollisionRect.Height = mrBall.Bottom - rBallOldPosition.Top; } // Else the Ball is moving up else { rBallCollisionRect.Location = mrBall.Location; rBallCollisionRect.Width = rBallOldPosition.Right - mrBall.Left; rBallCollisionRect.Height = rBallOldPosition.Bottom - mrBall.Top; } } } // If the Ball hit the Top Wall if (rBallCollisionRect.IntersectsWith(mrTopWall)) { // Reverse it's Y direction mcBallDirection.Y = -mcBallDirection.Y; // Place it to be hitting the Wall (not in the Wall) mrBall.Y = mrTopWall.Bottom; // Play Sound CFMOD.PlaySound(msSoundBallBounce, false); } // If the Ball hit the Bottom Wall else if (rBallCollisionRect.IntersectsWith(mrBottomWall)) { // Reverse it's Y direction mcBallDirection.Y = -mcBallDirection.Y; // Place it to be hitting the Wall (not in the Wall) mrBall.Y = mrBottomWall.Top - mrBall.Height; // Play Sound CFMOD.PlaySound(msSoundBallBounce, false); } // If the Ball hit the Right wall if (rBallCollisionRect.IntersectsWith(mrRightWall)) { // Reverse it's X direction mcBallDirection.X = -mcBallDirection.X; // Place it to be hitting the Wall (not in the Wall) mrBall.X = mrRightWall.Left - mrBall.Width; // Play Sound CFMOD.PlaySound(msSoundBallBounce, false); } // Test for collision between the Ball and the Paddle // NOTE: Test for collision between Paddle before left wall incase ball is // travelling too fast and would pass through both if (rBallCollisionRect.IntersectsWith(mrPaddle)) { // Increase the Balls speed slightly float fSpeed = mcBallDirection.Length(); fSpeed += miBALL_SPEED_INCREMENT; // Make sure Ball does not go too fast if (fSpeed > miBALL_MAX_SPEED) { fSpeed = miBALL_MAX_SPEED; } // Reverse the Balls X direction mcBallDirection.X = -mcBallDirection.X; // Add some randomness to the Balls Y direction float fRandomness = mcRandom.Next(-25, 25); fRandomness /= 100.0f; mcBallDirection.Normalize(); mcBallDirection.Y += fRandomness; // Set the Balls speed mcBallDirection.Normalize(); mcBallDirection.Scale(fSpeed); // Place the Ball on the Paddle (not inside it) mrBall.X = mrPaddle.Right; // Play Sound CFMOD.PlaySound(msSoundBallBounce, false); } // Else if the Ball hit the Left wall else if (rBallCollisionRect.IntersectsWith(mrLeftWall)) { // Player loses a life miLives--; // If the Player is dead if (miLives == 0) { // Save the Players Score int iScore = miScore; // Restart the Game Reset(); // Restore the Players Score miScore = iScore; // Play Game Over sound CFMOD.PlaySound(msSoundGameOver, false); // Check if the Player has beat their High Score if (CProfiles.Instance().mcCurrentProfile.iScoreSpong < miScore) { // Save the Players new High Score CProfiles.Instance().mcCurrentProfile.iScoreSpong = miScore; CProfiles.Instance().SaveProfilesToFile(); } // Exit this function so the Game restarts now return; } // Play sound of losing a Ball CFMOD.PlaySound(msSoundBallDied, false); // Reset the Balls position and direction ResetBall(); // Reset the Next Ball Wait Timer mfNextBallWaitTime = 0.0f; // Enter the Wait For Next Ball state mePongState = EPongGameStates.WaitForNextBall; } // Update the Players Score miScore += (int)(fTimeSinceLastUpdateInSeconds * 1000.0f); }
// Update Game Information void UpdateGame() { // Calculate how many milliseconds have passed since the last Update int iElapsedTime = (int)mcUpdateStopwatch.ElapsedMilliseconds; mcUpdateStopwatch.Reset(); mcUpdateStopwatch.Start(); // If we should switch Games if (msTransition.bSwitchGamesNow) { // Mark that the Game has been Switched msTransition.bSwitchGamesNow = false; // Switch Games PlayGame(msTransition.eGameToSwitchTo); } // If we should calculate the FPS if (mbShowFPS) { // Update the Time and Frame count miFPSTime += iElapsedTime; miFPSFrames++; // If a second has passed if (miFPSTime > 1000) { // Subtract a second from the FPS Time miFPSTime -= 1000; // Record the FPS for the last second and reset the FPS counter miFPS = miFPSFrames; miFPSFrames = 0; } } // Get input from PD (audio input from player) CSoundInput.Instance().GetPDInput(true); // Get midi input from PD CMidiInput.Instance().GetPDInput(); // Calculate how much time has passed in seconds since the last Update float fElapsedTimeInSeconds = iElapsedTime / 1000.0f; // Update the Game mcGame.Update(fElapsedTimeInSeconds, mcBackBuffer); // If we are in a screen Transition if (msTransition.bPerfromingTransition) { float fProgress = 0.0f; // Calculate the Elapsed Time msTransition.iElapsedTime += iElapsedTime; // If the Transition should happen instantly if (msTransition.iDurationInMilliseconds == 0) { // Record that we should be at the end of the fade in/out fProgress = 1.0f; } else { // Calculate how far into the Transition we are fProgress = (float)msTransition.iElapsedTime / (float)msTransition.iDurationInMilliseconds; if (fProgress > 1.0f) { fProgress = 1.0f; } else if (fProgress == 0.0f) { fProgress = 0.0001f; } } // If we are now fading back in if (msTransition.bFadeOutComplete) { // Bug Workaround - If we are not in the Profile Settings if (mcGame.meGame != EGames.ProfileSettings) { // Reverse the progress so that we fade in instead of out fProgress = 1.0f - fProgress; } } // Calculate the Transparency to use int iOpacity = (int)(fProgress * (msTransition.fEndOpacity * 255.0f)); // Draw the Transition Brush cBrush = new SolidBrush(Color.FromArgb(iOpacity, msTransition.sColor)); mcBackBuffer.FillRectangle(cBrush, 0, 0, mcBackBufferImage.Width, mcBackBufferImage.Height); cBrush.Dispose(); // If we have faded out all the way if (fProgress == 1.0f) { // Mark that we have faded out all the way msTransition.bFadeOutComplete = true; // Reset the Elapsed time msTransition.iElapsedTime = 0; // Mark that we should Switch Games Now msTransition.bSwitchGamesNow = true; } // Else if we haved faded in all the way else if (fProgress == 0.0f) { // Stop doing the Transition msTransition.Reset(); } } // If the FPS should be shown if (mbShowFPS) { // Display the FPS Brush cBrush = new SolidBrush(Color.WhiteSmoke); mcBackBuffer.DrawString("FPS: " + miFPS.ToString(), mcFontFPS, cBrush, 1, 550); cBrush.Dispose(); } // Update FMOD CFMOD.CheckResult(CFMOD.GetSystem().update(), "FMOD Update Error"); // Update the Display by invalidating the Form this.Invalidate(); }