Keydown event and timer is not working good together - c#

I'm kinda new to both Keys event and timers in my code but for some reason there is this weird bug. (read the last edit)
public partial class Form1 : Form
{
bool start = false;
Snake ormen = new Snake(10);
short direction = 3;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Hide();
timer1.Enabled = true;
start = true;
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Graphics g = e.Graphics;
if (start)
{
ormen.rita(g);
}
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
direction = 3;
break;
case Keys.Down:
direction = 1;
break;
case Keys.Left:
direction = 2;
break;
case Keys.Right:
direction = 0;
break;
default:
break;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
ormen.flytta(direction);
Invalidate();
}
}
}
I also tried to use debug at the key event but it does not even activate until after the time period. Can anyone please tell me why? Also if there are any obvious mistakes i would appreciate it if you could mention them. I have also tried to make the timer interval higher to check if the program can't keep up but it can. (read the last edit)
[EDIT] I don't think it will help but here is the code for the class "Snake". I doubt it's a problem in there but anyways.
private short diameter = 0;
//0 = Right, 1 = Down, 2 = Left, 3 = Up
public Snake(short diameter)
{
this.diameter = diameter;
ormensPlatser.Enqueue(new Point(0, 0));
ormensPlatser.Enqueue(new Point(0 + diameter, 0));
ormensPlatser.Enqueue(new Point(0 + diameter + diameter, 0));
}
Queue<Point> ormensPlatser = new Queue<Point>();
public void rita(Graphics g)
{
Point temp;
for (int i = 0; i < ormensPlatser.Count; i++)
{
temp = ormensPlatser.Dequeue();
g.FillEllipse(new SolidBrush(Color.Red), temp.X, temp.Y, diameter, diameter);
ormensPlatser.Enqueue(temp);
}
}
private void ormNäraKant(short direction,ref Point ormBit)
{
switch (direction)
{
case 0:
ormBit.X = ormBit.X + diameter >= 380 ? 0 : ormBit.X + diameter;
break;
case 1:
ormBit.Y = ormBit.Y + diameter >= 360 ? 0 : ormBit.Y + diameter;
break;
case 2:
ormBit.X = ormBit.X - diameter < 0 ? 370 : ormBit.X - diameter;
break;
case 3:
ormBit.Y = ormBit.Y - diameter < 0 ? 350 : ormBit.Y - diameter;
break;
}
}
public void flytta(short direction)
{
Point temp;
int temp1 = ormensPlatser.Count - 1;
for (int i = 0; i < ormensPlatser.Count; i++)
{
if (i == temp1)
{
switch(direction)
{
case 0:
temp = ormensPlatser.Dequeue();
ormNäraKant(0, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 1:
temp = ormensPlatser.Dequeue();
ormNäraKant(1, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 2:
temp = ormensPlatser.Dequeue();
ormNäraKant(2, ref temp);
ormensPlatser.Enqueue(temp);
break;
case 3:
temp = ormensPlatser.Dequeue();
ormNäraKant(3, ref temp);
ormensPlatser.Enqueue(temp);
break;
}
}
else
{
ormensPlatser.Dequeue();
temp = ormensPlatser.Peek();
ormensPlatser.Enqueue(temp);
}
}
}
}
}
[EDIT2] Okey, apparently it wasn't about the time or anything like that, the code worked but i think it has something to do with what slawekwin said in the comments about the focus when the program starts. So the problem is still the same but if I ALT+tab to a another program then back to the snake program it works.

SO i finally figure it out, i thought that the problem was with the timer event and the key input event when they worked together but my assumption was wrong. So what i did is that i went through all the properties that the form has and i found a setting called "KeyPrevied" and it was false so i tried to set it to true and it worked :).

Related

How do I use a timer/ delay to make an object or a character move in Console Window?

I'm trying to create a console game where character 'M' as in "Martian" and character 'S' as in "SpaceCreature" stay opposite on both ends on the X axis and move up and down across Y axis.
I use arrow keys to make the 'M' move up and down. But the 'S' should also move but by itself whenever 'M' moves. I need to make the 'S' move at a slower pace to follow the 'M'.
As of now, I got 'M' moving up and down using arrow keys and 'S' is also moving at the same time.
I need to make the 'S' move slower. I have tried thread.Sleep, but that just makes the 'S' disappear and appear back like a glitch. I think I need to use something called "Console.keyAvailable" but I am finding it hard on where to place that function.
//X and Y get set constructors are defined in the abstract class:-SpaceObject
public override void Draw() //In both classes Martian and SpaceCreature
{
Console.SetCursorPosition(X, Y);
Console.WriteLine("S");
//In Martian class:- Console.WriteLine("M");
}
static void Main(string[] args)
{
var m = new Martian(100, 10);
var s = new SpaceShip(100, 10);
const int MaxY = 25;
m.Draw(); //Abstract override void method
s.X = m.X + 100;
s.Y = m.Y;
s.Draw(); //Abstract override void method
ConsoleKeyInfo keyInfo;
while (true)
{
keyInfo = Console.ReadKey(true);
Console.Clear();
switch (keyInfo.Key)
{
case ConsoleKey.UpArrow:
if (m.Y > 0)
{
m.Y--;
}
break;
case ConsoleKey.DownArrow:
if (m.Y < MaxY)
{
m.Y++;
}
break;
}
m.Draw();
s.X = m.X + 100;
s.Y = m.Y;
s.Draw();
}
}
}
You don't need another thread...play with this. Press the up/down arrows or escape to quit; you do NOT have to hold down the arrow keys for continued movement. You may also be interested in my Console Snake example.
class Program
{
enum Directions
{
Up,
Down,
None
}
static void Main(string[] args)
{
DateTime next;
bool quit = false;
ConsoleKeyInfo cki;
Directions direction = Directions.None;
Console.Clear();
Console.CursorVisible = false;
var m = new Martian();
var s = new SpaceShip();
m.Draw(true);
s.Draw(true);
do
{
// wait for next keypress, or next movement
next = new DateTime(Math.Min(m.nextMovement.Ticks, s.nextMovement.Ticks));
while(!Console.KeyAvailable && DateTime.Now < next)
{
System.Threading.Thread.Sleep(10);
}
// was a key pressed?
if (Console.KeyAvailable)
{
cki = Console.ReadKey(true);
switch (cki.Key)
{
case ConsoleKey.UpArrow:
direction = Directions.Up;
break;
case ConsoleKey.DownArrow:
direction = Directions.Down;
break;
case ConsoleKey.Escape:
quit = true;
break;
}
}
// does anything need to move?
if (DateTime.Now >= m.nextMovement)
{
switch(direction)
{
case Directions.Up:
m.MoveUp();
break;
case Directions.Down:
m.MoveDown();
break;
case Directions.None:
m.UpdateNextMovement();
break;
}
}
if (DateTime.Now >= s.nextMovement)
{
s.MoveToward(m);
}
} while (!quit);
}
}
public abstract class SpaceObject
{
public int X;
public int Y;
public int MovementDelay;
public DateTime nextMovement;
abstract public void Draw(bool Visible);
public void MoveUp()
{
if (this.Y > 0)
{
this.Draw(false);
this.Y--;
this.Draw(true);
}
this.UpdateNextMovement();
}
public void MoveDown()
{
if (this.Y < Console.WindowHeight - 1)
{
this.Draw(false);
this.Y++;
this.Draw(true);
}
this.UpdateNextMovement();
}
public void MoveToward(SpaceObject so)
{
if (so.Y < this.Y)
{
this.MoveUp();
}
else if (so.Y > this.Y)
{
this.MoveDown();
}
else
{
this.UpdateNextMovement();
}
}
public void UpdateNextMovement()
{
this.nextMovement = DateTime.Now.AddMilliseconds(this.MovementDelay);
}
}
public class Martian : SpaceObject
{
public Martian()
{
this.X = 1;
this.Y = Console.WindowHeight / 2;
this.MovementDelay = 100;
this.nextMovement = DateTime.Now.AddMilliseconds(this.MovementDelay);
}
public override void Draw(bool Visible)
{
Console.SetCursorPosition(this.X, this.Y);
Console.Write(Visible ? "M" : " ");
}
}
public class SpaceShip : SpaceObject
{
public SpaceShip()
{
this.X = Console.WindowWidth - 2;
this.Y = Console.WindowHeight / 2;
this.MovementDelay = 750;
this.nextMovement = DateTime.Now.AddMilliseconds(this.MovementDelay);
}
public override void Draw(bool Visible)
{
Console.SetCursorPosition(this.X, this.Y);
Console.Write(Visible ? "S" : " ");
}
}
----- EDIT -----
How do I make the 'M' movement by tapping up/ down arrow keys instead
of making continuous movement?
Change the "was a key pressed" block to:
// was a key pressed?
if (Console.KeyAvailable)
{
cki = Console.ReadKey(true);
switch (cki.Key)
{
case ConsoleKey.UpArrow:
m.MoveUp();
break;
case ConsoleKey.DownArrow:
m.MoveDown();
break;
case ConsoleKey.Escape:
quit = true;
break;
}
}
Then delete the if (DateTime.Now >= m.nextMovement) block so you are only left checking for the SpaceShip time below. Now your "M" should only move when you tap and/or hold down the arrow keys.
Did you try to put Thread.Sleep(100); right after s.Y = m.Y; and didn't work?
Changing sleep time to shorter times might work.
Also:
while (true)
{
keyInfo = Console.ReadKey(true);
Console.Clear();
switch (keyInfo.Key)
{
case ConsoleKey.UpArrow:
if (m.Y > 0)
{
m.Y--;
}
break;
case ConsoleKey.DownArrow:
if (m.Y < MaxY)
{
m.Y++;
}
break;
}
}
m.Draw();
s.X = m.X + 100;
s.Y = m.Y;
s.Draw(); //i think is better to put draw functions outside switch(key)
}

C# Form, trying to change random pictureBox to a random image with timer

What I'm trying to do is this:
I want the 4 pictureBoxes I got in the form to get the faces of card - turn them over I mean. a random card from the 4 will be chosen, turned over and show the face of the card being chosen also randomley.
Once a card is turned over, it cant be turend over again in the next timer interval, and once all cards had been turned over, a messageBox appears and once the user presses ok, it all restarts.
Problem is: the messageBox keeps appearing over and over again, because of the flag positive value. I don't know which variable should I use to prevent that from happening.
Relevant code:
//This function is the timer's function, it starts every time interval:
private void cardsChangingTimer_Tick(object sender, EventArgs e)
{
int chosenImage = rnd.Next(1, 17);
int chosenCard = rnd.Next(0, 4);
if (bucketArr[chosenCard] == 0)
{
bucketArr[chosenCard]++;
switch (chosenCard)
{
case 0:
card1Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 1:
card2Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 2:
card3Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
case 3:
card4Pic.Image = Image.FromFile("cards\\" + chosenImage + ".png");
break;
}
}
gameEnded = true;
for (int i = 0; i < bucketArr.Length; i++)
{
if (bucketArr[i] == 0)
{
gameEnded = false;
break;
}
}
if (gameEnded)
{
DialogResult dialog = MessageBox.Show("All 4 cards were turned over...");
if (dialog == DialogResult.OK)
{
card1Pic.Image = Image.FromFile("..\\..\\17.png");
card2Pic.Image = Image.FromFile("..\\..\\17.png");
card3Pic.Image = Image.FromFile("..\\..\\17.png");
card4Pic.Image = Image.FromFile("..\\..\\17.png");
}
gameEnded = false;
for(int i = 0; i < bucketArr.Length; i++)
bucketArr[i] = 0;
}
}
Thanks alot for any help...
The problem you are having is the timer is continuing to run while the dialog box is shown. Simply stop the timer before the MessageBox is shown then restart the timer after the box returns.
private void cardsChangingTimer_Tick(object sender, EventArgs e)
{
int chosenImage = rnd.Next(1, 17);
int chosenCard = rnd.Next(0, 4);
/// ... Rest of the code goes here
break;
}
}
if (gameEnded)
{
//Get a reference to the timer and stop it.
var timer = (Timer)sender;
timer.Stop();
DialogResult dialog = MessageBox.Show("All 4 cards were turned over...");
if (dialog == DialogResult.OK)
{
card1Pic.Image = Image.FromFile("..\\..\\17.png");
card2Pic.Image = Image.FromFile("..\\..\\17.png");
card3Pic.Image = Image.FromFile("..\\..\\17.png");
card4Pic.Image = Image.FromFile("..\\..\\17.png");
}
gameEnded = false;
for(int i = 0; i < bucketArr.Length; i++)
bucketArr[i] = 0;
//start the timer here after everything has been re-initialized.
timer.Start();
}
}

How to keep picturebox in the form while moving it?

I'm trying to make a single game, but I got a little problem here...
I'm moving a picturebox with the arrow keys, to avoid other pictureboxes... The problem is, that my picturebox moves out of the form when I press the left key too many times... I succeeded in solving this problem with the right side(by blocking the picturebox with an another), but the left side version still doesn't works, and I don't know why...
Here is the code:
if (pictureBox7.Bounds.IntersectsWith(pictureBox1.Bounds))
switch (e.KeyCode)
{
case Keys.Escape: Application.Exit(); break;
case Keys.P: timerkunai1.Enabled = false;
timerkunai2.Enabled = false; timerkunai3.Enabled = false;
timerkunai4.Enabled = false; timerninja.Enabled = false;
timerlife.Enabled = false;
button3.Show(); break;
case Keys.Right: i = 6; dx = 25; press = true; break;
}
if (pictureBox8.Bounds.IntersectsWith(pictureBox1.Bounds))
switch (e.KeyCode)
{
case Keys.Escape: Application.Exit(); break;
case Keys.P: timerkunai1.Enabled = false;
timerkunai2.Enabled = false; timerkunai3.Enabled = false;
timerkunai4.Enabled = false; timerninja.Enabled = false;
timerlife.Enabled = false;
button3.Show(); break;
case Keys.Left: i = 0; dx = -25; press = true; break;
}
else
switch (e.KeyCode)
{
case Keys.Escape: Application.Exit(); break;
case Keys.P: timerkunai1.Enabled = false;
timerkunai2.Enabled = false; timerkunai3.Enabled = false;
timerkunai4.Enabled = false; timerninja.Enabled = false;
timerlife.Enabled = false;
button3.Show(); break;
case Keys.Left: i = 0; dx = -25; press = true; break;
case Keys.Right: i = 6; dx = 25; press = true; break;
}
You need code to check if the picturebox's bounds are outside of the form. If the picturebox movement will cause it to be outside the bounds then prevent the motion.
Something like this pseudocode:
if (pictureBoxZ + dx < 0 || pictureBoxZ + dx > pictureBoxZ.Parent.Width) { //Deny Motion }
Is your dx variable an offset to the new Location of the PictureBox?
Then limit the Location.x to 0:
if (pictureBox1.Location.x + dx > 0)
pictureBox1.Location += dx;
If you want to limit to left and right size, to the width of the Form use this code:
if ((pictureBox1.Location.x + dx > 0) && (pictureBox1.Location.x + dx < this.Size.Width - pictureBox1.Size.Width))
pictureBox1.Location += dx;

Override paint method C#

I have two forms Form 1 and Form 2.
Form 2 is inheriting from Form 1. In Form 1 I have a method on_Paint for a particular panel, in which I am drawing an image. Since Form 2 is inheriting from Form 1, the panel is being shown as painted before I even run the program (on the design of Form 2).
The problem is, that now I need to paint some things over this image after the image is painted in Form 2. How can I make this possible?
This is some code to make the problem more clear.
// This is Form 1 on_Paint method
private void grid_Paint(object sender, PaintEventArgs e)
{
Image img = Image.FromFile(resourcesPath+ "grid.fw.png");
gridGraphics = grid.CreateGraphics();
gridGraphics.DrawImage(img, 0, 0, 650, 550);
}
// This is the method which I want to be invoked after the grid is painted.. This is located in Form 1:
public void paintSprites(int row, int column, int value)
{
int yLoc = 0;
int xLoc = 0;
Graphics g = grid.CreateGraphics();
switch (row)
{
case 0: yLoc = 435; break;
case 1: yLoc = 355; break;
case 2: yLoc = 275; break;
case 3: yLoc = 195; break;
case 4: yLoc = 115; break;
case 5: yLoc = 35; break;
}
switch (column)
{
case 0: xLoc = 35; break;
case 1: xLoc = 120; break;
case 2: xLoc = 205; break;
case 3: xLoc = 290; break;
case 4: xLoc = 375; break;
case 5: xLoc = 460; break;
case 6: xLoc = 545; break;
}
if (value == 1)
{
g.DrawImage(red, xLoc, yLoc, 65, 65);
}
else g.DrawImage(gold, xLoc, yLoc, 65, 65);
}
This method is located in Form 2 and calls the method above:
public void checkWhichToPaint()
{
for (int i = 0; i < ROWS; i++)
{
for (int j = 0; j < COLUMNS; j++)
{
if (gridMap[i, j] != 0)
{
paintSprites(i, j, gridMap[i, j]);
}
}
}
}
and I am calling the method checkWhichToPaint() after creating a new instance of Form 2 and Showing it:
Tournament tournament = new Tournament();
tournament.LoadGame();
tournament.Show();
tournament.checkWhichToPaint();
where can I call this method such as it is painted after the grid_Paint is invoked?
Thanks for your help :)
This is the answer to whoever might need it!
In Form 1:
protected virtual void grid_Paint(object sender, PaintEventArgs e)
{
Image img = Image.FromFile(resourcesPath+ "grid.fw.png");
gridGraphics = grid.CreateGraphics();
gridGraphics.DrawImage(img, 0, 0, 650, 550);
}
In Form 2:
protected override void grid_Paint(object sender, PaintEventArgs e)
{
checkWhichToPaint();
base.grid_Paint(null, null);
}
Enjoy ! :)
Override the paint method in the second form and call base paint method before you run your form 2 code.

Problem to move many images in c#

I wanna write an application to do below job:
We have 15 different location (that we present them with point (x1,y1) for first location, point (x1,y2) for second location and so on point (x1,y15) for last location).
100 image must to be shown at this locations (with specific order) with pictureBox.
Each image that shown, must start to move horizontally to reach new point (e.g. point (Xc, Yc) ) and then move vertically and so on…
When the image reach to specific point (e.g. point (Xm,Ym) ), we decide that it must continue moving or it must destroy (with probability 20%) (which means that we can create next image at that initial location).
For example, an image create at location (Xi,Yi) with pictureBox1. Then it’s not allowed to create any more image at location (Xi,Yi) until pictureBox1 destroy or return to its initial location.
What I have written so far is:
create 15 location.
move one image to reach point (Xc,Yc).
I’ve some problems:
I use one timer to move an image. But I want to move 100 images. (from each 15 location, we create images and move them until we destroy them and then create next image).
So what I must to do? Use 15 timer for each location?!but How?
at specific point (e.g. point (Xk,Yk) ), the image must stop moving for random seconds and then continue moving. How I should do this? With another timer?!But how?
when image reach point (Xc,Yc) and with we decide to destroy it or not, nothing happen in my code…I don’t know why!
I’ve add an picture of what I want HERE
Here is my code so far:
public partial class Form1 : Form
{
Random r = new Random();
// falg to prevent create just one image at each location
private Boolean[] createNext = {true,true,true,true,true,true,true,
true,true,true,true,true,true,true,true};
private void setImage()
{
int i = 1 + r.Next() % 15;
while (createNext[i] != true)
i = 1 + r.Next() % 15;
switch (i)
{
case 1: pictureBox1.ImageLocation = "grin.png";
break;
case 2: pictureBox2.ImageLocation = "grin.png";
break;
case 3: pictureBox3.ImageLocation = "grin.png";
break;
case 4: pictureBox4.ImageLocation = "grin.png";
break;
case 5: pictureBox5.ImageLocation = "grin.png";
break;
case 6: pictureBox6.ImageLocation = "grin.png";
break;
case 7: pictureBox7.ImageLocation = "grin.png";
break;
case 8: pictureBox8.ImageLocation = "grin.png";
break;
case 9: pictureBox9.ImageLocation = "grin.png";
break;
case 10: pictureBox10.ImageLocation = "grin.png";
break;
case 11: pictureBox11.ImageLocation = "grin.png";
break;
case 12: pictureBox12.ImageLocation = "grin.png";
break;
case 13: pictureBox13.ImageLocation = "grin.png";
break;
case 14: pictureBox14.ImageLocation = "grin.png";
break;
case 15: pictureBox15.ImageLocation = "grin.png";
break;
}
}
private int k = 0;
private Boolean destroy = true;
// timer that move pictureBox1
void timer_Tick(object sender, EventArgs e)
{
k++;
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
if (k <= 150)//go right 300 in 150 ticks
pictureBox1.Location = new Point(x + 2, y);
else if (k <= 300)
{
if (y < 200)
pictureBox1.Location = new Point(x, y + 1);
if (y > 200)
pictureBox1.Location = new Point(x, y - 1);
}
else if (k <= 400)
pictureBox1.Location = new Point(x + 2, y);
else if (k <= 550)
{
if (destroy == false)
pictureBox1.Location = new Point(x + 2, y);
if (destroy == true)
pictureBox1.Location = new Point(x, y - 3);
}
else if (k <= 650)
pictureBox1.Location = new Point(x, y - 1);
else if (k <= 850)
pictureBox1.Location = new Point(x - 2, y);
else if (k <= 950)
pictureBox1.Location = new Point(x, y + 1);
else
timer1.Stop();
}
public Form1()
{
InitializeComponent();
for (int i = 0; i < 15; i++)
{
setImage();
timer1.Start();
timer1.Interval = 15;
timer1.Tick += new EventHandler(timer_Tick);
}
}
Please help me to complete this application.
Thanks in advance.
You should probably just use one timer, and make a number of instances of a class that represents your moving picturebox. (This class would contain the points it will go to, ordered to the first point is always your next destination. Also it will contain the picturebox.. etc).
enum Action
{
None,
Stop,
CheckDestroy
}
class InterestingPoint
{
Point m_Point;
Action m_Action;
}
class MovingImage
{
public bool DestroyMe {get; private set; }
PictureBox m_PictureBox;
List<InterestingPoint> m_PointsToVisit;
int m_StoppedUntil = 0;
MovingImage(...)
{
// Constructor
}
void Update(int k)
{
if(m_StoppedUntil > k) return;
//Move m_PictureBox towards m_PointsToVisit.First
//when m_PictureBox.Location == m_PointToVisit.First, check if the InterestingPoint
//has a action you need to handle,
//like if the action is stop, you set m_StoppedUntil to k+ the number of frames you
//want the picturebox to stay still. (m_StoppedUntil = k+10 => doesnt update for 10 frames)
//if the action is checkdestroy, see if it shall be destroyed and set DestroyMe to true
}
So, you initialize your MovingImage objects with a picturebox and list of point it should move to, these points contain a action for the object to execute when it arrives there.
Keep your MovingImages in a list of some kind and iterate over them to update them.
In your Timer_Tick you do something like
void timer_Tick(object sender, EventArgs e)
{
k++
foreach(MovingImage m in m_MyMovingImages)
{
m.Update(k);
if(m.DestroyMe)
{
//Destroy it.
}
}
}

Categories