C# Console program runs faster when button is pressed - c#

I'm creating a procedurally generated platformer in the C# console, out of interest. However, I found that the program runs slower than I would expect unless I hold any button, then it returns to the expected amount entered as timeLapse.
Currently the only button with a functionality is the space bar, which makes you jump. I tested the code as well without the code on line // THIS CODE, and that removes the problem. Does anyone have an explanation or an article about this? Couldn't find a lot myself.
PlatformGenerator code could be added, although I don't think it would be necessary.
Program code:
namespace TestProject.Procedural_Generation
{
public class PlatformManager
{
#region Variables
// Game settings
private static char[,] screen;
private static int screenWidth = 96;
private static int screenHeight = 20;
// Platform generation settings
private static int minGeneration = 4;
private static int maxGeneration = 18;
private static PlatformGenerator pg;
private static List<Platform> platforms = new List<Platform>();
// Physics variables
private static int oldX = 0;
private static int currentX = 0;
private static int currentY = 8;
private static string toSkip = "";
private static Player player;
// Timer variables
private static float timeLapse = 100;
private static float jumpTime = 200;
private static Timer graphicUpdater;
private static Timer physicUpdater;
private static Timer jumpTimer;
private static bool isJumping = false;
private static long score = 0;
#endregion
public PlatformManager()
{
screen = new char[screenHeight, screenWidth];
pg = new PlatformGenerator(minGeneration, maxGeneration);
player = new Player();
// Physics
physicUpdater = new Timer(timeLapse);
physicUpdater.Elapsed += ExecutePhysics;
physicUpdater.AutoReset = true;
physicUpdater.Enabled = true;
jumpTimer = new Timer(jumpTime);
jumpTimer.Elapsed += Land;
jumpTimer.Enabled = true;
// Graphics
graphicUpdater = new Timer(timeLapse);
graphicUpdater.Elapsed += ExecuteGraphics;
graphicUpdater.AutoReset = true;
graphicUpdater.Enabled = true;
while (true)
{
score++;
}
}
private void Land(object source, EventArgs e)
{
isJumping = false;
}
#region Graphics
private void ExecuteGraphics(object source, ElapsedEventArgs e)
{
Console.Clear();
Console.Write(Display());
}
// Makes sure everything is printed correctly
public string Display()
{
string result = "";
for (int y = 0; y < screenHeight; y++)
{
for (int x = 0; x < screenWidth; x++)
{
if (y == player.y && x == player.x)
{
result += "O";
}
else if (screen[y, x] == '=')
{
result += "=";
}
else
{
result += " ";
}
}
result += "\n";
}
return result;
}
#endregion
#region Physics
// Controls platform generation and movement
private void ExecutePhysics(object source, ElapsedEventArgs e)
{
Platformer();
if (player.y == screenHeight - 1)
{
graphicUpdater.Stop();
physicUpdater.Stop();
Console.WriteLine();
Console.WriteLine("Game over! Score: " + Math.Floor(Math.Sqrt(score)));
}
else if (isJumping)
{
player.y -= 1;
}
else if (Console.ReadKey(true).Key == ConsoleKey.Spacebar && screen[player.y + 1, player.x] == '=') // THIS CODE
{
isJumping = true;
jumpTimer.Start();
player.y -= 1;
}
else if (screen[player.y + 1, player.x] != '=' && !isJumping)
{
player.y += 1;
}
}
// Generate a new platform
public void Platformer()
{
Platform newPlatform = pg.Generate(currentX, currentY);
currentY = newPlatform.y;
if (currentX + newPlatform.size + newPlatform.xDif > screenWidth)
{
MoveScreen(newPlatform.size + newPlatform.xDif);
currentX -= newPlatform.size + newPlatform.xDif;
oldX -= newPlatform.size + newPlatform.xDif;
}
while (currentX < oldX + newPlatform.size + newPlatform.xDif)
{
screen[currentY, currentX] = '=';
currentX += 1;
}
oldX = currentX;
}
// Update all rows so the newly added ones fit.
public void MoveScreen(int amount)
{
for (int y = 0; y < screenHeight; y++)
{
for (int x = amount; x < screenWidth; x++)
{
screen[y, x - amount] = screen[y, x];
}
}
for (int y = 0; y < screenHeight; y++)
{
for (int x = screenWidth - amount; x < screenWidth; x++)
{
screen[y, x] = '\0';
}
}
}
#endregion
}
}

Not sure If I understand correclty, but the
Console.ReadKey(true).Key == ConsoleKey.Spacebar
waits for a keypress to happen, so the code will not be processed until a key is actually pressed, if you remove that the programm will obviously move "faster" because it does not wait for a keypress to happen

Related

Can't make a win checker in c# connect four game using windows forms

This is my code so far,im trying to make a c# connect four game but i cant seem to get the win checker to work! I'd like for my game to be able to check for four in a row, horizontally, vertically and diagonally and show a message telling you the winner. I have checked and everything else works as it should.
namespace ConnectFour
{
public partial class Form1 : Form
{
Button[] gameButtons = new Button[42]; //array of buttons for markers(red and blue)
bool blue = true; //blue is set to true if the next marker is to be a blue
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Text = "Connect 4";
this.BackColor = Color.BlanchedAlmond;
this.Width = 500;
this.Height = 500;
for (int i = 0; i < gameButtons.Length; i++)
{
int index = i;
this.gameButtons[i] = new Button();
int x = 50 + (i % 7) * 50;
int y = 50 + (i / 7) * 50;
this.gameButtons[i].Location = new System.Drawing.Point(x, y);
this.gameButtons[i].Name = "btn" + (index + 1);
this.gameButtons[i].Size = new System.Drawing.Size(50, 50);
this.gameButtons[i].TabIndex = i;
//this.gameButtons[i].Text = Convert.ToString(index);
this.gameButtons[i].UseVisualStyleBackColor = true;
this.gameButtons[i].Visible = true;
gameButtons[i].Click += (sender1, ex) => this.buttonHasBeenPressed(sender1, index);
this.Controls.Add(gameButtons[i]);
}
}
private void buttonHasBeenPressed(object sender, int i)
{
if (((Button)sender).BackColor == Color.BlanchedAlmond)
{
if (blue == true)
{
((Button)sender).BackColor = Color.Red;
}
else
{
((Button)sender).BackColor = Color.Blue;
}
blue = !blue;
}
}
private void fourInARow(int a, int b, int c,int d)
{
if (gameButtons[a].BackColor == gameButtons[b].BackColor && gameButtons[a].BackColor == gameButtons[c].BackColor && gameButtons[a].BackColor==gameButtons[d].BackColor)
{
if (gameButtons[a].BackColor == Color.Blue)
{
MessageBox.Show("the winner is player 1");
}
else
{
MessageBox.Show("the winner is player 2");
}
}
}
}
Why do you use Index?
int index = I;
will stay at "0" - because its an initializer and only called once in for-loop.
But it makes no sense for me at all to have an index var.

Fft in real time - AsioOut+SampleAggregator

I am currently working on my thesis project, this is an application that writes tablature by ASIO drivers. In short, write what you play. I'm new in all regards Naudio and I'm having poblemas to transform sound into FFT. I am capturing the sound with a device called "GuitarLink" which runs through ASIO4ALL.
So I need to compare frequencies for the chord in real time.
Currently, the program gives me two values, X and Y.
(I am using "SampleAggregator" Class and AsioOut)
MAIN
private SampleAggregator sampleAggregator = new(fftLength);
public MainWindow()
{
InitializeComponent();
dispatcherTimer.Tick += new EventHandler(SoClose);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
dispatcherTimer.Start();
}
void SoClose(object sender, EventArgs e)
{
try
{
if (PBass)
{
sampleAggregator.PerformFFT = true;
sampleAggregator.FftCalculated += new EventHandler<FftEventArgs>(FftCalculated);
AsioOut asioOut = new();
BufferedWaveProvider wavprov = new(new WaveFormat(48000, 1));
asioOut.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs>(asio_DataAvailable);
asioOut.InitRecordAndPlayback(wavprov, 1, 25);
asioOut.Play();
I1E.Text = frecuencia.ToString();
}
}
catch
{
MessageBox.Show("Error de bajo presupuesto", "Obviamente algo anda mal");
}
}
private void FftCalculated(object sender, FftEventArgs e)
{
for (int i = 0; i < e.Result.Length; ++i)
{
A = e.Result[i].X;
B = e.Result[i].Y;
frecuencia = B;
Debug.WriteLine($"FFT: X={e.Result[i].X} Y={e.Result[i].Y}");
}
}
void asio_DataAvailable(object sender, AsioAudioAvailableEventArgs e)
{
byte[] buf = new byte[e.SamplesPerBuffer * 4];
for (int i = 0; i < e.InputBuffers.Length; i++)
{
Marshal.Copy(e.InputBuffers[i], buf, 0, e.SamplesPerBuffer * 4);
Marshal.Copy(buf, 0, e.OutputBuffers[i], e.SamplesPerBuffer * 4);
}
for (int i = 0; i < buf.Length; i = i + 4)
{
float sample = Convert.ToSingle(buf[i] + buf[i + 1] + buf[i + 2] + buf[i + 3]);
sampleAggregator.Add(sample);
}
e.WrittenToOutputBuffers = true;
}
SampleAggregator class
public class SampleAggregator
{
// FFT
public event EventHandler<FftEventArgs> FftCalculated;
public bool PerformFFT { get; set; }
// This Complex is NAudio's own!
private Complex[] fftBuffer;
private FftEventArgs fftArgs;
private int fftPos;
private int fftLength;
private int m;
public SampleAggregator(int fftLength)
{
if (!IsPowerOfTwo(fftLength))
throw new ArgumentException("FFT Length must be a power of two");
this.m = (int)Math.Log(fftLength, 2.0);
this.fftLength = fftLength;
this.fftBuffer = new Complex[fftLength];
this.fftArgs = new FftEventArgs(fftBuffer);
}
public void Add(float value)
{
if (PerformFFT && FftCalculated != null)
{
fftBuffer[fftPos].X = (float)(value * FastFourierTransform.HammingWindow(fftPos, fftLength));
fftBuffer[fftPos].Y = 0; // This is always zero with audio.
fftPos++;
if (fftPos >= fftLength)
{
fftPos = 0;
FastFourierTransform.FFT(true, m, fftBuffer);
FftCalculated(this, fftArgs);
}
}
}
static bool IsPowerOfTwo(int x) => (x & (x - 1)) == 0;
}
public class FftEventArgs : EventArgs
{
public Complex[] Result { get; private set; }
public string resultado = "";
[DebuggerStepThrough]
public FftEventArgs(Complex[] result) => Result = result;
void FftCalculated(object sender, FftEventArgs e)
{
}
}
Well the problem is that when I play a note, the values that are delivered are not affected.

Make variable method

I am currently working on a XP Leveling system in unity. At the moment my code works (this first part is inside the onclick method):
currentExp = Xp.LevelToXP(combat + 1);
if (combatExp + 5 < currentExp)
{
combatExp += 5;
if (previousExp == 0)
{
float fill = (float)(currentExp) / 100;
XpBar.fillAmount += (5 / fill) / 100;
}
else
{
float fill = (float)(currentExp - previousExp) / 100;
XpBar.fillAmount += (5 / fill) / 100;
}
}
else if (combatExp + 5 == currentExp)
{
combatExp += 5;
combat++;
previousExp = currentExp;
XpBar.fillAmount = 0;
}
else if (combatExp + 5 > currentExp)
{
combatExp += 5;
combat++;
previousExp = currentExp;
XpBar.fillAmount = 0;
float remainingExp = (float)combatExp - currentExp;
XpBar.fillAmount += (remainingExp / currentExp) / 100f;
}
txtCombatLvl.text = "Combat Level: " + combat;
this is what happens when you press the button.
but when i try to put all of this in a method instead of the onclick method
void AddExp (int skill, int skillExp, int expAmount)
{
currentExp = Xp.LevelToXP(skill + 1);
if (skillExp + expAmount < currentExp)
{
skillExp += expAmount;
if (previousExp == 0)
{
float fill = (float)(currentExp) / 100;
XpBar.fillAmount += (expAmount / fill) / 100;
}
else
{
float fill = (float)(currentExp - previousExp) / 100;
XpBar.fillAmount += (expAmount / fill) / 100;
}
}
else if (skillExp + expAmount == currentExp)
{
skillExp += expAmount;
skill++;
previousExp = currentExp;
XpBar.fillAmount = 0;
}
else if (skillExp + expAmount > currentExp)
{
skillExp += expAmount;
skill++;
previousExp = currentExp;
XpBar.fillAmount = 0;
float remainingExp = (float)skillExp - currentExp;
XpBar.fillAmount += (remainingExp / currentExp) / 100f;
}
}
And I try to access it by calling it like this:
AddExp(combat, combatExp, 5);
none of my combat xp and level don't save. Can someone point me in the right direction since none of what i tried worked.
The parameters of a C# method are passed by value and not by references, so changes to them inside a function are local to the function. If you want the values updated then you prefix them with the ref keyword.
void AddExp (ref int skill, ref int skillExp, int expAmount)
Alternate Solution
Alternatively, you could simplify your design with an encapsulation of your concept of a Skill with a class. Here's a possibility, I couldn't quite follow your math and am not familiar with your other classes, so you can adjust this as necessary.
public class Skill
{
private string _name;
private int _currentValue;
private int _currentLevel = 1;
public Skill(string name) {
}
public string Name { get { return _name; } }
public int CurrentXp { get { return _currentValue; } }
public int CurrentLevel { get { return _currentLevel; } }
public int XpRequiredForNextLevel { get { return Xp.LevelToXP(_currentLevel + 1); } }
public int XpRequiredForCurrentLevel { get { return Xp.LevelToXP(_currentLevel); } }
private float CalculateFillPercentage(int xp)
{
var xpInLevel = XpRequiredForNextLevel - XpRequiredForCurrentLevel;
return (float)(xp - XpRequiredForCurrentLevel) / (float)xpInLevel;
}
public void AddXp(int expAmount)
{
_currentValue += expAmount;
int XpInCurrentLevel = XpRequiredForNextLevel - XpRequiredForCurrentLevel;
if (_currentValue > XpRequiredForNextLevel) {
} else {
_currentLevel++;
}
XpBar.fillAmount = CalculateFillPercentage (_currentValue);
}
}
You could use this by holding instances of each skill, for example:
Skill combat = new Skill("combat");
And then later
combat.AddXp(50);
Each skill would be self contained. I'm not sure about the XpBar or how that is controlled between different types of skills, but you could further encapsulate by calculating internally, so the skill provides everything your UI needs to keep up to date.

How to update progressbars individually (simultaneous downloads)

I´m currently trying to add parallel downloads to my application but I don´t know how to handle the DownloadProgressChangedEvent to display the progress in multiple progressbars.
I´m using a datagridview with predefined rows for each file the user is able to download and each row has a cell with a progressbar in it.
The problem now is, that I don´t know how to update each progressbar individually, because right now, all selected progressbars are showing the same percentage and they´re just jumping between the progress of download1 & download2.
Here´s the code im using:
To start the downloads:
private void download_button_Click(object sender, EventArgs e)
{
start = DateTime.Now;
download_button.Enabled = false;
Rows = dataGridView1.Rows.Count;
Checked = 0;
CheckedCount = 0;
//count the selected rows
for (i = 0; i < Rows; i++)
{
Checked = Convert.ToInt32(dataGridView1.Rows[i].Cells["checkboxcol"].FormattedValue);
CheckedCount += Checked;
richTextBox3.Text = CheckedCount.ToString();
}
for (int z = 1; z < CheckedCount; z++)
{
_MultipleWebClients = new WebClient();
_MultipleWebClients.DownloadFileCompleted += new AsyncCompletedEventHandler(_DownloadFileCompleted);
_MultipleWebClients.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(_DownloadProgressChanged);
_MultipleWebClients.DownloadFileAsync(new Uri(_downloadUrlList[z].ToString()), #"F:\test" + z + ".mp4");
}
}
(I´m also unable to download more than two files simultaneously - the third download won´t start until the first two are finished)
DownloadProgressChangedEvent:
private void _DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
for (int c = 0; c < CheckedCount; c++)
{
dataGridView1.Rows[_downloadRowNrList[c]].Cells[3].Value = e.ProgressPercentage;
}
float size = ((e.TotalBytesToReceive / 1024) / 1024);
label1.Text = size.ToString();
double dn = (double)e.BytesReceived / 1024.0 / (DateTime.Now - start).TotalSeconds;
label2.Text = (dn.ToString("n") + " KB/s) " + e.ProgressPercentage);
}
The problem probably is, that all progressbars are using the same DownloadProgressChangedEvent, but I´m not sure how to create multiple of these events without knowing the needed number...
So i hope that someone is able to help me with this,
thanks in advance!
What you want to do is use the other DownloadFileAsync method:
http://msdn.microsoft.com/en-us/library/ms144197.aspx
The third parameter is a userToken which gets passed as part of the DownloadProgressChangedEventArgs (it's in the UserState property).
So, when you make the DownloadFileAsync call, pass in a unique token (an integer, or something else) that you can then associate with the progressBar that needs updating.
//(Snip)
//in download_button_Click, pass the row you are updating to the event.
for (int z = 1; z < CheckedCount; z++)
{
_MultipleWebClients = new WebClient();
_MultipleWebClients.DownloadFileCompleted += new AsyncCompletedEventHandler(_DownloadFileCompleted);
_MultipleWebClients.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(_DownloadProgressChanged);
_MultipleWebClients.DownloadFileAsync(new Uri(_downloadUrlList[z].ToString()), #"F:\test" + z + ".mp4", dataGridView1.Rows[z]);
}
}
private void _DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
var rowToUpdate = (DataGridViewRow)e.UserState;
RowToUpdate["ProgressBar"].Value = e.ProgressPercentage;
RowToUpdate["TextProgress"].Value = e.ProgressPercentage;
RowToUpdate["BytesToRecive"].Value = ((e.TotalBytesToReceive / 1024) / 1024).ToString();
double dn = (double)e.BytesReceived / 1024.0 / (DateTime.Now - start).TotalSeconds;
RowToUpdate["Speed"].Value = (dn.ToString("n") + " KB/s) " + e.ProgressPercentage);
}
Sounds like you need a progress bar for multi-parted progress:
public partial class ProgressBarEx : ProgressBar
{
private readonly Dictionary<Guid, double> _partsProgress =
new Dictionary<Guid, double>();
private readonly Dictionary<Guid, double> _partsSizes =
new Dictionary<Guid, double>();
private double _value;
private double _maximum;
public ProgressBarEx()
{
this.InitializeComponent();
}
public int Parts
{
get { return this._partsSizes.Count; }
}
public new int Minimum { get; private set; }
public new double Maximum
{
get { return this._maximum; }
private set
{
this._maximum = value;
base.Maximum = (int)value;
}
}
public new double Value
{
get { return this._value; }
private set
{
this._value = value;
base.Value = (int)value;
}
}
[Obsolete("Not useable in ProgressBarEx.")]
public new int Step
{
get { return 0; }
}
public Guid AddPart(double size)
{
if (size <= 0)
{
throw new ArgumentException("size");
}
var partId = Guid.NewGuid();
this.Maximum += size;
this._partsSizes.Add(partId, size);
this._partsProgress.Add(partId, 0);
return partId;
}
public bool RemovePart(Guid partId)
{
double size;
if (!this._partsSizes.TryGetValue(partId, out size))
{
return false;
}
this.Maximum -= size;
this._partsSizes.Remove(partId);
this.Value -= this._partsProgress[partId];
this._partsProgress.Remove(partId);
return true;
}
public bool ContainsPart(Guid partId)
{
return this._partsSizes.ContainsKey(partId);
}
public double GetProgress(Guid partId)
{
return this._partsProgress[partId];
}
public void SetProgress(Guid partId, double progress)
{
if (progress < 0 || this._partsSizes[partId] < progress)
{
throw new ArgumentOutOfRangeException("progress");
}
this.Value += progress - this._partsProgress[partId];
this._partsProgress[partId] = progress;
}
public void AddProgress(Guid partId, double progress)
{
this.SetProgress(partId, progress + this._partsProgress[partId]);
}
[Obsolete("Not useable in ProgressBarEx.")]
public new void PerformStep()
{
}
}
Example usage:
public Form1()
{
InitializeComponent();
var pbe = new ProgressBarEx {Location = new Point(100, 100)};
this.Controls.Add(pbe);
for (var i = 0; i < 4; i++)
{
var size = i * 10 + 30;
var partId = pbe.AddPart(size);
var pb = new ProgressBar
{
Maximum = size,
Location = new Point(100, i * 30 + 130)
};
this.Controls.Add(pb);
var timer = new Timer {Interval = 1000 + i * 100};
timer.Tick += (sender, args) =>
{
pb.Value += 5;
pbe.AddProgress(partId, 5);
if (pb.Value == pb.Maximum)
{
timer.Stop();
}
};
timer.Start();
}
}

Animate opacity over time in XNA

I would like to animate the opacity value of a text string containing the name of the level in and out with a delay in the middle.
So the sequence of events would be like:
Start transparent
Fade in to solid white over a second of game time
Wait a second
Fade out to transparent again over a second.
The code I have written to animate the alpha value isn't working. Plus, it's pretty ugly and I'm sure there's a better way to do it using the XNA framework.
I've been unable to find any advice elsewhere about doing this. Surely animating values like this isn't that uncommon. How can I do it?
Here's my current code as requested (yes it's horrible).
private int fadeStringDirection = +1;
private int fadeStringDuration = 1000;
private float stringAlpha = 0;
private int stringRef = 0;
private int stringPhase = 1;
...
if (!pause)
{
totalMillisecondsElapsed += gameTime.ElapsedGameTime.Milliseconds;
if (fadestringDirection != 0)
{
stringAlpha = ((float)(totalMillisecondsElapsed - stringRef) / (float)(fadeStringDuration*stringPhase)) * fadeStringDirection;
stringAlpha = MathHelper.Clamp(stringAlpha, 0, 1);
if (topAlpha / 2 + 0.5 == fadeStringDirection)
{
fadeStringDirection = 0;
stringRef = totalMillisecondsElapsed;
stringPhase++;
}
}
else
{
stringRef += gameTime.ElapsedGameTime.Milliseconds;
if (stringRef >= fadeStringDuration * stringPhase)
{
stringPhase++;
fadeStringDirection = -1;
stringRef = totalMillisecondsElapsed;
}
}
}
Here's the solution I have now. Much nicer than what I had before (and in a class of its own).
/// <summary>
/// Animation helper class.
/// </summary>
public class Animation
{
List<Keyframe> keyframes = new List<Keyframe>();
int timeline;
int lastFrame = 0;
bool run = false;
int currentIndex;
/// <summary>
/// Construct new animation helper.
/// </summary>
public Animation()
{
}
public void AddKeyframe(int time, float value)
{
Keyframe k = new Keyframe();
k.time = time;
k.value = value;
keyframes.Add(k);
keyframes.Sort(delegate(Keyframe a, Keyframe b) { return a.time.CompareTo(b.time); });
lastFrame = (time > lastFrame) ? time : lastFrame;
}
public void Start()
{
timeline = 0;
currentIndex = 0;
run = true;
}
public void Update(GameTime gameTime, ref float value)
{
if (run)
{
timeline += gameTime.ElapsedGameTime.Milliseconds;
value = MathHelper.SmoothStep(keyframes[currentIndex].value, keyframes[currentIndex + 1].value, (float)timeline / (float)keyframes[currentIndex + 1].time);
if (timeline >= keyframes[currentIndex + 1].time && currentIndex != keyframes.Count) { currentIndex++; }
if (timeline >= lastFrame) { run = false; }
}
}
public struct Keyframe
{
public int time;
public float value;
}
}

Categories