Screen is blinking when overriding BeginDraw and calling GraphicsDevice.Clear at initialization

Context: I am trying to reproduce a Random Walk, I want to draw a moving object on screen and keep it’s previous draws.

You can see a example of this here: p5.js Web Editor | CC 52: Random Walk (p5js.org)

The implementation uses a Walker object, a object with a Position, Texture, and a Walk method.

public class Walker {
        Random rnd = new();
        public Vector2 Position;
        public Texture2D Texture;        
        public Walker(Vector2 position,Texture2D texture)
        {
            Position = position;
            Texture = texture;
        }        
        private void Walk(Vector2 position)
        {
            Position = Vector2.Add(Position,position);
        }
        public void Walk(){
            Walk(GeneratePositionChange());
        }
        protected Vector2 GeneratePositionChange(){
            var x = rnd.Next(-256,256) * 0.01f;
            var y = rnd.Next(-256,256) * 0.01f;
            var position = new Vector2();
            position.X = x;
            position.Y = y;
            return position;
        }
}

and this is the game class

public class Walk : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;         
        Walker walker;        
        Vector2 ScreenSize;
        public Walk()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            IsMouseVisible = true;
        }
        
        protected override void Initialize()
        {
            base.Initialize();
            GraphicsDevice.Clear(Color.White);            
            var texture = new Texture2D(GraphicsDevice,16,16);
            var textureData = Enumerable.Repeat(Color.Black,16 * 16).ToArray();
            texture.SetData(textureData);
            ScreenSize = new Vector2(_graphics.PreferredBackBufferWidth,_graphics.PreferredBackBufferHeight);
            walker = new Walker(new Vector2(ScreenSize.X / 2,ScreenSize.Y / 2),texture);

        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            
            walker.Walk();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            _spriteBatch.Begin();
            _spriteBatch.Draw(walker.Texture,walker.Position,Color.Black);
            _spriteBatch.End();
            base.Draw(gameTime);
        }
        protected override bool BeginDraw()
        {            
            return base.BeginDraw();
        }
    }

this is the result:

Blinking error

someone that knows what is happening can explain why this happen or how to fix this?

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        base.Initialize();
    }

EDIT

Also:

Hi @adnanioricce, Welcome to the Community!

Happy Coding!

Sorry, I don’t get it
The initialization logic should be called before base.Initialize()? Or not called at all?
The GraphicsDevice.Clear() should be called at Initialize()?
I also tried all, but the screen continues to blink.
I Also find that BeginDraw() don’t need to actually be overrided, I want to keep the previous draw of the walks so don’t call GraphicsDevice.Clear() does it, but still blinks.
and thanks for the welcome.

1 Like

This is called once, so it goes where it is.

so it should be this way?

protected override void Initialize()
        {                              
            var texture = new Texture2D(GraphicsDevice,16,16);
            var textureData = Enumerable.Repeat(Color.White,16 * 16).ToArray();
            texture.SetData(textureData);
            ScreenSize = new Vector2(_graphics.PreferredBackBufferWidth,_graphics.PreferredBackBufferHeight);
            walker = new Walker(new Vector2(ScreenSize.X / 2,ScreenSize.Y / 2),texture);
            base.Initialize();                        
        }

about the image blink? There is some way to draw the walker retaining it’s contents?

Well, it seems that I was trying to go againts the API.
To keep the previous draws, I have to use a render target, drawing to it first before drawing to the screen(I suppose that I was drawing to the backbuffer?)
so I created a render target, drawed the walker on it, and after that drawed the render target.
The code:

public class Walk : Game
    {
        private GraphicsDeviceManager _graphics;
        private SpriteBatch _spriteBatch;         
        Walker walker;        
        Vector2 ScreenSize;                                
        RenderTarget2D renderTarget;        
        public Walk()
        {
            _graphics = new GraphicsDeviceManager(this);                     
            Content.RootDirectory = "Content";
            IsMouseVisible = true;            
            
        }
        
        protected override void Initialize()
        {   
            _spriteBatch = new SpriteBatch(GraphicsDevice);                                      
            var texture = new Texture2D(GraphicsDevice,16,16);
            var textureData = Enumerable.Repeat(Color.White,16 * 16).ToArray();
            texture.SetData(textureData);
            ScreenSize = new Vector2(_graphics.PreferredBackBufferWidth,_graphics.PreferredBackBufferHeight);
            walker = new Walker(new Vector2(ScreenSize.X / 2,ScreenSize.Y / 2),texture);
            renderTarget = new RenderTarget2D(GraphicsDevice,(int)ScreenSize.X,(int)ScreenSize.Y ,false,SurfaceFormat.Color,DepthFormat.Depth24,0,RenderTargetUsage.PreserveContents);//Remember to set to PreserveContents
            base.Initialize();                        
        }

        protected override void LoadContent()
        {   
            base.LoadContent();
        }

        protected override void Update(GameTime gameTime)
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();
            walker.Walk();
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {            
            //draws the walker in the render target
            GraphicsDevice.SetRenderTarget(renderTarget);
            _spriteBatch.Begin();
            _spriteBatch.Draw(walker.Texture,walker.Position,Color.White);
            _spriteBatch.End();
            GraphicsDevice.SetRenderTarget(null);
            //now draws the renderTarget to the screen, keeping it's previous states
            GraphicsDevice.Clear(Color.Teal);
            _spriteBatch.Begin();
            _spriteBatch.Draw(renderTarget,Vector2.Zero,renderTarget.Bounds,Color.White);
            _spriteBatch.End();
            base.Draw(gameTime);
        }        
        
    }

well,I will at least give a print of the result.

1 Like

Did you solve your problem? if so, mark the post that solves the issue

Just thought about it and thought I could leave some untested ideas here.

You could probably just use a 1x1 sized rectangle for drawing and then use a method overload of the spritebatch draw which allows to define a size or scale.

You could try different “stamps” (source images) which you draw to the random positions. Hexagons / stars / hearts… Maybe use Alpha blending. Could produce some nice images I guess.

You could “buffer” some number of positions, just drawing all again each frame to a render target which is not using “preserve content”. Only now and then clear the buffer by using this render target by drawing it to the one which does preserve contents. Not sure I wrote this clear enough. In simple steps collect all random walk positions. Then draw all of them every frame to a render target. After some arbitrary number use the render target and draw it to another render target which preserves content. Only in those frames when you do this additional drawing to the preserve contents render target you clear the collected positions. To the screen you would always draw the combination of the preserve contents render target and the render target which gets drawn all currently collected random walk positions.

Hoping for new images if you work more on this project.