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:
someone that knows what is happening can explain why this happen or how to fix this?
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.
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);
}
}
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.