using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using WaveLib;
using System.IO;
using System.Threading;
using Microsoft.DirectX.AudioVideoPlayback;
using System.Reflection;
namespace MusicRider
{
public class MusicRiderGame : Microsoft.Xna.Framework.Game
{
private enum GameMode
{
FileSelection,
Playing,
GameOver,
Processing,
Menu
}
private enum WaveMode
{
Mono = 0,
Stereo = 1
}
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont menuItemFont, browseFont, bigFont;
GameMode currentMode;
WaveMode currentWaveMode = WaveMode.Mono;
Texture2D haloBall, haloPlayer, haloSpiral;
Texture2D logo;
String recordsFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
public MusicRiderGame()
{
graphics
= new GraphicsDeviceManager
(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch
= new SpriteBatch
(GraphicsDevice
);
menuItemFont = Content.Load<SpriteFont>("Forte18");
browseFont = Content.Load<SpriteFont>("Arial16");
bigFont = Content.Load<SpriteFont>("Addiel44");
haloBall = Content.Load<Texture2D>("Halo3");
haloPlayer = Content.Load<Texture2D>("Halo2");
haloSpiral = Content.Load<Texture2D>("HaloSpiral");
logo = Content.Load<Texture2D>("MusicRider");
currentMode = GameMode.Menu;
player.Sprite = haloPlayer;
player.Color = Color.White;
notes
= new List
<GameObject
>();
timedFloatingBonuses
= new List
<FloatingText
>();
if (File.Exists(recordsFolder + "\\records.dat"))
records = ScoreTable.Load(recordsFolder + "\\records.dat");
if (records == null)
records
= new ScoreTable
();
Properties.Settings.Default.Reload();
Vector2 res = Properties.Settings.Default.Resolution;
this.graphics.PreferredBackBufferWidth = (int)res.X;
this.graphics.PreferredBackBufferHeight = (int)res.Y;
this.GraphicsDevice.PresentationParameters.BackBufferWidth = (int)res.X;
this.GraphicsDevice.PresentationParameters.BackBufferHeight = (int)res.Y;
this.graphics.ApplyChanges();
menuItems[1] = String.Format("Risoluzione: {0:N0}x{1:N0}", res.X, res.Y);
menuItems[3] = "Gameplay: " + GetDifficulty(Properties.Settings.Default.Difficulty);
if (Properties.Settings.Default.Fullscreen)
{
this.graphics.ToggleFullScreen();
menuItems[2] = "Visualizzazione: Schermo intero";
}
else
menuItems[2] = "Visualizzazione: Finestra";
currentWaveMode = (WaveMode)Properties.Settings.Default.Mode;
if (currentWaveMode == WaveMode.Mono)
menuItems[4] = "Modalità: Mono";
else
menuItems[4] = "Modalità: Stereo";
}
protected override void UnloadContent()
{
if (music != null)
{
try { music.Stop(); music.Dispose(); }
catch { }
}
foreach (String file in filesDump)
File.Delete(file);
}
#region "Elaborazione onda"
Wave currentWave;
FileStream audioData;
Thread temp;
String waveFileName, fasterWaveFileName, slowerWaveFileName;
float completePercentage = 0;
float speedChangeFactor = 1.0f;
private void CreateSlowerAndFasterWaves()
{
fasterWaveFileName = String.Format("{0}\\{1} (faster).wav", Path.GetDirectoryName(waveFileName), Path.GetFileNameWithoutExtension(waveFileName));
slowerWaveFileName = String.Format("{0}\\{1} (slower).wav", Path.GetDirectoryName(waveFileName), Path.GetFileNameWithoutExtension(waveFileName));
if (File.Exists(fasterWaveFileName) && File.Exists(slowerWaveFileName))
return;
Wave tmp
= new Wave
(waveFileName,
false);
Int32 originalSampleRate = tmp.SampleRate;
tmp.ChangeSampleRate((int)(originalSampleRate * 0.6));
tmp.Save(slowerWaveFileName);
tmp.ChangeSampleRate((int)(originalSampleRate * 1.4));
tmp.Save(fasterWaveFileName);
tmp.Dispose();
filesDump.Add(fasterWaveFileName);
filesDump.Add(slowerWaveFileName);
}
private FileStream CreateMonoAudioFile(String dataFilePath)
{
FileStream stream
= new FileStream
(dataFilePath, FileMode.
Create);
BinaryWriter writer
= new BinaryWriter
(stream
);
Int32 duration = (int)Math.Floor(currentWave.Duration);
Int32 minIntensity, maxIntensity, minPeeksNumber, maxPeeksNumber;
maxIntensity = maxPeeksNumber = 0;
minIntensity = minPeeksNumber = Int32.MaxValue;
writer.Write((Int32)0); //minimo intensità
writer.Write((Int32)0); //massimo "
writer.Write((Int32)0); //minimo picchi
writer.Write((Int32)0); //massimo picchi
for (Int32 second = 0; second < duration; second++)
{
Int32 prev1, prev2, cur;
List
<Int32
> peeks
= new List
<Int32
>();
prev1 = Math.Abs((currentWave.ReadSample())[0]);
prev2 = Math.Abs((currentWave.ReadSample())[0]);
for (Int32 i = 0; i < currentWave.SampleRate - 2; i++)
{
cur = Math.Abs((currentWave.ReadSample())[0]);
if ((prev2 > prev1) && (prev2 > cur))
peeks.Add(prev2);
prev1 = prev2;
prev2 = cur;
}
if (peeks.Count > maxPeeksNumber)
maxPeeksNumber = peeks.Count;
if ((peeks.Count > 0) && (peeks.Count < minPeeksNumber))
minPeeksNumber = peeks.Count;
Int32 avg = 0;
if (peeks.Count > 0)
{
foreach (Int32 i in peeks)
avg += i;
avg /= peeks.Count;
if (avg < minIntensity)
minIntensity = avg;
if (avg > maxIntensity)
maxIntensity = avg;
}
writer.Write((Int32)peeks.Count);
writer.Write((Int32)avg);
completePercentage = ((float)second / duration) * 100f;
}
writer.Flush();
writer.BaseStream.Position = 0;
writer.Write(minIntensity);
writer.Write(maxIntensity);
writer.Write(minPeeksNumber);
writer.Write(maxPeeksNumber);
writer.Flush();
writer = null;
stream.Position = 0;
return stream;
}
private FileStream CreateStereoAudioFile(String dataFilePath)
{
FileStream stream
= new FileStream
(dataFilePath, FileMode.
Create);
BinaryWriter writer
= new BinaryWriter
(stream
);
Int32 duration = (int)Math.Floor(currentWave.Duration);
Int32 minIntensity, maxIntensity, minPeeksNumber, maxPeeksNumber;
maxIntensity = maxPeeksNumber = 0;
minIntensity = minPeeksNumber = Int32.MaxValue;
writer.Write((byte)'s');
writer.Write((byte)'t');
writer.Write((byte)'e');
writer.Write((byte)'r');
writer.Write((Int32)0); //minimo intensità
writer.Write((Int32)0); //massimo "
writer.Write((Int32)0); //minimo picchi
writer.Write((Int32)0); //massimo picchi
for (Int32 second = 0; second < duration; second++)
{
Int32[] prev1, prev2, cur;
List
<Int32
> peeksLeft
= new List
<Int32
>();
List
<Int32
> peeksRight
= new List
<Int32
>();
prev1 = currentWave.ReadSample();
prev2 = currentWave.ReadSample();
for (Int32 i = 0; i < currentWave.SampleRate - 2; i++)
{
cur = currentWave.ReadSample();
if ((prev2[0] > prev1[0]) && (prev2[0] > cur[0]))
peeksLeft.Add(prev2[0]);
if ((prev2[1] > prev1[1]) && (prev2[1] > cur[1]))
peeksRight.Add(prev2[1]);
prev1 = prev2;
prev2 = cur;
}
if (peeksLeft.Count > maxPeeksNumber)
maxPeeksNumber = peeksLeft.Count;
if (peeksRight.Count > maxPeeksNumber)
maxPeeksNumber = peeksRight.Count;
if ((peeksLeft.Count > 0) && (peeksLeft.Count < minPeeksNumber))
minPeeksNumber = peeksLeft.Count;
if ((peeksRight.Count > 0) && (peeksRight.Count < minPeeksNumber))
minPeeksNumber = peeksRight.Count;
Int32 avg = 0;
if (peeksLeft.Count > 0)
{
foreach (Int32 i in peeksLeft)
avg += i;
avg /= peeksLeft.Count;
if (avg < minIntensity)
minIntensity = avg;
if (avg > maxIntensity)
maxIntensity = avg;
}
writer.Write((Int32)peeksLeft.Count);
writer.Write((Int32)avg);
avg = 0;
if (peeksRight.Count > 0)
{
foreach (Int32 i in peeksRight)
avg += i;
avg /= peeksRight.Count;
if (avg < minIntensity)
minIntensity = avg;
if (avg > maxIntensity)
maxIntensity = avg;
}
writer.Write((Int32)peeksRight.Count);
writer.Write((Int32)avg);
peeksLeft.Clear();
peeksRight.Clear();
peeksLeft = null;
peeksRight = null;
completePercentage = ((float)second / duration) * 100f;
}
writer.Flush();
writer.BaseStream.Position = 4;
writer.Write(minIntensity);
writer.Write(maxIntensity);
writer.Write(minPeeksNumber);
writer.Write(maxPeeksNumber);
writer.Flush();
writer = null;
stream.Position = 0;
return stream;
}
private void ProcessWave()
{
completePercentage = 0f;
String dataFilePath = Path.GetDirectoryName(currentWave.OriginalFileName) + "\\" + Path.GetFileNameWithoutExtension(currentWave.OriginalFileName) + ".ad";
waveFileName = currentWave.OriginalFileName;
if (File.Exists(dataFilePath))
{
if (audioData != null)
{
try { audioData.Close(); }
catch { }
}
audioData = File.Open(dataFilePath, FileMode.Open);
completePercentage = 50f;
CreateSlowerAndFasterWaves();
completePercentage = 100f;
return;
}
if ((currentWaveMode == WaveMode.Mono) ||
(currentWaveMode == WaveMode.Stereo && currentWave.ChannelsNumber < 2))
audioData = CreateMonoAudioFile(dataFilePath);
else
audioData = CreateStereoAudioFile(dataFilePath);
audioData.Position = 0;
currentWave.Dispose();
CreateSlowerAndFasterWaves();
completePercentage = 100f;
}
private void ProcessWaveAsync()
{
temp
= new Thread
(ProcessWave
);
temp.Start();
}
#endregion
#region "Gestione Input"
bool keyPressed = false;
bool buttonPressed = false;
Vector2[] screenFormats = {
new Vector2
(1680, 1050
)};
String[] menuItems = { "Seleziona file", "Risoluzione: 800x600", "Visualizzazione: Schermo intero", "Gameplay: Normale", "Modalità: Mono", "Score Table", "Esci" };
String[] gameOverMenuItems = { "Ritenta", "Score Table", "Classifica online (NYI)", "Ritorna al menu" };
Int32 selectedIndex = 0;
Int32 selectedSubIndex = 0;
List<String> wavesList;
String currentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyMusic);
private void ProcessMenuInput()
{
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Up) && !keyPressed)
{
selectedIndex--;
if (selectedIndex < 0)
selectedIndex = 0;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Down) && !keyPressed)
{
selectedIndex++;
if (selectedIndex > menuItems.Length - 1)
selectedIndex = menuItems.Length - 1;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Left) && !keyPressed)
{
switch (selectedIndex)
{
case 1:
selectedSubIndex--;
if (selectedSubIndex < 0)
selectedSubIndex = 0;
menuItems[1] = String.Format("Risoluzione: {0:N0}x{1:N0}", screenFormats[selectedSubIndex].X, screenFormats[selectedSubIndex].Y);
keyPressed = true;
break;
case 3:
selectedSubIndex--;
if (selectedSubIndex < 0)
selectedSubIndex = 0;
keyPressed = true;
menuItems[3] = "Gameplay: " + GetDifficulty(selectedSubIndex);
break;
}
}
if (kState.IsKeyDown(Keys.Right) && !keyPressed)
{
switch(selectedIndex)
{
case 1:
selectedSubIndex++;
if (selectedSubIndex > screenFormats.Length - 1)
selectedSubIndex = screenFormats.Length - 1;
menuItems[1] = String.Format("Risoluzione: {0:N0}x{1:N0}", screenFormats[selectedSubIndex].X, screenFormats[selectedSubIndex].Y);
keyPressed = true;
break;
case 3:
selectedSubIndex++;
if (selectedSubIndex > 6)
selectedSubIndex = 6;
menuItems[3] = "Gameplay: " + GetDifficulty(selectedSubIndex);
keyPressed = true;
break;
}
}
if (kState.IsKeyDown(Keys.Enter) && !keyPressed)
{
switch (selectedIndex)
{
case 0:
currentMode = GameMode.FileSelection;
break;
case 1:
Properties.Settings.Default.Resolution = screenFormats[selectedSubIndex];
Properties.Settings.Default.Save();
this.graphics.PreferredBackBufferWidth = (int)screenFormats[selectedSubIndex].X;
this.graphics.PreferredBackBufferHeight = (int)screenFormats[selectedSubIndex].Y;
this.GraphicsDevice.PresentationParameters.BackBufferWidth = (int)screenFormats[selectedSubIndex].X;
this.GraphicsDevice.PresentationParameters.BackBufferHeight = (int)screenFormats[selectedSubIndex].Y;
this.graphics.ApplyChanges();
break;
case 2:
this.graphics.ToggleFullScreen();
if (this.graphics.IsFullScreen)
menuItems[2] = "Visualizzazione: Schermo intero";
else
menuItems[2] = "Visualizzazione: Finestra";
Properties.Settings.Default.Fullscreen = this.graphics.IsFullScreen;
Properties.Settings.Default.Save();
break;
case 3:
Properties.Settings.Default.Difficulty = selectedSubIndex;
Properties.Settings.Default.Save();
break;
case 4:
currentWaveMode = 1 - currentWaveMode;
if (currentWaveMode == WaveMode.Mono)
menuItems[4] = "Modalità: Mono";
else
menuItems[4] = "Modalità: Stereo";
Properties.Settings.Default.Mode = (int)currentWaveMode;
Properties.Settings.Default.Save();
break;
case 5:
records.GenerateHtmlTable(recordsFolder + "\\records.html");
System.Diagnostics.Process.Start(recordsFolder + "\\records.html");
break;
case 6:
this.Exit();
break;
}
selectedIndex = 0;
keyPressed = true;
return;
}
if (kState.IsKeyUp(Keys.Up) && kState.IsKeyUp(Keys.Down) && kState.IsKeyUp(Keys.Enter)
&& kState.IsKeyUp(Keys.Left) && kState.IsKeyUp(Keys.Right))
keyPressed = false;
}
public static String GetDifficulty(Int32 index)
{
switch (index)
{
case 0: return "Molto semplice";
case 1: return "Semplice";
case 2: return "Normale";
case 3: return "Difficile";
case 4: return "Molto difficile";
case 5: return "Impossibile";
case 6: return "Custom";
}
return "???";
}
private void ProcessFileSelectionInput()
{
KeyboardState kState = Keyboard.GetState();
if (wavesList == null)
{
wavesList
= new List
<String>();
wavesList.AddRange(Directory.GetDirectories(currentDirectory));
wavesList.AddRange(Directory.GetFiles(currentDirectory, "*.wav", SearchOption.TopDirectoryOnly));
}
if (kState.IsKeyDown(Keys.Up) && !keyPressed)
{
selectedIndex--;
if (selectedIndex < 0)
selectedIndex = 0;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Down) && !keyPressed)
{
selectedIndex++;
if (selectedIndex > wavesList.Count - 1)
selectedIndex = wavesList.Count - 1;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Enter) && !keyPressed)
{
try
{
if (File.Exists(wavesList[selectedIndex]))
{
currentWave
= new Wave
(wavesList
[selectedIndex
],
false);
currentMode = GameMode.Processing;
ProcessWaveAsync();
}
else if (Directory.Exists(wavesList[selectedIndex]))
{
currentDirectory = wavesList[selectedIndex];
wavesList.Clear();
wavesList.Add("Parent");
wavesList.AddRange(Directory.GetDirectories(currentDirectory));
wavesList.AddRange(Directory.GetFiles(currentDirectory, "*.wav", SearchOption.TopDirectoryOnly));
selectedIndex = 0;
}
else if (wavesList[selectedIndex] == "Parent")
{
currentDirectory = currentDirectory.Remove(currentDirectory.LastIndexOf("\\"));
wavesList.Clear();
if (currentDirectory != Environment.GetFolderPath(Environment.SpecialFolder.MyMusic))
wavesList.Add("Parent");
wavesList.AddRange(Directory.GetDirectories(currentDirectory));
wavesList.AddRange(Directory.GetFiles(currentDirectory, "*.wav", SearchOption.TopDirectoryOnly));
selectedIndex = 0;
}
}
catch
{
wavesList.RemoveAt(selectedIndex);
}
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Escape))
{
keyPressed = true;
currentMode = GameMode.Menu;
}
if (kState.IsKeyUp(Keys.Up) && kState.IsKeyUp(Keys.Down) && kState.IsKeyUp(Keys.Enter))
keyPressed = false;
}
private void ProcessGameInput(GameTime gameTime)
{
MouseState mState = Mouse.GetState();
KeyboardState kState = Keyboard.GetState();
player.
Position = new Vector2
(mState.
X, mState.
Y);
if (kState.IsKeyDown(Keys.Escape))
{
keyPressed = true;
currentMode = GameMode.Menu;
notes.Clear();
notesToSpawn.Clear();
if (music != null)
{
music.Stop();
music.Dispose();
}
}
if (mState.LeftButton == ButtonState.Pressed && !buttonPressed && availableMagnets > 0)
{
magnetEnabled = true;
magnetStartTime = gameTime.TotalGameTime.TotalSeconds;
timedFloatingBonuses.
Add(new FloatingText
(player.
Position,
"Magnet!", player.Color, gameTime.TotalGameTime.TotalSeconds));
availableMagnets--;
buttonPressed = true;
}
if (mState.RightButton == ButtonState.Pressed && !buttonPressed && availableAllColors > 0)
{
foreach (GameObject note in notes)
note.Color = player.Color;
availableAllColors--;
buttonPressed = true;
}
if (mState.LeftButton == ButtonState.Released && mState.RightButton == ButtonState.Released)
buttonPressed = false;
}
private void ProcessGameOverInput()
{
KeyboardState kState = Keyboard.GetState();
if (kState.IsKeyDown(Keys.Up) && !keyPressed)
{
selectedIndex--;
if (selectedIndex < 0)
selectedIndex = 0;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Down) && !keyPressed)
{
selectedIndex++;
if (selectedIndex > gameOverMenuItems.Length - 1)
selectedIndex = gameOverMenuItems.Length - 1;
keyPressed = true;
}
if (kState.IsKeyDown(Keys.Enter) && !keyPressed)
{
switch (selectedIndex)
{
case 0:
StartPlaying();
break;
case 1:
records.GenerateHtmlTable(recordsFolder + "\\records.html");
System.Diagnostics.Process.Start(recordsFolder + "\\records.html");
break;
case 2:
// todo
break;
case 3:
currentMode = GameMode.Menu;
notes.Clear();
notesToSpawn.Clear();
try
{
if (music != null)
{
music.Stop();
music.Dispose();
audioData.Close();
}
}
catch { }
finally
{
audioData.Close();
}
break;
}
selectedIndex = 0;
keyPressed = true;
return;
}
if (kState.IsKeyUp(Keys.Up) && kState.IsKeyUp(Keys.Down) && kState.IsKeyUp(Keys.Enter))
keyPressed = false;
}
#endregion
#region "Gestione gioco"
// Discarica (file temporanei da eliminare)
List
<String> filesDump
= new List
<String>();
// Generale
Audio music;
Random rnd
= new Random
(DateTime.
Now.
Millisecond);
// Note
List<GameObject> notesToSpawn;
List<GameObject> notes;
Player player;
public Int32 maxNotesPerSecond = 30;
// Punteggi
Int64 score = 0;
Color scoreColor = Color.White;
Int32 baseScaleBonus = 100;
Int32 baseSpeedBonus = 10;
float baseVariationBonus = 2;
public float baseNegativeBonus = -5;
float multiplier = 1.0f;
public float multiplierIncrement = 0.1f;
public float baseNegativeMultiplier = 0.5f;
ScoreTable records;
// Altri parametri
public float baseYSpeed = 800f;
public double movingNotesPercentage = 0.2d;
public double shrinkingNotesPercentage = 0.2d;
public double badNotesPercentage = 0.2d;
// Powerups
bool magnetEnabled = false;
double magnetStartTime = 0;
double magnetDuration = 10d;
public Int32 numberOfMagnets = 2;
public Int32 numberOfAllColors = 2;
Int32 availableMagnets = 2;
Int32 availableAllColors = 2;
// Spiral
bool spiralAppeared = true;
double spiralApparitionPercent = 0.0005d;
double spiralApparitionTime = 0;
GameObject spiral;
// Dati partita
Int32 numberOfBadNotes, numberOfCaughtBadNotes, numberOfNotes, numberOfCaughtNotes;
// Testo scorrevole
List<FloatingText> timedFloatingBonuses;
float secondsBeforeTextElapses = 2.5f;
private void SpiralCreationEvent(GameObject obj)
{
double pos = music.CurrentPosition;
music.Stop();
music.Dispose();
if (rnd.NextDouble() < 0.5d)
{
music = Audio.FromFile(fasterWaveFileName);
speedChangeFactor = 1.4f;
}
else
{
music = Audio.FromFile(slowerWaveFileName);
speedChangeFactor = 0.6f;
}
foreach (GameObject note in notesToSpawn)
note.Speed *= speedChangeFactor;
music.CurrentPosition = pos / speedChangeFactor;
music.Play();
}
private void ApplyDifficulty()
{
switch (Properties.Settings.Default.Difficulty)
{
case 0 :
baseNegativeBonus = 0;
multiplierIncrement = 0.5f;
baseNegativeMultiplier = 1.0f;
maxNotesPerSecond = 10;
baseYSpeed = 350f;
movingNotesPercentage = 0.1f;
shrinkingNotesPercentage = 0.1f;
badNotesPercentage = 0.05f;
numberOfAllColors = 3;
numberOfMagnets = 3;
break;
case 1:
baseNegativeBonus = -2;
multiplierIncrement = 0.3f;
baseNegativeMultiplier = 0.7f;
maxNotesPerSecond = 16;
baseYSpeed = 400f;
movingNotesPercentage = 0.15f;
shrinkingNotesPercentage = 0.15f;
badNotesPercentage = 0.08f;
numberOfAllColors = 3;
numberOfMagnets = 2;
break;
case 2:
baseNegativeBonus = -4;
multiplierIncrement = 0.15f;
baseNegativeMultiplier = 0.5f;
maxNotesPerSecond = 19;
baseYSpeed = 500f;
movingNotesPercentage = 0.2f;
shrinkingNotesPercentage = 0.2f;
badNotesPercentage = 0.09f;
numberOfAllColors = 2;
numberOfMagnets = 2;
break;
case 3:
baseNegativeBonus = -6;
multiplierIncrement = 0.1f;
baseNegativeMultiplier = 0.3f;
maxNotesPerSecond = 24;
baseYSpeed = 600f;
movingNotesPercentage = 0.25f;
shrinkingNotesPercentage = 0.25f;
badNotesPercentage = 0.1f;
numberOfAllColors = 2;
numberOfMagnets = 1;
break;
case 4:
baseNegativeBonus = -7;
multiplierIncrement = 0.05f;
baseNegativeMultiplier = 0.1f;
maxNotesPerSecond = 27;
baseYSpeed = 700f;
movingNotesPercentage = 0.3f;
shrinkingNotesPercentage = 0.3f;
badNotesPercentage = 0.11f;
numberOfAllColors = 1;
numberOfMagnets = 1;
break;
case 5:
baseNegativeBonus = -9;
multiplierIncrement = 0.05f;
baseNegativeMultiplier = 0f;
maxNotesPerSecond = 32;
baseYSpeed = 800f;
movingNotesPercentage = 0.3f;
shrinkingNotesPercentage = 0.3f;
badNotesPercentage = 0.13f;
numberOfAllColors = 0;
numberOfMagnets = 0;
break;
case 6:
StreamReader reader
= new StreamReader
(recordsFolder
+ "\\custom_diff.ini");
String line;
FieldInfo[] fields = this.GetType().GetFields();
// regex per un ini? non ho voglia
do {
line = reader.ReadLine();
line = line.Trim();
if (line.StartsWith("[") || String.IsNullOrEmpty(line) || line.StartsWith("#") || !line.Contains("="))
continue;
if (line.IndexOf("#") > -1)
line = line.Remove(line.IndexOf("#"));
String[] parts = line.Split('=');
parts[0] = parts[0].Trim();
parts[1] = parts[1].Trim();
foreach (FieldInfo f in fields)
{
try
{
if (parts[0] == f.Name)
f.SetValue(this, Convert.ChangeType(parts[1], f.FieldType));
}
catch { }
}
} while (!reader.EndOfStream);
reader.Close();
break;
}
}
private void StartPlaying()
{
currentMode = GameMode.Playing;
score = 0;
scoreColor = Color.White;
availableMagnets = numberOfMagnets;
availableAllColors = numberOfAllColors;
multiplier = 1.0f;
magnetEnabled = false;
player.
Position = new Vector2
(this.
graphics.
PreferredBackBufferWidth / 2
- player.
Sprite.
Width / 2,
this.graphics.PreferredBackBufferHeight - 100);
ApplyDifficulty();
GenerateNotes();
music = Audio.FromFile(waveFileName);
music.Play();
}
private GameObject GenerateOneMonoNote(float peeksPercent, float notesPercent)
{
GameObject n
= new GameObject
();
Int32 x;
n.Sprite = haloBall;
x = 35 + (int)(peeksPercent * (this.graphics.PreferredBackBufferWidth - 70));
n.
Position = new Vector2
(x
+ (float)((rnd.
NextDouble() - 0.5d
) * 50
), 40
);
n.Speed = Vector2.UnitY * notesPercent * baseYSpeed;
n.Speed += Vector2.UnitX * (float)((rnd.NextDouble() - 0.5d) * 30);
n.Scale = 0.7f + (float)(rnd.NextDouble() * 0.4);
if (rnd.NextDouble() < shrinkingNotesPercentage)
n.Variation = GameObject.HarmonicScaleVariation;
else if (rnd.NextDouble() < movingNotesPercentage)
n.Variation = GameObject.HarmonicXVariation;
if (rnd.NextDouble() > (1.0f - badNotesPercentage))
{
n.Color = Color.Red;
numberOfBadNotes++;
}
else
n.
Color = new Color
((byte)rnd.
Next(50, 256
),
(byte)rnd.
Next(50, 256
),
(byte)rnd.
Next(50, 256
));
return n;
}
private GameObject GenerateOneStereoNote(float peeksPercent, float notesPercent, bool isLeft)
{
GameObject n
= new GameObject
();
Int32 y;
n.Sprite = haloBall;
y = 35 + (int)(peeksPercent * (this.graphics.PreferredBackBufferHeight - 70));
if (isLeft)
{
n.
Position = new Vector2
(40, y
+ (float)((rnd.
NextDouble() - 0.5d
) * 50
));
n.Speed = Vector2.UnitX * notesPercent * baseYSpeed;
}
else
{
n.
Position = new Vector2
(this.
graphics.
PreferredBackBufferWidth - 40, y
+ (float)((rnd.
NextDouble() - 0.5d
) * 50
));
n.Speed = -Vector2.UnitX * notesPercent * baseYSpeed;
}
n.Speed += Vector2.UnitY * (float)((rnd.NextDouble() - 0.5d) * 30);
n.Scale = 0.7f + (float)(rnd.NextDouble() * 0.4);
if (rnd.NextDouble() < shrinkingNotesPercentage)
n.Variation = GameObject.HarmonicScaleVariation;
else if (rnd.NextDouble() < movingNotesPercentage)
n.Variation = GameObject.HarmonicYVariation;
if (rnd.NextDouble() > (1.0f - badNotesPercentage))
{
n.Color = Color.Red;
numberOfBadNotes++;
}
else
n.
Color = new Color
((byte)rnd.
Next(50, 256
),
(byte)rnd.
Next(50, 256
),
(byte)rnd.
Next(50, 256
));
return n;
}
private void GenerateNotes()
{
BinaryReader reader
= new BinaryReader
(audioData
);
Int32 minIntensity, maxIntensity, minPeeksNumber, maxPeeksNumber;
Int32 second = 0;
Char[] chars;
bool isStereo = false;
chars = reader.ReadChars(4);
if (chars[0] == 's' && chars[1] == 't' && chars[2] == 'e' && chars[3] == 'r')
isStereo = true;
else
reader.BaseStream.Position = 0;
minIntensity = reader.ReadInt32();
maxIntensity = reader.ReadInt32();
minPeeksNumber = reader.ReadInt32();
maxPeeksNumber = reader.ReadInt32();
if (notesToSpawn == null)
notesToSpawn
= new List
<GameObject
>();
notesToSpawn.Clear();
notes.Clear();
numberOfCaughtNotes = 0;
numberOfBadNotes = 0;
numberOfCaughtBadNotes = 0;
do
{
Int32 peeksCount, avg;
Int32 notesNumber;
peeksCount = reader.ReadInt32();
avg = reader.ReadInt32();
notesNumber = (int)(((float)(avg - minIntensity) / (maxIntensity - minIntensity)) * maxNotesPerSecond);
notesNumber = (int)MathHelper.Clamp(notesNumber, 1, maxNotesPerSecond);
for (Int32 i = 0; i < notesNumber; i++)
{
GameObject n;
if ((currentWaveMode == WaveMode.Mono) || (!isStereo))
n = GenerateOneMonoNote((float)(peeksCount - minPeeksNumber) / (maxPeeksNumber - minPeeksNumber), (float)notesNumber / maxNotesPerSecond);
else
n = GenerateOneStereoNote((float)(peeksCount - minPeeksNumber) / (maxPeeksNumber - minPeeksNumber), (float)notesNumber / maxNotesPerSecond, true);
n.SpawnTime = (double)second + ((double)i / notesNumber);
notesToSpawn.Add(n);
}
if (isStereo)
{
peeksCount = reader.ReadInt32();
avg = reader.ReadInt32();
if (currentWaveMode == WaveMode.Stereo)
{
notesNumber = (int)(((float)(avg - minIntensity) / (maxIntensity - minIntensity)) * maxNotesPerSecond);
notesNumber = (int)MathHelper.Clamp(notesNumber, 1, maxNotesPerSecond);
for (Int32 i = 0; i < notesNumber; i++)
{
GameObject n;
n = GenerateOneStereoNote((float)(peeksCount - minPeeksNumber) / (maxPeeksNumber - minPeeksNumber), (float)notesNumber / maxNotesPerSecond, false);
n.SpawnTime = (double)second + ((double)i / notesNumber);
notesToSpawn.Add(n);
}
}
}
second++;
} while (reader.BaseStream.Position < reader.BaseStream.Length - 1);
numberOfNotes = notesToSpawn.Count;
reader = null;
audioData.Position = 0;
}
private void SpawnNotes()
{
List
<GameObject
> toDel
= new List
<GameObject
>();
foreach (GameObject go in notesToSpawn)
{
if (go.SpawnTime <= music.CurrentPosition * speedChangeFactor)
{
notes.Add(go);
toDel.Add(go);
}
}
foreach (GameObject go in toDel)
{
notesToSpawn.Remove(go);
}
toDel.Clear();
toDel = null;
}
private void CheckCollisions(GameTime gameTime)
{
List
<GameObject
> toDel
= new List
<GameObject
>();
double seconds = gameTime.TotalGameTime.TotalSeconds;
foreach (GameObject note in notes)
{
if (player.Intersects(note))
{
if (!String.IsNullOrEmpty(note.Tag) && (note.OnCollision != null))
note.OnCollision.Invoke(player);
float bonus;
bonus = baseScaleBonus * note.Scale;
bonus += baseSpeedBonus * note.Speed.Length();
if (note.Variation != null)
bonus *= baseVariationBonus;
if (note.Color == Color.Red)
{
bonus *= baseNegativeBonus;
multiplier = baseNegativeMultiplier;
numberOfCaughtBadNotes++;
}
else
{
multiplier += multiplierIncrement;
numberOfCaughtNotes++;
}
scoreColor = note.Color;
score += (int)bonus;
timedFloatingBonuses.
Add(new FloatingText
(player.
Position,
bonus > 0 ? String.Format("+{0}", (int)bonus) : bonus.ToString("N0"),
note.Color, seconds));
toDel.Add(note);
}
else if ((note.Position.Y > this.graphics.PreferredBackBufferHeight) || (note.Position.Y < 0)
|| (note.Position.X > this.graphics.PreferredBackBufferWidth) || (note.Position.X < 0))
toDel.Add(note);
}
foreach (GameObject note in toDel)
notes.Remove(note);
toDel.Clear();
toDel = null;
}
private void UpdateFloatingText(GameTime gameTime)
{
List
<FloatingText
> textToDel
= new List
<FloatingText
>();
double seconds = gameTime.TotalGameTime.TotalSeconds;
foreach (FloatingText txt in timedFloatingBonuses)
{
if (seconds - txt.SpawnTime < secondsBeforeTextElapses)
{
txt.
Color = new Color
(txt.
Color.
R, txt.
Color.
G, txt.
Color.
B,
(byte)((1 - ((seconds - txt.SpawnTime) / secondsBeforeTextElapses)) * 255));
txt.Position -= Vector2.UnitY * 2;
}
else
textToDel.Add(txt);
}
foreach (FloatingText txt in textToDel)
timedFloatingBonuses.Remove(txt);
textToDel.Clear();
textToDel = null;
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
switch (currentMode)
{
case GameMode.Menu :
ProcessMenuInput();
break;
case GameMode.FileSelection :
ProcessFileSelectionInput();
break;
case GameMode.Processing :
if ((completePercentage == 100f) && (!temp.IsAlive))
StartPlaying();
break;
case GameMode.Playing :
SpawnNotes();
ProcessGameInput(gameTime);
double seconds = gameTime.TotalGameTime.TotalSeconds;
foreach (GameObject note in notes)
note.Update(gameTime);
if (magnetEnabled)
{
foreach(GameObject note in notes)
if (note.Color != Color.Red)
{
Vector2 tmp = player.Position - note.Position;
tmp.Normalize();
note.Speed = tmp * (note.Speed.Length() > 3.0f ? note.Speed.Length() : 5.0f);
note.Variation = null;
}
if (seconds - magnetStartTime > magnetDuration)
magnetEnabled = false;
}
CheckCollisions(gameTime);
UpdateFloatingText(gameTime);
if ((rnd.NextDouble() < spiralApparitionPercent) && !spiralAppeared)
{
spiral
= new GameObject
();
spiral.Sprite = haloSpiral;
spiral.
Position = new Vector2
((float)(this.
graphics.
PreferredBackBufferWidth / 2
- spiral.
Sprite.
Width / 2
),
(float)(this.
graphics.
PreferredBackBufferHeight / 2
- spiral.
Sprite.
Height / 2
));
spiral.Variation = GameObject.RotationVariation;
spiral.Tag = "spiral";
spiral.OnCollision = SpiralCreationEvent;
notes.Add(spiral);
spiralAppeared = true;
spiralApparitionTime = seconds;
}
if ((spiral != null) && (seconds - spiralApparitionTime > 5))
{
notes.Remove(spiral);
spiral = null;
}
try
{
if (music.CurrentPosition >= music.Duration)
{
music.Stop();
currentMode = GameMode.GameOver;
records.
Add(new Record
(Path.
GetFileNameWithoutExtension(waveFileName
),
DateTime.Now, score, (byte)Properties.Settings.Default.Difficulty,
numberOfNotes, numberOfCaughtNotes, numberOfBadNotes,
numberOfCaughtBadNotes, currentWaveMode == WaveMode.Mono ? "Mono" : "Stereo"));
records.Save(recordsFolder + "\\records.dat");
}
}
catch
{
currentMode = GameMode.GameOver;
records.
Add(new Record
(Path.
GetFileNameWithoutExtension(waveFileName
),
DateTime.Now, score, (byte)Properties.Settings.Default.Difficulty,
numberOfNotes, numberOfCaughtNotes, numberOfBadNotes,
numberOfCaughtBadNotes, currentWaveMode == WaveMode.Mono ? "Mono" : "Stereo"));
records.Save(recordsFolder + "\\records.dat");
}
break;
case GameMode.GameOver :
ProcessGameOverInput();
break;
}
base.Update(gameTime);
}
#endregion
#region "Disegno"
private static Vector2 vector20
= new Vector2
(20, 20
);
private void DrawMenu()
{
Color c;
Vector2 size;
spriteBatch.
Draw(logo,
new Rectangle
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- logo.
Width / 2
), 10, logo.
Width, logo.
Height), Color.
White);
for (Int32 i = 0; i < menuItems.Length; i++)
{
c = Color.White;
if (i == selectedIndex)
c = Color.Yellow;
size = menuItemFont.MeasureString(menuItems[i]);
spriteBatch.
DrawString(menuItemFont, menuItems
[i
],
new Vector2
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- size.
X/2
), 240
+ i
* 30
), c
);
}
}
private void DrawFileSelection()
{
if (wavesList == null)
return;
Color c;
Int32 filesNumber = (int)((this.graphics.PreferredBackBufferHeight - 40) / 30);
float y = 20f;
for (Int32 i = (selectedIndex / filesNumber) * filesNumber; i < wavesList.Count; i++)
{
if (File.Exists(wavesList[i]))
c = Color.White;
else if (Directory.Exists(wavesList[i]))
c = Color.Green;
else
c = Color.Red;
if (i == selectedIndex)
c = Color.Yellow;
spriteBatch.
DrawString(menuItemFont, Path.
GetFileNameWithoutExtension(wavesList
[i
]),
new Vector2
(20, y
), c
);
y += 30f;
if (y + 30 > this.graphics.PreferredBackBufferHeight)
break;
}
}
private void DrawCompletePercentage()
{
spriteBatch.DrawString(menuItemFont, String.Format("Elaborazione in corso: {0:N2}%", completePercentage), vector20, Color.White);
}
private void DrawGameInterface()
{
spriteBatch.DrawString(menuItemFont, "Score: " + score.ToString(), vector20, scoreColor);
foreach (FloatingText txt in timedFloatingBonuses)
spriteBatch.DrawString(menuItemFont, txt.Text, txt.Position, txt.Color);
spriteBatch.DrawString(menuItemFont,
String.Format("Moltiplicatore: {0:N1} - Magneti: {1} - Colore: {2}", multiplier, availableMagnets, availableAllColors),
new Vector2
(20,
this.
graphics.
PreferredBackBufferHeight - 40
), Color.
White);
}
private void DrawGameOverInterface()
{
Vector2 size = bigFont.MeasureString(score.ToString());
String notesInfo = String.Format("Note prese: {0} / {1}", numberOfCaughtNotes, numberOfNotes);
String badNotesInfo = String.Format("Note prese: {0} / {1}", numberOfCaughtBadNotes, numberOfBadNotes);
Color c;
spriteBatch.
DrawString(bigFont, score.
ToString(),
new Vector2
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- size.
X / 2
), 50
), scoreColor
);
size = bigFont.MeasureString(notesInfo);
spriteBatch.
DrawString(bigFont, notesInfo,
new Vector2
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- size.
X / 2
), 100
), Color.
White);
size = bigFont.MeasureString(badNotesInfo);
spriteBatch.
DrawString(bigFont, badNotesInfo,
new Vector2
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- size.
X / 2
), 150
), Color.
Red);
for (Int32 i = 0; i < gameOverMenuItems.Length; i++)
{
c = Color.White;
if (i == selectedIndex)
c = Color.Yellow;
size = menuItemFont.MeasureString(gameOverMenuItems[i]);
spriteBatch.
DrawString(menuItemFont, gameOverMenuItems
[i
],
new Vector2
((int)(this.
graphics.
PreferredBackBufferWidth / 2
- size.
X / 2
), 250
+ i
* 30
), c
);
}
}
#endregion
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
switch (currentMode)
{
case GameMode.Menu :
DrawMenu();
break;
case GameMode.FileSelection :
DrawFileSelection();
break;
case GameMode.Processing :
DrawCompletePercentage();
break;
case GameMode.Playing :
foreach (GameObject go in notes)
go.Draw(spriteBatch);
player.Draw(spriteBatch);
DrawGameInterface();
break;
case GameMode.GameOver :
DrawGameOverInterface();
break;
}
spriteBatch.End();
base.Draw(gameTime);
}
}
}