After viewing the source code, you have two flicker problems:
The first is that you order the picture box painted white:
ApiConexion._hub.On("ciclo", (p) =>
{
g.Clear(Color.White);
...
Even if you have used double buffer in the picturebox, if you order it to be painted white it will be painted white. That is the main flicker.
I have made two changes: The first is to create a custom control that is a double-buffer picturebox. Do not change the property by reflection, this is a bad practice. The correct solution is to use, instead of a picturebox, an instance of the following class:
using System.Windows.Forms;
namespace Snake.Juego.Controles
{
public class DoubleBufferedPictureBox : PictureBox
{
public DoubleBufferedPictureBox() {
this.DoubleBuffered = true;
this.SetStyle(ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint |
ControlStyles.ResizeRedraw |
ControlStyles.ContainerControl |
ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor, true);
}
}
}
I have added this class to a "Controls" folder.
Remember to compile the solution or the toolbox will not detect it.
Next, let's use the double buffer properly.
For this I have to give my picture box final images. If you create a Graphics of the image and order a Clear, the result of that operation is drawn.
So the next thing is to create a new bitmap, create graphics for that bitmap and paint in the bitmap. When we have finished, we replace the image of the picture box with the bitmap:
ApiConexion._hub.On("ciclo", (p) =>
{
Bitmap newImg = new Bitmap(_canvas.Width, _canvas.Height);
Graphics gNewImg = Graphics.FromImage(newImg);
gNewImg.Clear(Color.White);
gNewImg.SmoothingMode = SmoothingMode.AntiAlias;
gNewImg.InterpolationMode = InterpolationMode.HighQualityBicubic;
gNewImg.PixelOffsetMode = PixelOffsetMode.HighQuality;
if (disparos.Count()>0)
{
for (int a=0;a<disparos.Count();a++)
{
disparos[a].dibujar(gNewImg);
disparos[a].mover();
}
}
if (armasL.Count() > 0)
{
for (int d = 0; d < armasL.Count(); d++)
{
draw.getXY(armasL[d].x, armasL[d].y);
draw.FromImageArma(gNewImg,armasL[d].x, armasL[d].y); //Imprime el sprite
}
}
for (int it = 0; it < jugadores.Count(); it++)
{
///////////////////////////////////
if (armasL.Count() > 0)
{
for (int i = 0; i < armasL.Count(); i++)
{
if (jugadores[it].interseccion(armasL[i]))
{
armasL.Remove(armasL[i]);
jugadores[it].recogerMunicion();
if (jugadores[it].idCola == ApiConexion.connection.ConnectionId)
{
this.Invoke((MethodInvoker)delegate
{
refrescarMunicionTask(jugadores[it]);
});
return;
}
}
}
}
///////////////////////////////////////////
ParteCola temp = new ParteCola(jugadores[it].x, jugadores[it].y, jugadores[it].color, jugadores[it].idCola);
lock (jugadores[it])
{
jugadores[it].dibujar(gNewImg, jugadores[it].color);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
foreach (var act in jugadores)
{
if (act.partes.Find(x => x.PositionX == temp.PositionX) != null && act.partes.Find(x => x.PositionY == temp.PositionY) != null && act.idCola != jugadores[it].idCola /*&& filtrar que entre el jug que yo estoy manejando*/ )
{
ApiConexion._hub.Invoke("pararMov", jugadores[it]);
}
if (act.x == jugadores[it].x && act.y == jugadores[it].y && act.idCola != jugadores[it].idCola)
{
ApiConexion._hub.Invoke("pararMov", jugadores[it]);
ApiConexion._hub.Invoke("pararMov", act);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
jugadores[it].movimiento();
jugadores[it].ChoquePared();
for (int i = 0; i < comidas.Count(); i++)
{
//comidas[i].dibujar(g);
draw.getXY(comidas[i].x, comidas[i].y);
draw.FromImageManzana(gNewImg, comidas[i].x, comidas[i].y); //Imprime el sprite
if (jugadores[it].interseccion(comidas[i]))
{
if (jugadores[it].partes.Count() > 0)
{
jugadores[it].meter(jugadores[it].partes.Last().PositionX, jugadores[it].partes.Last().PositionY);
}
else
{
jugadores[it].meter(jugadores[it].x, jugadores[it].y);
}
comidas[i].colocarComidaUno(comidas[i].x, comidas[i].y);
comidas.Remove(comidas[i]);
jugadores[it].sumarPunto();
ApiConexion._hub.Invoke("refrescarPuntuacion");
}
}
}
}
_canvas.Image = newImg;
});
This fixes a good part of the flicker. Occasionally I see a flicker when getting food, but I suspect it has nothing to do with the picturebox.
I will pass the source code as soon as I can