RunUO Community

This is a sample guest message. Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Reducing Flicker

Cmonkey123

Wanderer
Reducing Flicker

Now that I've successfully learned how to draw stuff in C#, I've run into yet another problem: the flickering caused by drawing without buffering.

I've gone through many buffering and double buffering tutorials, but they're all confusing and very specific to certain tasks.

Does anyone know of simple code or a set of methods I can use to make a general graphics buffering method? Perhaps if someone could recommend easy, understandable on this topic reading? Anything so I can learn this buffering thing fast. Help is greatly appreciated.
 

Serp

Sorceror
What you want is double buffering.
What this means is that you draw on a plane that isn't visible, then when you're done drawing it you swap it with the visible plane. This eliminates flickering.
 
You also need to set AllPaintingInWmPaint, and UserPaint control styles.

SetStyle( ControlStyles.UserPaint, true );
SetStyle( ControlStyles.AllPaintingInWmPaint, true );
 

Cmonkey123

Wanderer
Alright, well I looked at some websites and tried what you guys suggested. It reduced flickering just a tad bit, but my script still very obviously flickers.

Here's my entire script:
Code:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace rotation_test
{
	public class rotationtest : System.Windows.Forms.Form
	{
		Timer rotationtimer = new Timer();

		Image sphere;
		Image sun;
		Bitmap offScreenBuffer;

		float sphereX, sphereY;
		
		double rotationfactor;

		const string sphere_file_name = "..\\..\\sphere.ico";
		const string sun_file_name = "..\\..\\sun.ico";

		private System.ComponentModel.Container components = null;

		public rotationtest()
		{
			sphere = Image.FromFile( sphere_file_name );
			sun = Image.FromFile( sun_file_name );

			InitializeComponent();
		}

		public void RotationTimerTick( object sender, System.EventArgs e )
		{
			rotationfactor += 0.025;

			sphereX = 100 * (float)Math.Cos( rotationfactor ) + ( ( this.ClientSize.Width / 2 ) - 16 );
			sphereY = 100 * (float)Math.Sin( rotationfactor ) + ( ( this.ClientSize.Height / 2 ) - 16 );

			Invalidate();
		}

		public void DoPaint( Graphics g, PaintEventArgs e )
		{
			System.Drawing.Pen ellipsepen = new Pen( Color.Red, 1 );

			g = e.Graphics;

			g.DrawEllipse( ellipsepen, ( this.ClientSize.Width / 2 ) - 100, ( this.ClientSize.Height / 2 ) - 100, 
				200, 200 ); 
			g.DrawImage( sphere, sphereX, sphereY );
			g.DrawImage( sun, ( this.ClientSize.Width / 2 ) - 16, ( this.ClientSize.Height / 2 ) - 16 );

			base.OnPaint( e );
		}

		private void InitializeComponent()
		{
			// 
			// rotationtest
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.BackColor = System.Drawing.Color.Black;
			this.ClientSize = new System.Drawing.Size(792, 466);
			this.ForeColor = System.Drawing.Color.Black;
			this.MaximumSize = new System.Drawing.Size(800, 500);
			this.MinimumSize = new System.Drawing.Size(800, 500);
			this.Name = "rotationtest";
			this.Text = "rotation test";

			SetStyle( ControlStyles.UserPaint, true );
			SetStyle( ControlStyles.AllPaintingInWmPaint, true );

			rotationtimer.Enabled = false;
			rotationtimer.Interval = 30;
			rotationtimer.Tick += new System.EventHandler( RotationTimerTick );
		}

		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		protected override void OnKeyDown( KeyEventArgs e )
		{
			string input = e.KeyData.ToString();

			switch( input )
			{
				case "Enter":
					rotationtimer.Enabled = true;
					break;
			}

			Invalidate();
		}

		protected override void OnPaint( PaintEventArgs e )
		{
			Graphics gOffScreen;
			Graphics g = e.Graphics;

			if( offScreenBuffer == null || offScreenBuffer.Width != this.ClientSize.Width || offScreenBuffer.Height != this.ClientSize.Height )
			{
				offScreenBuffer = new Bitmap( this.ClientSize.Width, this.ClientSize.Height );
			}
			
			gOffScreen = Graphics.FromImage( offScreenBuffer );
			DoPaint( gOffScreen, e );
			gOffScreen.Dispose();

			g.DrawImage( offScreenBuffer, 0, 0 );
		}

		[STAThread]
		static void Main() 
		{
			Application.Run( new rotationtest() );
		}
	}
}

I used the OnPaint to draw the off screen buffer and then used the DoPaint to draw on the buffer, then I displayed it with DrawImage at the end of OnPaint. If I am doing the buffering properly, why is it still flickering? If not, what needs fixing?
 
You also need to make the application double buffered. In .Net 2.0 i think you just do "this.DoubleBuffered = true" but for .net 1.1 you do SetStyle( ControlStyles.DoubleBuffered, true );
 

David

Moderate
This has been an interesting project. I would like to see your final code if you have it working--if you don't mind.
 

Cmonkey123

Wanderer
Once I'm finished I'll post the code on the forum if you'd like. It won't be too interesting, just a compilation of mostly graphics related stuff I'm trying to learn bundled into one program.

Ultimately though, I'm going to develop my own game. I've had a sweet idea for a game for a long time and I really want to put my ideas into action before I lose interest. It's gonna take me a long time, but I don't have much else educational, interesting, or fun to do with my free time.
 
Top