Winforms window freezes - c#

Winforms C#
I'm implementing a power up system in my snake game and every time i run the method to spawn a power up the window completely stops as if it was processing something heavy but forever. i don't get any error nor windows asking to close window.
this is my script:
private void spawn_powerup()
{
int r = random.Next(0, Powers.Length);
foreach (Power_Up item in Powers)
{
if (item.code == r)
{
bool done = false;
do
{
int X = random.Next(0, grid_size);
int Y = random.Next(0, grid_size);
if (matriz[X, Y] == background_color)
{
matriz[X, Y] = item.Pixel_color;
done = true;
item.placed = true;
}
} while (done);
return;
}
}
}

You never set done to false inside your do-while-loop.
So if within your first iteration your if expression evaluates to true, done is set to true and your do-while runs forever
For what I think you want to achieve change your do-while condition to !done, but then you have to make sure that your if condition is met after some time (but in a snake game this shouldn't be much of an issue).

First of all your while logic is wrong. While loop continues when it is set to true, and exits whenever it gets false or break; command is issued.
Also you are using Synchronous programming pattern. So your application runs on single thread and whenever you call long running function you application start to wait that long running function to finish. Then it resumes continuing.
Please consider to look Asynchronous Programming in C#
Another Reference

Your loop conditions will never allow it to stop, since you wrote while(done), which means: "while done is set to true", which it always is.
You should change you loop to this:
bool done = false;
do
{
(- your code here -)
} while (!done);

Related

Why does my windows form not load? Is it just my build or does this truly not pop anything up?

I am using this code along with other methods after it, but cannot get the form I've been using in designer to pop up. The only thing that pops up successfully is the MessageBox asking the player if they would like to play as X. I've tried commenting that out to see if that's the issue for why it won't load, but I'm completely lost as to why my form will not load at all.
namespace mmelichar_Topic6_Activity13
{
public partial class mmelichar_TicTacToe : Form
{
int player = 0;
int position;
int turn = 0;
int playerMove;
int firstMove;
int secondMove;
string[,] location = new string[3, 3] { { "", "", "" }, { "", "", "" }, { "", "", "" } };
public mmelichar_TicTacToe()
{
InitializeComponent();
}
private void mmelichar_TicTacToe_Load(object sender, EventArgs e)
{
//There's only two moves that have to be hard-coded for AI to be able to
//play tic-tac-toe near perfectly, each game /should/ result in a tie or
//a win for the CPU. Other than that, the tryWin and tryBlock methods
//should be able to win the game if there is an availability for that,
//or block the opponent from winning if they cannot win quite yet.
Random rnd = new Random();
DialogResult dialogResult = MessageBox.Show("Do you want to play as X?", "Player Choice", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
if (dialogResult == DialogResult.Yes)
{
player = 1;
}
else if (dialogResult == DialogResult.No)
{
player = 0;
}
//player is O
if (player == 0 && turn == 0)
{
firstTurnCPU();
//player turn
mre.WaitOne();
}
//player is X
if (player == 1 && turn == 0)
{
//player turn 1
mre.WaitOne();
//cpu turn 1
firstTurnCPU();
//player turn 2
mre.WaitOne();
//cpu turn 2
secondTurnCPU();
//player turn 3
mre.WaitOne();
//cpu turn 3
tryWin();
tryBlock();
//player turn 4
mre.WaitOne();
//cpu turn 4
tryWin();
tryBlock();
//player turn
}
}
private readonly ManualResetEvent mre = new ManualResetEvent(false);
private void playerTurn_EventHandler(object sender, EventArgs e)
{
mre.Set();
}
edit: updated code to remove while loop and include my ManualResetEvent
You have an infinite loop:
while (playing)
{
// perform a bunch of logic
// but probably don't do anything async or properly interact with the UI
}
An infinite loop on the UI threat would certainly prevent the UI from ever drawing to the screen. (It may also be running away with the CPU a lot more than you want it to.)
If you really do want a "game loop" style of game construction, there are approaches you can take in Windows Forms. But now would be a good time to really think through the design of the game before going that route.
Windows Forms is highly event-driven. It's idle most of the time, and responds when users interact with the UI. (A click here, a mouse-over there, etc.) If your game fits that structure (turn based, etc.) then use that structure since it's more native to Windows Forms.
You can also combine the two, using Windows Forms events to process user interactions, but when the program launches you can create a separate thread for your game loop to process ongoing events/logic in the background. Just make sure that loop isn't killing the CPU by constantly running. It's reasonable to sleep the thread for a moment on each iteration of the loop.
I had two problems within my code:
First, an infinite while loop that I forgot to remove, increasing CPU usage needlessly.
Second, use of ManualResetEvent instead of just using normal flow within the program to hand control back and forth from player to CPU and vice-versa.

(C# WPF) I'm using 2 awaits in a loop and they're going all over the place

Here's the code I'm trying to make work:
public async Task PlayAudioAsync(int id)
{
stop = false;
while (!stop)
{
music.Position = TimeSpan.FromSeconds(0);
music2.Position = TimeSpan.FromSeconds(0);
music.Play();
if (id < 1)
{
await Task.Delay(16000);
music2.Play();
await Task.Delay(16000);
}
else
{
await Task.Delay(51200);
music2.Play();
await Task.Delay(51200);
}
}
stop = false;
}
The first question that you'd ask first is probably that why am I using two music players? I want the end of the sound loops play as well, there's reverb effects and the notes fade smoothly.
The second loop should start after 16 seconds if id is 0.
The first loop should restart after 16 seconds is id is 0.
In this case, the id is 0.
What happens?
First time they play as they should.
After that they either don't play at all or play at the same time.
After that they do the opposite of what they just did.
And so on...
Also this is my first post, so I almost know what I'm doing here...

Asynchronous method call in C#

We have such a situation. We have a canvas, on which some ammount of figures are rendered. It may be 1 or many more (for example thousand) and we need to animate their translation to another location (on button click) using storyboard:
internal void someStoryBoard(figure someFigure, double coordMoveToValue)
{
string sbName = "StoryBoard_" + figure.ID;
string regName = "figure_" + figure.ID;
try
{
cnvsGame.Resources.Remove(sbName);
cnvsGame.UnregisterName(regName);
}
catch{ }
someCanvas.RegisterName(regName, someFigure.Geometry);
var moveFigureYAnimation = new PointAnimation();
moveFigureYAnimation.From = new Point(someFigure.Geometry.Center.X, someFigure.Geometry.Center.Y);
moveFigureYAnimation.To = new Point(someFigure.eGeometry.Center.X, coordMoveToValue);
moveFigureYAnimation.Duration = TimeSpan.FromSeconds(0.5);
var sbFigureMove = new Storyboard();
Storyboard.SetTargetName(sbFigureMove, regName);
Storyboard.SetTargetProperty(sbFigureMove, new PropertyPath(Geometry.CenterProperty));
sbFigureMove.Children.Add(moveFigureYAnimation);
cnvsGame.Resources.Add(sbName, sbFigureMove);
sbFigureMove.Begin();
}
Figures are stored in list. We are calling this StoryBoard using for loop:
for(int i = 0; i<listOfFigures.Count; i++)
{
someStoryBoard(listOfFigures[i], someCoord);
}
But here's the problem: if we have a little amount of figures - code completes quickly. But if ammount is big - there is a delay after a button is clicked and before the figures begin to move.
So, here's the question: is it possible to call someStoryBoard method asynchronously? Is next algorithm possible -> When someStoryBoard is called it begins to move figure instantly, not waiting for whole for loop to complete.?
You can add actions into Dispatcher queue by calling Dispatcher.InvokeAsync. You can also specify dispatcher priority, depending on your requirements.
Please note that moving thousands of items can't be reliably fast, so you may need to rethink the drawing logic. If even starting animation is slow, it's highly likely animating won't be fast enough too.
You can try use async/await modifier
async internal Task someStoryBoard(figure someFigure, double coordMoveToValue)

Unity IEnumerator, waiting but no longer executing called function fully anymore

I am writing a game with some logic that records player actions and then replays them in the same sequence at the same timing but with other influences involved at a later date.
So far I have the code sort of working, it records perfectly as I require it, and then plays back the sequence perfectly, but the issue has been timing.
As an simple example. If the character is to walk from A -> B -> C but to wait for x time at B, then the code easily traverses the path, but will not stop at B for the given time.
So I wrote a couple of functions that I thought might handle this as you can see here.
private IEnumerator followSequence()
{
// Loop through each action steps in sequence.
foreach (Action step in sequence)
{
//Check if the action time is less than the current clock time.
Debug.Log("Step.tick: " + step.tick + " || Clock.tick: " + clock.getTick());
if (clock.getTick() < step.tick)
{
//If so wait out the difference to resync the action.
yield return new WaitForSeconds(step.tick - clock.getTick());
}
// Carry out the step.
play(step);
}
yield break;
}
private void play(Action step)
{
Debug.Log(step.type);
// Set up a followpath script
FollowPath follow = (player.GetComponent<FollowPath>() ? player.GetComponent<FollowPath>() : player.AddComponent<FollowPath>());
// Tell the follow path script that object is not a guard.
follow.isGuard = false;
// Create a new point object on the map
Transform aPoint = (Transform)Instantiate(PathPoint, step.point, Quaternion.identity);
path.points.Add(aPoint);
// Initiate movement.
follow.Path = path;
follow.TravelPath();
// Check if action is an objective.
if (step.type == Action.Type.Action)
{
step.actions.OnClick();
}
}
Now if I comment out the *yield return new WaitForSeconds()* part in the first function, the code works as expected and completes the step in the sequence just not to the given timing.
When the same code is not commented out, then the timings work perfectly and the 2nd *Debug.log("step.type")* is called at the exact right time, however the character no longer moves, I.E. the *follow.TravelPath()* never seems to be executed.
I have tried making the 2nd function an IEnmerator and yielding to it. I have tried a custom wait() function. I have tried yielding to the TravelPath() function.
Has anyone any more ideas I have follow up or where I could look to try and resolve this?
Edit:
Code that calls followSequence() as requested:
private void playActions()
{
// Reset player immediately to the starting position
player.transform.position = sequence[0].point;
// Stop the character and freeze the scene when alarm sounds!.
player.GetComponent<IncrementController>().freeze();
player.GetComponent<IncrementController>().enabled = false;
// Restart the clock and scene.
clock.Restart();
sceneManager.restart();
// Activate guard and remove sphere.
guard.SetActive(true);
guardShere.SetActive(false);
// Stop recording;
recording = false;
line.SetActive(false);
// Start playback sequence.
StartCoroutine(followSequence());
}
The behavior is as expected, on the line there you do yield return the execution of the context is paused until you do MoveNext() (which does apparently never happen) on the enumerator, which is returned by followSequence.
But as far as I can see from the comments, you just want to wait for some seconds for resync so you don't need to return at all. In your case I don't see any reason why you might need an Enumerable of WaitForSeconds if you just want to skip some time. Without to know how you you call the function and the implementation of WaitForSeconds I would suggest you to change it's return type to void.
private void followSequence()
{
// Loop through each action steps in sequence.
foreach (Action step in sequence)
{
//Check if the action time is less than the current clock time.
Debug.Log("Step.tick: " + step.tick + " || Clock.tick: " + clock.getTick());
if (clock.getTick() < step.tick)
{
//If so wait out the difference to resync the action.
new WaitForSeconds(step.tick - clock.getTick());
}
// Carry out the step.
play(step);
}
}

Finish playing a sound before continuing with execution

I am trying to make my application play a quick .wav before closing the application, but every time it only plays the .wav and does not exit the application. Here is my code:
bool condition = false;
if (condition)
{
SoundPlayer sndPlayer = new SoundPlayer(Project_Rage_v3._1.Properties.Resources.syl);
sndPlayer.Play();
}
else
{
Application.Exit();
}
I know if the bool == true it will do the if function and if the bool == false it will do the else function. But if I don't split them up, the program just quits immediately without playing the sound.
How do I have it play the sound then quit, but only quit after the sound is finished playing?
Remove the else block. You're telling the program to play the sound if condition is true, and exit if condition is false. Put the commands in sequential order and call PlaySync instead of Play (MSDN). This will block the rest of the code from executing until the playing is finished.
bool condition = false;
if (condition)
{
SoundPlayer sndPlayer = new SoundPlayer(Project_Rage_v3._1.Properties.Resources.syl);
sndPlayer.PlaySync();
Application.Exit();
}

Categories