Introduction
First I want to say: "Sorry about my spelling - but I'll try to become better!"
When you create moving objects/graphics using GDI+, you have to refresh the screen every time the timer ticks :-) But then the graphics begin to flicker - to avoid this you can use Double-Buffering. In this sample, I'll show what you need for flicker-free-graphics and also how to use KeyEvent
s.
Using the code
I've used a timer with an interval of 40 milliseconds because we need about 25 frames per second (1000 milliseconds / 25 frames = 40). To demonstrate how to move the graphics-object I have also built in KeyEvent
s.
At first you have to set Double-Buffering in the constructor of your class:
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
Then we use a timer to refresh the form every 40 milliseconds:
private System.Windows.Forms.Timer t;
t = new Timer();
t.Interval = 40;
t.Tick += new System.EventHandler(TimerOnTick);
t.Enabled = true;
private void TimerOnTick(object sender, System.EventArgs e)
{
this.Refresh();
this.Text = DateTime.Now.ToString();
this.Text += " " + this.PlayerPosition.ToString();
}
Next we "listen" to our keyboard:
this.KeyDown += new System.Windows.Forms.KeyEventHandler(OnKeyPress);
private void OnKeyPress(object sender, System.Windows.Forms.KeyEventArgs e)
{
if(e.KeyValue == 37)
{
this.PlayerPosition = new Point(this.PlayerPosition.X
- this.playerSize.Width,
this.PlayerPosition.Y);
}
if(e.KeyValue == 38)
{
this.PlayerPosition = new Point(this.PlayerPosition.X,
this.PlayerPosition.Y
- this.playerSize.Width);
}
if(e.KeyValue == 39)
{
this.PlayerPosition = new Point(this.PlayerPosition.X
+ this.playerSize.Height,
this.PlayerPosition.Y);
}
if(e.KeyValue == 40)
{
this.PlayerPosition = new Point(this.PlayerPosition.X,
this.PlayerPosition.Y
+ this.playerSize.Height);
}
}
And we have to overwrite the OnPaint
event to draw our object:
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(Color.Red),
this.PlayerPosition.X,
this.PlayerPosition.Y,
this.playerSize.Width,
this.playerSize.Height);
}
To calculate if the new position of our graphics-object is in the client area and what to do if not, I've used a property:
private Point PlayerPosition
{
get
{
return this.playerPosition;
}
set
{
if(value.X < 0)
{
this.playerPosition.X = this.ClientSize.Width - this.playerSize.Width;
}
else if(value.X + this.playerSize.Width > this.ClientSize.Width)
{
this.playerPosition.X = 0;
}
else
{
this.playerPosition.X = value.X;
}
if(value.Y < 0)
{
this.playerPosition.Y = this.ClientSize.Height -
this.playerSize.Height;
}
else if(value.Y + this.playerSize.Height > this.ClientSize.Height)
{
this.playerPosition.Y = 0;
}
else
{
this.playerPosition.Y = value.Y;
}
}
}
Now we have a flicker-free animation ;-)
Points of interest
In the first version of my sample I used if()
- else if()
for the KeyEvent
. But then one key worked at a time. Using if()
for every key makes it possible to combine the keys for a diagonal movement. It's also important to use this.Client.Width
and this.Client.Height
instead of this.Width
and this.Height
- because the graphics-object can only be moved in the client-area and so you can calculate areas for the movement.