I have this Code:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if(e.KeyData == Keys.Left)
{
left = true;
right = false;
down = false;
}
}
private void timerMoving_Tick(object sender, EventArgs e)
{
if(Ghost.Bounds.IntersectsWith(panel3.Bounds))
{
timerMoving.Stop();
}
if(left)
{
Ghost.Left -= 5;
timerMoving.Start();
}
}
In the above code as my Ghost(which is moving down) hits the panel3 boundary it stops.
I want my timer to start again as i press Left,Right or up key and only stop when it's moving down,hitting panel3. I tried doing this:
if(left)
{
Ghost.Left -= 5;
timerMoving.Start();
}
but nothing happens, Why?
The simple (though not the optimal) way to achieve this goal pertinent to your task description is by adding the line shown in the following code snippet:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.Left)
{
// add this line
if(!timerMoving.Enabled) timerMoving.Start();
left = true;
right = false;
down = false;
up = false;
}
}
and removing this line as shown below:
if (left)
{
Ghost.Left -= 5;
//timerMoving.Start(); - comment off
}
Hope this may help.
Related
I am working on Winforms with C#.
I have a problem with the logic, there are two different methods that I need to call, so that if I click the button, the first action should get applied and if I click the same button again, the second action should get applied.
This is not the exact code but I have an idea something like this:
private void button1_Click(object sender, EventArgs e)
{
if(button1.click==true)
{
fileNumber = 1;
ImgSave();
}
else
{
ImgSave.exit();
}
}
Here I have two problems regarding whether the button is already clicked:
If it's not clicked the Imgsave() should get activated.
If button is clicked the Imgsave() should get closed.
Can anyone please help me with this? Thanks.
You need to keep state somewhere. You can do this:
private bool buttonClicked = false;
private void button1_Click(object sender, EventArgs e)
{
if(!buttonClicked)
{
buttonClicked = true;
fileNumber = 1;
ImgSave();
}
else
{
ImgSave.exit();
}
}
This assumes you never going to click it a third time. If you are, you would need to handle that in some way.
I'd have either a class level variable track the number of times a button is clicked:
private bool _unclicked = false;
private void button1_Click(object sender, EventArgs e)
{
if(!_unclicked)
{
_unclicked = true; //toggle so next time the ELSE will be performed
fileNumber = 1;
ImgSave();
}
else
{
_unclicked = false; //toggle it off again
ImgSave.exit();
}
}
, or I'd store it in the .Tag of the button:
private void button1_Click(object sender, EventArgs e)
{
if(!button1.Tag.ToString() == "unclicked")
{
button1.Tag = "clicked"; //toggle so next time the ELSE will be performed
fileNumber = 1;
ImgSave();
}
else
{
button1.Tag = "unclicked"; //toggle it off again
ImgSave.exit();
}
}
You could also remove one event handler and add another:
private void button1_FirstClick(object sender, EventArgs e)
{
button1.Clicked -= button1_FirstClick;
button1.Clicked += button1_SecondClick;
fileNumber = 1;
ImgSave();
}
private void button1_SecondClick(object sender, EventArgs e)
{
button1.Clicked -= button1_SecondClick;
button1.Clicked += button1_FirstClick;
ImgSave.exit();
}
I've always been less of a fan of adding and removing event handlers to achieve things like this but it's quite a clean solution
You should save your state in a variable. Your state will change after first click and you can change the state of Clicking button with calling ConditionChanger() method anytime.
For example you may need change the state of variable when you clicked a second button.
private void ConditionChanger(){
myState = !myState;
}
Your variable :
private bool myState = false;
And your click event :
private void button1_Click(object sender, EventArgs e)
{
if(!myState)
{
myState = true;
fileNumber = 1;
ImgSave();
}
else
{
ImgSave.exit();
}
}
When I hold a key in my game to move my player:
public void MainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Up)
{
Player.MoveUp();
}
}
The player instantly moves one step as soon as I press the down arrow, and then pauses for a short duration before starting to smoothly move again. Why's this? How can I prevent it?
The answer in the proposed duplicate is incorrect, unfortunately. It doesn't ignore repeated KeyDown events, and so will gradually increase the "delta" value in the direction being handled by each key case. It also doesn't respond to the keypress immediately (i.e. no action happens until the first timer tick).
This answer to Holding Arrow Keys Down For Character Movement C# .Net ISSUES explains how to ignore the subsequent KeyDown events, but doesn't explain how then your character would move.
In other words, I couldn't find a duplicate question that actually correctly answers your question. So…
The basic technique you want to do is:
Don't move on the actual key input. Instead, generate your own timing logic that will move the object.
Instead of using the KeyDown event to actually move the object, use it to set a movement direction, which is then processed by your timing logic.
There are a variety of ways to accomplish this. One version would look like this:
private bool _moveUp;
private bool _moveDown;
private bool _moveLeft;
private bool _moveRight;
// You can add the Timer in the Winforms Designer instead if you like;
// The Interval property can be configured there at the same time, along
// with the Tick event handler, simplifying the non-Designer code here.
private System.Windows.Forms.Timer _movementTimer = new Timer { Interval = 100 };
public MainForm()
{
InitializeComponent();
_movementTimer.Tick += movementTimer_Tick;
}
private void movementTimer_Tick(object sender, EventArgs e)
{
_DoMovement();
}
private void _DoMovement()
{
if (_moveLeft) Player.MoveLeft();
if (_moveRight) Player.MoveRight();
if (_moveUp) Player.MoveUp();
if (_moveDown) Player.MoveDown();
}
// You could of course override the OnKeyDown() method instead,
// assuming the handler is in the Form subclass generating the
// the event.
public void MainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat)
{
// Ignore key repeats...let the timer handle that
return;
}
switch (e.KeyCode)
{
case Keys.Up:
_moveUp = true;
break;
case Keys.Down:
_moveDown = true;
break;
case Keys.Left:
_moveLeft = true;
break;
case Keys.Right:
_moveRight = true;
break;
}
_DoMovement();
_movementTimer.Start();
}
public void MainForm_KeyUp(object sender, KeyEventArgs e)
{
switch (e.KeyCode)
{
case Keys.Up:
_moveUp = false;
break;
case Keys.Down:
_moveDown = false;
break;
case Keys.Left:
_moveLeft = false;
break;
case Keys.Right:
_moveRight = false;
break;
}
if (!(_moveUp || _moveDown || _moveLeft || _moveRight))
{
_movementTimer.Stop();
}
}
Do note that the timer objects in .NET have limited resolution. I show an interval of 100 ms (10 times per second) above (same as in the other question's answer), and this is about as frequent an update as you're going to reliably get. Even then, the timer's Tick event may not (and probably won't) be raised on exactly 100 ms intervals. There will be some variation back and forth. But it will be close enough for a basic game.
If you need more precision than that, you will have to implement your own state-polling-and-animation loop somewhere. That's a whole other ball o' wax. :)
A subjectivly elegent approach:
public partial class Form1 : Form
{
private static Timer timer;
private static bool[] keys_down;
private static Keys[] key_props;
private void Form1_Load(object sender, EventArgs e)
{
keys_down = new bool[4];
key_props = new []{Keys.A, Keys.D, Keys.W, Keys.S};
timer = new Timer();
timer.Interval = 15; // Roughly 67 FPS
timer.Tick += tick;
timer.Start();
KeyDown += key_down_event;
KeyUp += key_up_event;
... // More things to do when the form loads.
}
private void tick(Object source, EventArgs e)
{
... // Do this every timing interval.
byte n = 0;
foreach (var v in keys_down)
{
if (n == 3 && v)
... // If the "s" key is being held down, no key delay issues. :)
n++;
}
...
}
private void key_down_event(object sender, KeyEventArgs e)
{
byte n = 0;
foreach (var v in keys_down)
{
if (e.KeyCode == key_props[n])
keys_down[n] = true;
n++;
}
}
private void key_up_event(object sender, KeyEventArgs e)
{
byte n = 0;
foreach (var v in keys_down)
{
if (e.KeyCode == key_props[n])
keys_down[n] = false;
n++;
}
}
public Form1()
{
InitializeComponent();
}
}
I was looking for solutions to create a small copy of Flappy Bird. Perhaps my decision will help someone.
I used the addition of a player position with a variable in timer to simulate gravity. When I press W, I turned off the further reception of the command using bool and simply inverted gravity
private void time_Tick(object sender, EventArgs e)
{
if (bird.Location.Y >= 540)
{
bird.Location = new Point(bird.Location.X, 540);
}
else
{
bird.Location = new Point(bird.Location.X, bird.Location.Y+grav);
}
}
private void Form1_KeyPress(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.W && press == false)
{
press = true;
grav = -10;
}
return;
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyData == Keys.W && press == true)
{
press = false;
grav = 5;
}
return;
}
here is my code:
MediaPlayer player = new System.Windows.Media.MediaPlayer();
bool playing = false;
bool _bKeyIsDown = false;
protected override void OnKeyDown(KeyEventArgs e)
{
if (_bKeyIsDown) return;
_bKeyIsDown = true;
// play sound;
base.OnKeyDown(e);
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
_bKeyIsDown = false;
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D1)
{
if (label5.Text == "Waiting 01.wav")
{
MessageBox.Show("No beat loaded");
return;
}
pictureBox6.Image = Form1.Properties.Resources.white_square_button;
try
{
playing = true;
player.Open(new Uri(label37.Text));
player.Volume = (double)trackBar4.Value / 100;
player.Play();
}
catch (FileNotFoundException)
{
MessageBox.Show("File has been moved." + "\n" + "Please relocate it now!");
}
}
}
private void Window_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D1)
{
pictureBox6.Image = Form1.Properties.Resources.black_square_button;
player1.Stop();
player1.Close();
playing = false;
}
This what makes is to play a sound while key is down, but the problem is that when you release that key and press another one the sound delays and if you press 2 keys at the same time it only play the first one you pressed.
If you remove if (_bKeyIsDown) return; it does the trick but the sound won't play at its full length.
Is there a way to fix this problem? Thanks!
If its just play and stop 1 sound just do KeyDown event and use bool to toggle:
bool playing = false;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.D1)
{
if (!playing)
{
player.Open(new Uri(yourURI));
player.Play();
playing = true;
}
else
{
player.Stop();
playing = false;
}
}
}
EDIT:
then may i suggest you create a dictionary with all the sounds you need like this:
Dictionary<Keys, Uri> sounds = new Dictionary<Keys, Uri>()
{
{Keys.A,new Uri(#"C:\..\..\youraudiofile.mp3")},
{Keys.B,new Uri(#"C:\..\yourotheraudiofile.wma")}
};
and create a list to keep references to the mediaplayers:
List<MediaPlayer> myplayers = new List<MediaPlayer>();
then only in KeyDown event(remove the onKeyDown,and keyup also):
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
foreach (MediaPlayer m in myplayers)
{
m.Stop();
}
return;
}
if (sounds.ContainsKey(e.KeyCode))
{
MediaPlayer mp = new MediaPlayer();
mp.Open(sounds[e.KeyCode]);
mp.Play();
}
}
I'm making a snake game in C# and I have a pause and play button. Problem is: these buttons are in the exact same position, so I can't click start after I have clicked pause (because it's still active)
private void picBreak_Click(object sender, EventArgs e)
{
timer1.Stop();
picBreak.Visible = false;
picStart.Visible = true;
}
private void picStart_Click(object sender, EventArgs e)
{
timer1.Start();
picBreak.Visible = true;
picStart.Visible = false;
picStart.Focus = true;
}
The .Focus does not work and gives an error :/
ERROR = Error 1 Cannot assign to 'Focus' because it is a 'method group' C:\Users\Mave\Desktop\SnakeGame\Form1.cs 271 7 SnakeGame
Control.Focus is a method, not a property. This should be:
private void picStart_Click(object sender, EventArgs e)
{
timer1.Start();
picBreak.Visible = true;
picStart.Visible = false;
picBreak.Focus(); // Focus picBreak here?
}
In your code, you are trying to give focus to a control that you made invisible in the previous line... also, the compiler is telling you that Focus is a method, and you are trying to use it as a property.
I'd do this in a different way:
Just one button called btnStartPauseResume... and in the click event:
private void btnStartPauseResume_Click(object sender, EventArgs e)
{
if (btnStartPause.Text == "start")
{
btnStartPause.Text == "pause";
// code to start the game
}
else if (btnStartPause.Text == "pause")
{
btnStartPause.Text == "resume";
// code to pause the game
}
else if (btnStartPause.Text == "resume")
{
btnStartPause.Text == "pause";
// code to resume the game
}
}
ok i have question, i made this code to play axmediaplayer base on item listed on listbox.
first i make this code to make a list using opendialog :
private string[] files, path;
private void button1_Click(object sender, EventArgs e)
{
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
files = openFileDialog1.SafeFileNames;
path = openFileDialog1.FileNames;
for (int i = 0; i < files.Length; i++) {
listBox1.Items.Add(files[i]);
}
}
}
and then it play the music when the listbox index changed (when the item on the list box cliked) using this code :
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
axWindowsMediaPlayer1.URL = path[listBox1.SelectedIndex];
}
it works fine, and then i want player to automove to the next song base on item on my listbox. with using events PlayStateChange, so i make this code
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (axWindowsMediaPlayer1.playState == WMPLib.WMPPlayState.wmppsMediaEnded)
{
if(listBox1.SelectedIndex < files.Length - 1)
{
listBox1.SelectedIndex = listBox1.SelectedIndex + 1;
}
}
}
the selected index change, but the player doesn't auto play the next song. i must click the play button manually in order to play the list. can anyone help me up?
ok i found it, the solution is to add timer before playing the next song.
first im adding timer, that shoud be timer1. and then i change playstate event to something like this :
private void axWindowsMediaPlayer1_PlayStateChange(object sender, axWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (axWindowsMediaPlayer1.playState == WMPLib.WMPPlayState.wmppsMediaEnded)
{
timer1.Interval = 100;
timer1.Enabled = true;
}
}
then on the timer i adding tick event, the tick event is something like this :
private void timer1_Tick(object sender, EventArgs e)
{
if (listBox1.SelectedIndex < files.Length - 1)
{
listBox1.SelectedIndex++;
timer1.Enabled = false;
}
else
{
listBox1.SelectedIndex = 0;
timer1.Enabled = false;
}
}
now its work fine ^^
Below functionality worked for me:
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if ((WMPLib.WMPPlayState)e.newState == WMPLib.WMPPlayState.wmppsMediaEnded)
{
timer1.Interval = 100;
timer1.Start();
timer1.Enabled = true;
timer1.Tick += timer1_Tick;
}
}
private void timer1_Tick(object sender, EventArgs e)
{
/// method to play video list items
myFuntiontoPlayVideo();
timer1.Enabled = false;
}