Reputation: 35
I'm working on a video poker style arcade game using WinForms in C#. When the player clicks the "Deal" button, the 5 PictureBoxes on the form switch from a face down card image to face up card images. I have no trouble getting them to flip all at once, but I wanted there to be a slight delay between each card so they reveal from left-to-right.
I found an example from the official Microsoft .NET docs (second example on this page) which uses the Timer in such a way that it will only loop through a set number of times, perfect for me since I just want to flip the 5 cards.
When I use that example in my game though, something odd happens. The cards reveal in pairs of two from left-to-right instead of one at a time. When I set a breakpoint and step through, my counter is indeed incrementing by one, but the form only updates the images on every other pass.
Why is this happening? And what can I do to fix it?
Deal Button Click:
private void dealdraw_button1_Click(object sender, EventArgs e)
{
// If we are dealing a new hand...
if (dealPhase == "deal")
{
// Change game phase
dealPhase = "draw";
// Generate a new deck of cards
deck = new Deck();
// Shuffle the deck
deck.Shuffle();
// Deal five cards to the player
playerHand = deck.DealHand();
// Start timer loop
InitializeTimer();
// Enable "Hold" buttons
for (int i = 0; i < 5; i++)
{
playerHoldButtons[i].Enabled = true;
}
}
}
InitializeTimer():
private void InitializeTimer()
{
counter = 0;
timer1.Interval = 50;
timer1.Enabled = true;
// Hook up timer's tick event handler.
this.timer1.Tick += new System.EventHandler(this.timer1_Tick);
}
Timer1_Tick:
private void timer1_Tick(object sender, EventArgs e)
{
if(counter >= 5)
{
// Exit loop code
timer1.Enabled = false;
counter = 0;
}
else
{
playerHandPictureBoxes[counter].Image = cardFaces_imageList1.Images[playerHand[counter].imageListIndex];
counter = counter + 1;
}
}
Upvotes: 1
Views: 280
Reputation: 552
The issue in your InitializeTimer method. the cultprit is you are adding Tick event handler again and again in each click.
public partial class Form1 : Form
{
PictureBox[] playerHandPictureBoxes = new PictureBox[5];
int counter = 0;
public Form1()
{
InitializeComponent();
CreateCards();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void CreateCards()
{
int pWidth = 50;
int left = 10;
for (int i = 0; i < playerHandPictureBoxes.Length; i++)
{
playerHandPictureBoxes[i] = new PictureBox
{
Top = 10,
Left = left + (left * i) + (i * pWidth),
BackColor = Color.Red,
Width = pWidth,
Height = 50,
BackgroundImage = imageList1.Images[0],
BackgroundImageLayout = ImageLayout.Stretch
};
}
this.Controls.AddRange(playerHandPictureBoxes);
}
private void InitializeTimer()
{
counter = 0;
timer1.Interval = 500;
timer1.Enabled = true;
// Detach any previouly added event handlers
this.timer1.Tick -= Timer1_Tick;
// Hook up timer's tick event handler.
this.timer1.Tick += Timer1_Tick;
}
private void Timer1_Tick(object sender, EventArgs e)
{
if (counter >= 5)
{
// Exit loop code
timer1.Enabled = false;
counter = 0;
}
else
{
playerHandPictureBoxes[counter].BackgroundImage = imageList1.Images[1];
counter += 1;
}
}
private void btnDeal_Click(object sender, EventArgs e)
{
InitializeTimer();
// Enable "Hold" buttons
//for (int i = 0; i < 5; i++)
//{
// playerHoldButtons[i].Enabled = true;
//}
}
}
Upvotes: 1
Reputation: 65584
I think you want the Invalidate method causes a Repaint event to occur:
playerHandPictureBoxes[counter].Image = cardFaces_imageList1.Images[playerHand[counter].imageListIndex];
playerHandPictureBoxes[counter].Invalidate();
There are two ways to repaint a form and its contents:
- You can use one of the overloads of the Invalidate method with the Update method.
- You can call the Refresh method, which forces the control to redraw itself and all its children. This is equivalent to setting the Invalidate method to true and using it with Update.
The Invalidate method governs what gets painted or repainted. The Update method governs when the painting or repainting occurs. If you use the Invalidate and Update methods together rather than calling Refresh, what gets repainted depends on which overload of Invalidate you use. The Update method just forces the control to be painted immediately, but the Invalidate method governs what gets painted when you call the Update method.
You might want to either increase the Timers Interval or the counter, 250 ms is a bit quick/short to see an animation.
Upvotes: 1
Reputation: 1245
I wanted to add this as a comment but my reputation does not allow this.
You can try playerHandPictureBoxes[counter].Image.Update();
after setting the image. Haven't tested it though.
Upvotes: 0