How do I keep animations from flickering in C# game programming? - c#

Everytime I try to add a new line or move the paddle in this game the screen flickers.
How do I keep the screen from flickering when I move the paddle or add a line?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class GameTest : Form
{
int dx=3, dy=3, i =500, o = 100;
int rex = 400, rey = 450 ;
double c =0;
public GameTest()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Invalidate();
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
Graphics g = this.CreateGraphics();
if (e.KeyCode == Keys.Left)
{
//Graphics g = this.CreateGraphics();
Invalidate();
Brush black = new SolidBrush(Color.White);
g.FillRectangle(black, rex, rey, 200, 20);
rex -= 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
if (e.KeyCode == Keys.Right)
{
//Graphics g = this.CreateGraphics();
Brush white = new SolidBrush(Color.White);
g.FillRectangle(white, rex, rey, 200, 20);
rex += 40;
Brush red = new SolidBrush(Color.Green);
g.FillRectangle(red, rex, rey, 200, 20);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
DoubleBuffered = false;
Graphics g = this.CreateGraphics();
// Bitmap bmp1 = new Bitmap("G:\c#\Bouncing ball\Pic.jpg");
//TextureBrush tb2 = new TextureBrush(bmp1);
Brush green = new SolidBrush(Color.Green);
g.FillRectangle(green, rex, rey, 200, 20);
Graphics b= this.CreateGraphics();
Brush red = new SolidBrush(Color.Red);
b.FillEllipse(red, i, o, 20, 20);
Pen p = new Pen(Color.Black, 10);
//
g.DrawLine(p, 1000, 480,0,480);
g.DrawLine(p, 1000, 485, 1000, 0);
g .DrawLine(p, 0,480, 0, 0);
}
private void timer1_Tick(object sender, EventArgs e)
{
DoubleBuffered = false;
// int dx=3, dy=3, i = 300, o = 50;
i += dx;
if (i < 0)
{
dx = -dx;
}
else if (i + 50 > 1000)
{
dx = -dx;
}
o += dy;
if ((o +20>= rey) &&(i+20<=rex+200)&&(i+20>=rex))
{
//int rex = 400, rey = 450; RECTANGLE
// int dx=3, dy=3, i(x) = 500, o(y) = 100;
dy =-dy;
//c++;
//label1.Text = c.ToString();
}
// Misgeret\\
if (o < 0)
{
dy = -dy;
}
// Misgeret\\
else if (o + 50 > 600)
{
dy = -dy;
}
this.Invalidate();
}
private void label1_Click(object sender, EventArgs e)
{
label1.Text = c.ToString();
}
}
}

I noticed that you are setting DoubleBuffered to false in multiple areas of your program. That is definitely not helping since the whole reason to use double buffering is to prevent flickering.
The other thing is you are creating Graphics contexts and drawing in multiple places in your application. Try to refactor your code to only draw in the OnPaint() event handler of the form, and do not create a new Graphics context. Use the one provided in the PaintEventArgs of the OnPaint() event.
private void Form1_Paint(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
using(Brush green = new SolidBrush(Color.Green))
{
g.FillRectangle(green, rex, rey, 200, 20);
}
// .. etc, etc..
}
Then, when you need to the form to be repainted you just need to invoke the Invalidate() method to tell the GDI that your form, or a portion of it, needs to be repainted. That will in turn cause the Paint event to be fired and the OnPaint() to be called.
As a side note, as #HighCore suggested in the comments, WinForms is definitely not the right framework to create a game in. For games try the XNA framework, or one of several open source ones available on the web such as Unity
UPDATE
To prevent flickering you can use automatic double buffering for your form. This can be enabled in the form constructor, after the call to InitializeComponent(), using a call to SetStyle:
SetStyle( ControlStyles.AllPaintingInWmPaint
| ControlStyles.UserPaint
| ControlStyles.DoubleBuffer , true);

Related

Show Scrollbars if the height of a shape is greater than the Form's height

I just need to show scrollbars on forms if my shape height is greater than the form height. That way, when the user scrolls down, it can show the end of the shape.
This is my code:
public partial class Form1: Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
}
private void Form1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawLine(new Pen(Color.Black, 2), 100, 50, 100, 1000);
//if line height > form height then show scroll bars
}
}
You need to enable the AutoScroll property of the form, use the AutoScrollPosition coordinates in drawings, and set the AutoScrollMinSize property to contain your shapes:
In the constructor add:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AutoScroll = true;
}
}
and the painting routine:
private void Form1_Paint(object sender, PaintEventArgs e)
{
using (Matrix m = new Matrix(1, 0, 0, 1, AutoScrollPosition.X, AutoScrollPosition.Y))
{
var sY = VerticalScroll.Value;
var sH = ClientRectangle.Y;
var w = ClientRectangle.Width - 2 - (VerticalScroll.Visible ? SystemInformation.VerticalScrollBarWidth : 0);
var h = ClientRectangle.Height;
var paintRect = new Rectangle(0, sY, w, h); //This will be your painting rectangle.
var g = e.Graphics;
g.SmoothingMode = SmoothingMode.AntiAlias;
g.Transform = m;
g.Clear(BackColor);
using (Pen pn = new Pen(Color.Black, 2))
e.Graphics.DrawLine(pn, 100, 50, 100, 1000);
sH += 1050; //Your line.y + line.height
//Likewise, you can increase the w to show the HorizontalScroll if you need that.
AutoScrollMinSize = new Size(w, sH);
}
}
Good Luck.

How to operate on drawn graphics

I created two Rectangles. I want to add events on them. For example when mouse hover on one, the hovered one will change color, can do resize or drag them(rectangles) to other place...
I was just wondering if I could control the drawn graphic, or it will like Microsoft Paint that after you painted, the object can not be operate unless you clear canvas and do redraw.
Is it possible to control a drawn graphic, thanks for any suggestion.
Simple code of my drawn graphics
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create rectangle.
Rectangle rect1 = new Rectangle(20, 20, 250, 250);
Rectangle rect2 = new Rectangle(70, 70, 150, 150);
// Draw rectangle to screen.
e.Graphics.FillRectangle(Brushes.DeepSkyBlue, rect1);
e.Graphics.FillRectangle(Brushes.LightBlue, rect2);
}
Also, you can create your own control like:
class RectangleControl : Control
{
public void FillRectangle(Color color)
{
this.BackColor = color;
}
}
Then :
private void Form1_Paint(object sender, PaintEventArgs e)
{
RectangleControl rect1 = new RectangleControl() { Parent = this, Left = 20, Top = 20, Width = 250, Height = 250 };
rect1.FillRectangle(Color.DeepSkyBlue);
RectangleControl rect2 = new RectangleControl() { Parent = rect1, Left = 50, Top = 50, Width = 150, Height = 150 };
rect2.FillRectangle(Color.LightBlue);
rect1.MouseHover += Rect1_MouseHover;
rect2.MouseLeave += Rect2_MouseLeave;
}
private void Rect2_MouseLeave(object sender, EventArgs e)
{
(sender as RectangleControl).BackColor = Color.Yellow;
}
private void Rect1_MouseHover(object sender, EventArgs e)
{
(sender as RectangleControl).BackColor = Color.LightBlue;
}
You can use Panel control instead.
Just add 2 panel controls as you would like them to be arranged and add 2 event handlers:
private void panel1_MouseHover(object sender, EventArgs e)
{
panel1.BackColor = Color.Yellow;
}
private void panel1_MouseLeave(object sender, EventArgs e)
{
panel1.BackColor = Color.LightBlue;
}
You can monitor the MouseMove.
Here's code using MouseMove and some brush values used by the rectangles.
using System.Drawing;
using System.Windows.Forms;
namespace Question_Answer_WinForms_App
{
public partial class Form1 : Form
{
public Brush outerRectangleBrush = Brushes.DeepSkyBlue;
public Brush innerRectangleBrush = Brushes.LightBlue;
public Form1()
{
InitializeComponent();
Paint += Form1_Paint;
MouseMove += Form1_MouseMove;
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
var isWithinOuterRectangle = e.Location.X >= 20
&& e.Location.X <= 250 + 20
&& e.Location.Y >= 20
&& e.Location.Y <= 250 + 20;
var isWithinInnerRectangle = e.Location.X >= 70
&& e.Location.X <= 150 + 70
&& e.Location.Y >= 70
&& e.Location.Y <= 150 + 70;
if (isWithinOuterRectangle)
{
if (isWithinInnerRectangle)
{
outerRectangleBrush = Brushes.DeepSkyBlue;
innerRectangleBrush = Brushes.Red;
Refresh();
}
else
{
outerRectangleBrush = Brushes.Red;
innerRectangleBrush = Brushes.LightBlue;
Refresh();
}
}
else
{
outerRectangleBrush = Brushes.DeepSkyBlue;
innerRectangleBrush = Brushes.LightBlue;
Refresh();
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
// Create pen.
Pen blackPen = new Pen(Color.Black, 3);
// Create rectangle.
Rectangle rect1 = new Rectangle(20, 20, 250, 250);
Rectangle rect2 = new Rectangle(70, 70, 150, 150);
// Draw rectangle to screen.
e.Graphics.FillRectangle(outerRectangleBrush, rect1);
e.Graphics.FillRectangle(innerRectangleBrush, rect2);
}
}
}
#FJF, writing a ms-paint like application is not a complicated task. Windows Forms applications are using GDI+ to render graphics. so you can write a simple paint application using WindowsForms.
#nexolini uses a panel to do some draws. actually Ms-Paint does the same somehow. Ms-Paint is a Single-Layer Editor. So you can't resize all objects anytime you wanted (but as I said before you can assume that you have a panel for each newly drawn Shapes; Something like what Ms-Paint does).
So what is the problem?
Ms-Paint doesn't tracks your mouse movements and it doesn't needed (as it's a single layer). You can do all of it's tasks using these Answers.
e.g: for adding a Fill Color tool you can use a getpixel and putpixel to do a recursive algorithm on you image. and you are not needed to know which shape you are working on.
all the other tasks could be implemented easy.
for multi-layer Editors I will prefer to use a more powerful framework (but it's also could be implemented in Windows forms in a bad way), Like WPF. WPF uses DirectX to render your graphics and you are able to write an smooth Editor. WPF is designed to handle your graphical request so it does better on graphics.
#Reza_Aghaei 's comments are useful for Windows Forms.

C# paint program won't create any lines on the screen since I tried to draw using a bitmap

Here is my source code. I can't seem to get the bitmap to show the lines drawn on the panel when I move the mouse with the button pressed. Frustrated and looking for someone to help me finish the code so I can complete the app for my 9-yo daughter. Thank you in advance...
namespace TV_PAINT
{
public partial class ALANA_PAINT : Form
{
Graphics g;
Pen p = new Pen(Color.Black, 7);
Point sp = new Point(0, 0);
Point ep = new Point(0, 0);
int m = 0;
Bitmap BP;
public ALANA_PAINT()
{
InitializeComponent();
tb1.Text = p.Width.ToString();
BP = new Bitmap(pnl1.ClientSize.Width, pnl1.ClientSize.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
}
private void closeButton_Click(object sender, EventArgs e)
{
pnl1.Dispose();
p.Dispose();
this.Close();
}
private void clearButton_Click(object sender, EventArgs e)
{
//pnl1.Invalidate();
p.Color = System.Drawing.Color.Black;
p.Width = 7;
tb1.Text = p.Width.ToString();
//pnl1.Invalidate();
}
private void pnl1_MouseDown(object sender, MouseEventArgs e)
{
sp = e.Location;
if (e.Button == MouseButtons.Left)
m = 1;
if (e.Button == MouseButtons.Right)
m = 1;
}
private void pnl1_MouseMove(object sender, MouseEventArgs e)
{
if (m == 1)
{
ep = e.Location;
//g = pnl1.CreateGraphics();
Graphics g = Graphics.FromImage(BP);
g.DrawLine(p, sp, ep);
}
sp = ep;
}
private void pnl1_MouseUp(object sender, MouseEventArgs e)
{
m = 0;
}
BP is just a variable in the form. As I can see, it is not displayed anywhere in your form. Why do you need a bitmap for it.
You can do something like this, just get the graphics of your form, and draw using that graphic. https://msdn.microsoft.com/en-us/library/ztxk24yx(v=vs.110).aspx
Noted: you need to do it on PaintEvent of the form, otherwise your drawing will be removed after the next repaint, so you need some variables to store all of your lines, then draw all of them in the paint event.
System.Drawing.SolidBrush myBrush = new System.Drawing.SolidBrush(System.Drawing.Color.Red);
System.Drawing.Graphics formGraphics;
formGraphics = this.CreateGraphics();
formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, 200, 300));
myBrush.Dispose();
formGraphics.Dispose();
Updated:
If you want to save your change to a bitmap. You can use Form.DrawToBitmap to save your drawing in the form to a bitmap, then call bitmap.Save() to a file in directory.

Partially fill a Rectangle object

I was wondering if it's possible to fill a certain percentage of a Rectangle object that's been draw on-screen so that it behaves like a Progress Bar, where you can watch its "level" go up and down. Specifically, I'd like to fill it from top to bottom rather than left to right.
You can try this.
private void button1_Click(object sender, EventArgs e)
{
panel1.Width = 400;
panel1.Height = 50;
using (Graphics g = this.panel1.CreateGraphics())
{
g.Clear(Color.Black);
Pen pen = new Pen(Color.Red, 2);
for (int i = 0; i <= 50;i++ )
{
g.DrawRectangle(pen, 0, 0, 400, i);
Thread.Sleep(100);
}
pen.Dispose();
}
}

C# Save modified image in panel

I am attempting to save an image as modified by graphics tools such as pens and shapes that can be drawn onto the image. I have done this using a panel with background image and trying to set up a bit map that will save changes within this panel:
private void saveToolStripButton_Click(object sender, EventArgs e)
{
//sets panel1 contents as bit map to be saved at set locations
int width = panel1.Size.Width;
int height = panel1.Size.Height;
using (Bitmap bmp = new Bitmap(width, height))
{
panel1.DrawToBitmap(bmp, new Rectangle(0, 0, width, height));
bmp.Save(#"C:\Users\Me\Pics\testBitmap.jpeg", ImageFormat.Jpeg);
}
MessageBox.Show("Your image has been saved");
}
Once the save button is clicked, the image saves ok but the changes made with the graphics tools do not show up. Can anyone suggest a solution?
Here is some code regarding the graphics tool i've set up for use within the panel:
{
InitializeComponent();
//Create graphics object in panel1
g = panel1.CreateGraphics();
}
private void btnExit2_Click(object sender, EventArgs e)
{
this.Close();
}
Graphics g;
//set a drawing boolean
bool draw = false;
private void panel1_MouseDown(object sender, MouseEventArgs e)
{
draw = true;
if (drawSq)
{
SolidBrush brush = new SolidBrush(Color.FromArgb(128, 255, 0, 0));
if (toolStripTextBox1.Text != "")
{
g.FillRectangle(brush, e.X, e.Y, Convert.ToInt32(toolStripTextBox1.Text), Convert.ToInt32(toolStripTextBox1.Text));
}
else if (toolStripTextBox1.Text == "")
{
MessageBox.Show("Please enter a shape size");
}
draw = false;
drawSq = false;
}
}
and more:
private void panel1_MouseUp(object sender, MouseEventArgs e)
{
draw = false;
mouseX = null;
mouseY = null;
}
//null values allow freehand style drawing
int? mouseX = null;
int? mouseY = null;
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
//creates a pen tool and sets properties by mouse location
if (draw)
{
Pen pen = new Pen(btnColor.ForeColor, float.Parse(txtBox1.Text));
g.DrawLine(pen, new Point(mouseX ?? e.X, mouseY ?? e.Y), new Point(e.X, e.Y));
mouseX = e.X;
mouseY = e.Y;
}
}
Let's try to fix this.
Start by creating your image first:
Bitmap bmp;
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Now when you want to draw on it:
void panel1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
using (Graphics g = Graphics.FromImage(bmp)) {
g.FillEllipse(Brushes.Red, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
And display the results:
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.DrawImage(bmp, Point.Empty);
}
To save, just use your bitmap:
bmp.Save(#"c:\filename.png", ImageFormat.Png);
Use Double buffering with Panel to avoid the flickering.
This will works fine. I tested it and worked well........
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace drawing
{
public partial class Form2 : Form
{
Graphics g;
bool startPaint = false;
int? initX = null;
int? initY = null;
bool drawSquare = false;
bool drawRectangle = false;
bool drawCircle = false;
public Form2()
{
InitializeComponent();
bmp = new Bitmap(panel1.ClientSize.Width, panel1.ClientSize.Height);
}
Bitmap bmp;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (startPaint)
{
using ( g = Graphics.FromImage(bmp))
{
// g.FillEllipse(Brushes.Black, new Rectangle(e.X, e.Y , 5, 5));
Pen p = new Pen(btn_PenColor.BackColor, float.Parse(cmb_PenSize.Text));
g.DrawLine(p, new Point(initX ?? e.X, initY ?? e.Y), new Point(e.X, e.Y));
initX = e.X;
initY = e.Y;
//g.DrawImage(bmp, new Rectangle(e.X - 4, e.Y - 4, 8, 8));
}
panel1.Invalidate();
}
}
private void pnl_Draw_MouseDown(object sender, MouseEventArgs e)
{
startPaint = true;
if (drawSquare)
{
//Use Solid Brush for filling the graphic shapes
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width and height same for creating square.
//Getting the width and Heigt value from Textbox(txt_ShapeSize)
g.FillRectangle(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
//setting startPaint and drawSquare value to false for creating one graphic on one click.
startPaint = false;
drawSquare = false;
}
if (drawRectangle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
//setting the width twice of the height
g.FillRectangle(sb, e.X, e.Y, 2 * int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawRectangle = false;
}
if (drawCircle)
{
SolidBrush sb = new SolidBrush(btn_PenColor.BackColor);
g.FillEllipse(sb, e.X, e.Y, int.Parse(txt_ShapeSize.Text), int.Parse(txt_ShapeSize.Text));
startPaint = false;
drawCircle = false;
}
}
private void pnl_Draw_MouseUp(object sender, MouseEventArgs e)
{
startPaint = false;
initX = null;
initY = null;
}
void panel1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawImage(bmp, Point.Empty);
}
private void button1_Click(object sender, EventArgs e)
{
bmp.Save("D://filename.jpg", ImageFormat.Png);
}
}
}

Categories

Resources