I\'m working on programming a Tetris game in Visual C# 2005. This is the most extensive program I have designed yet.
I create a shape class and a block class to cont
If you're relying on key repeat to repeatedly send key down events to make the block move, I don't think this is the way you want to do it. The block should move consistently independent of key repeat. Therefore you should not be moving the block during the key events. You should only be tracking the state of the keys during the keydown and keyup events, and handle movement elsewhere. The actual movement should take place either in some sort of timer event (a timer control fires events at regular intervals even if nothing is going on) or you should have a main loop constantly checking the state of everything and moving objects when appropriate. If you use the second option, you will need to look into "DoEvents" because if you have code that's constantly running without ever finishing the function, the program will not process any other events such as keyup and keydown events. So you would want to call DoEvents within each loop to process the key events (among other things like moving the window). You might also want to call System.Threading.Thread.Sleep if you don't need to be processing things quite so constantly. If you use a timer control, you shouldn't have to worry about any of that.
Sorry, no specific help... it's saturday night after all... however:
Each key needs a state. When you get a keydown event, you can tell which key went down, and modifiy the keystate you are maintaining. When the key comes back up, once again, from looking at the event, you can tell which it was. Only modify the state of the key that the event was fired against: i.e. don't reset all states with the keyup event, otherwise the state of keys you are holding in memory will be corrupted, as you are seeing.
Most games don't wait for events. They poll the input device when neccessary and act accodringly. In fact, if you ever take a look at XNA, you'll see that there's a Keyboard.GetState() method (or Gamepad.GetState()) that you'll call in your update routine, and update your game logic based on the results. When working with Windows.Forms, there's nothing out of the box to do this, however you can P/Invoke the GetKeyBoardState() function to take advantage of this. The good thing about this is, that you can poll multiple keys at once, and you can therefore react to more than one key press at a time. Here's a simple class I found online that helps with this:
http://sanity-free.org/17/obtaining_key_state_info_in_dotnet_csharp_getkeystate_implementation.html
To demonstrate, I wrote a simple windows app that basically moves a ball around based on keyboard input. It uses the class I linked you to, to poll the keyboard's state. You'll notice that if you hold down two keys at a time, it'll move diagonally.
First, Ball.cs:
public class Ball
{
private Brush brush;
public float X { get; set; }
public float Y { get; set; }
public float DX { get; set; }
public float DY { get; set; }
public Color Color { get; set; }
public float Size { get; set; }
public void Draw(Graphics g)
{
if (this.brush == null)
{
this.brush = new SolidBrush(this.Color);
}
g.FillEllipse(this.brush, X, Y, Size, Size);
}
public void MoveRight()
{
this.X += DX;
}
public void MoveLeft()
{
this.X -= this.DX;
}
public void MoveUp()
{
this.Y -= this.DY;
}
public void MoveDown()
{
this.Y += this.DY;
}
}
Really nothing fancy at all....
Then here's the Form1 code:
public partial class Form1 : Form
{
private Ball ball;
private Timer timer;
public Form1()
{
InitializeComponent();
this.ball = new Ball
{
X = 10f,
Y = 10f,
DX = 2f,
DY = 2f,
Color = Color.Red,
Size = 10f
};
this.timer = new Timer();
timer.Interval = 20;
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
var left = KeyboardInfo.GetKeyState(Keys.Left);
var right = KeyboardInfo.GetKeyState(Keys.Right);
var up = KeyboardInfo.GetKeyState(Keys.Up);
var down = KeyboardInfo.GetKeyState(Keys.Down);
if (left.IsPressed)
{
ball.MoveLeft();
this.Invalidate();
}
if (right.IsPressed)
{
ball.MoveRight();
this.Invalidate();
}
if (up.IsPressed)
{
ball.MoveUp();
this.Invalidate();
}
if (down.IsPressed)
{
ball.MoveDown();
this.Invalidate();
}
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
if (this.ball != null)
{
this.ball.Draw(e.Graphics);
}
}
}
Simple little app. Just creates a ball and a timer. Every 20 milliseconds, it checks the keyboard state, and if a key is pressed it moves it and invalidates so that it can repaint.