Уроки, алгоритмы, программы, примеры

Вход на сайт

Материалы по разделам

Построения
на плоскости (2D)
Графика
в пространстве (3D)
Вычислительная
геометрия
Физическое
моделирование
Фрактальная
графика

Новые комментарии

Спасибо за реализацию, она действительно быстрая. Но не все линии отрисовывает в нужную сторону... Необходимо добавить проверку для случая X-линии if(y1 "<" y0) grad=-grad; и аналогично для Y-линии if(x1 "<" x0) grad=-grad; P.S. На...
Отличные уроки(учу GL по ним), только в renderScene нужно добавить очистку буфера цвета и буфера глубины. При изменении размеров треугольники размножаются)
как исправить это , сделал все по инструкции
Timer1 - выдает ошибку. Использовал IdleTimer1, работает! unit Unit1; {$mode objfpc}{$H+} interface uses Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, OpenGLContext, GL, GLU; type { TForm1 } TForm1 =...
в коде присутствуют ошибки! // Считываем координаты procedure TForm1.getCoords(Sender: TObject); var j1:longint; begin n:= StrToInt(Edit2.Text); //число точек s1:=Edit1.Text; s2:=''; i := 1; j:=1; k:=0...

Счетчики и рейтинг

Яндекс.Метрика Рейтинг@Mail.ru
Среда программирования: 
Microsoft C#

Если после прочтения предыдущего урока Вы попытались сделать анимацию, состоящую из небольшого количества элементов, то никаких проблем с анимацией не должно было возникнуть.
Но если картинка будет состоять из множества элементов или будет необходимость закрашивать весь фон, или будет анимация по неоднородному фону, а следовательно потребуется прорисовка большого количества элементов, то метод описанный в предыдущем уроке уже работать не будет и возникнут проблемы с «миганием» анимации. Например, как показано на гифке ниже, которая самую малость мерцает. (код данной анимации будет чуть ниже, уже в исправленном виде.)

Перейдем к решению этой проблемы.

Описания создания проекта, добавления всех необходимых элементов на форму и настройки таймера тут не будет. Подразумевается, что все манипуляции уже проводятся с готовым проектом, который необходимо исправить.

Для того, чтобы избавиться от мигания, нам необходимо будет завести некий буфер, на котором мы будем рисовать, а потом уже его в готовом виде отображать на pictureBox по тику таймера. В роли такого буфера выступит Bitmap.
Следовательно, всё что нам потребуется – это объявить объект типа Bitmap Bitmap myBitmap;(как глобальную переменную) и объект типа Graphics Graphics gr; .

Затем инициализируем Bitmap, указав размеры (ширину и высоту) myBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height); И привязываем графику не к PictureBox, как было ранее, а к созданному буферу – Bitmap gr = Graphics.FromImage(myBitmap);

Далее почти весь процесс рисования аналогичен процессу, приведенному в предыдущем уроке, но добавляется одна строчка, которая нужна для вывода Bitmap на PictureBox - pictureBox1.Image = myBitmap; Эта строчка указывает, какое изображение, должен отображать PictureBox.

Ниже приведен код исправленной не мигающей анимации.
Из-за того, что код вышел немножко большим, то советую обратить внимание лишь на работу с графикой - объявление и инициализация Bitmap, Graphics и вывод изображения на форму, а определения классов просто скопировать (начиная с class chset и по class circles).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace Lesson_Animation_Part2
{
    public partial class Form1 : Form
    {
        // объявляем объект типа Bitmap, который будет буфером для хранения
        // и прорисовки изображений
        Bitmap myBitmap; 
 
        // объявляем "средства" рисования - графику, перо и заливку
        Graphics gr; 
        Pen pen;
        SolidBrush brush;
 
        // объявляем переменные для храения центра рисуемого изображения
        // и смещения его относительно заданного центра
        int centerX;
        int centerY;
        int offsetX;
        int offsetY;
 
        // переменные для движения в анимации
        int movX;
        int movY;
 
        // объявляем объекты - части тела, рисуемого изображения
        // писание соответствующих классов будет ниже
        Circles circ;
        Chest ch;
        Shirt sh;
        Pants pa;
        Legs le;
        Cuffs cu;
        LHand lha;
        RHand rha;
        Eye bEye;
        Eye fEye;
        Mouth mo;
 
        // описание функции, для задания смещения изображения
        // при анимации, которая использует функции-методы определенных классов
        void setOffset(int x, int y)
        {
            ch.setOffset(x, y);
            bEye.setOffset(x, y);
            fEye.setOffset(x, y);
            mo.setOffset(x, y);
            lha.setOffset(x, y);
            rha.setOffset(x, y);
        }
 
 
 
        //класс - туловище изображения
        // так как само содержимое классов не сильно отличается, то 
        // только данный класс будет описан подробно
        // остальным будет дано лишь описание рисуемой части "тела"
        public class Chest
        {
            // переменные для хранения центра и смещения изображения
            int cenX;
            int cenY;
            int offsX;
            int offsY;
            // заливка туловища
            SolidBrush BrChest = new SolidBrush(Color.Yellow);
 
            // конструктор класса, который определеяем центр и смещение
            public Chest(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx;
                cenY = Cy;
                offsX = offX;
                offsY = offY;
            }
 
            // функция, для задания смещения при анимации
            public void setOffset(int x, int y)
            {
                offsX += x;
                offsY += y;
            }
 
            // функция для прорисовка данной части "тела"
            // принимает графику, которой рисует и перо
            public void Draw(Graphics b, Pen p)
            {
                // рисуем переднюю часть туловища
                Rectangle Chest1 = new Rectangle(cenX - 150 + offsX, cenY - 175 + offsY, 220, 175);
                b.FillRectangle(BrChest, Chest1);
                b.DrawRectangle(p, Chest1);
 
                // определяем многоугольник для того, чтобы придать
                // ощущение объемного тела изображения
                Point[] Chest2 = new Point[]{
                new Point(cenX - 150 + offsX, cenY - 175 + offsY), 
                new Point(cenX - 175 + offsX, cenY - 160 + offsY),
 
                new Point(cenX - 175 + offsX, cenY + 15 + offsY),
                new Point(cenX - 150 + offsX, cenY + offsY)
            };
                // заливаем полученную фигуру
                b.FillPolygon(BrChest, Chest2);
                b.DrawPolygon(p, Chest2);
 
            }
        }
 
        //класс для рисования рубашки (слой между телом и штанами)
        //никуда не сдвигается при анимации
        public class Shirt
        {
            int cenX;
            int cenY;
            int offsX;
            int offsY;
            SolidBrush BrShirt = new SolidBrush(Color.LightSteelBlue);
 
            public Shirt(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx;
                cenY = Cy;
                offsX = offX;
                offsY = offY;
            }
            public void Draw(Graphics b, Pen p)
            {
                Rectangle Shirt1 = new Rectangle(cenX - 150 + offsX, cenY + offsY, 220, 50);
                b.FillRectangle(BrShirt, Shirt1);
                b.DrawRectangle(p, Shirt1);
 
                Point[] Shirt2 = new Point[]{
                    new Point(cenX - 150 + offsX, cenY + offsY), 
                    new Point(cenX - 175 + offsX, cenY  + 15 + offsY),
 
                    new Point(cenX - 175 + offsX, cenY + 65 + offsY),
                    new Point(cenX - 150 + offsX, cenY + 50 + offsY)
            };
                b.FillPolygon(BrShirt, Shirt2);
                b.DrawPolygon(p, Shirt2);
 
 
            }
        }
 
        //класс для рисования штанов
        //никуда не сдвигается при анимации
        public class Pants
        {
            int cenX;
            int cenY;
            int offsX;
            int offsY;
            SolidBrush BrPants = new SolidBrush(Color.SaddleBrown);
 
            public Pants(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx;
                cenY = Cy;
                offsX = offX;
                offsY = offY;
            }
 
            public void Draw(Graphics b, Pen p)
            {
                Rectangle Pants1 = new Rectangle(cenX - 150 + offsX, cenY + 50 + offsY, 220, 50);
                b.FillRectangle(BrPants, Pants1);
                b.DrawRectangle(p, Pants1);
 
                Point[] Pants2 = new Point[]{
                    new Point(cenX - 150 + offsX, cenY  + 50 + offsY), 
                    new Point(cenX - 175 + offsX, cenY  + 65 + offsY),
 
                    new Point(cenX - 175 + offsX, cenY   + 115 + offsY),
                    new Point(cenX - 150 + offsX, cenY  + 100 + offsY)
            };
                b.FillPolygon(BrPants, Pants2);
                b.DrawPolygon(p, Pants2);
 
                Point[] Pants3 = new Point[]{
                    new Point(cenX - 175  + offsX, cenY   + 115 + offsY),
                    new Point(cenX - 150 + offsX, cenY  + 100 + offsY),
 
                    new Point(cenX + 70 + offsX, cenY  + 100 + offsY),
                    new Point(cenX + 45 + offsX, cenY  + 115 + offsY),
                    new Point(cenX - 175 + offsX, cenY   + 115 + offsY)
            };
                b.FillPolygon(BrPants, Pants3);
                b.DrawPolygon(p, Pants3);
 
            }
 
        }
 
        //класс для рисования ног
        //никуда не сдвигается при анимации
        public class Legs
        {
            int cenX;
            int cenY;
            int offsX;
            int offsY;
            SolidBrush BrLegs = new SolidBrush(Color.SaddleBrown);
            SolidBrush BrFoot = new SolidBrush(Color.Black);
            public Legs(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx;
                cenY = Cy;
                offsX = offX;
                offsY = offY;
            }
 
            public void Draw(Graphics b, Pen p)
            {
                Rectangle Leg1 = new Rectangle(cenX - 130 + offsX, cenY + 110 + offsY, 40, 40);
                Rectangle Leg2 = new Rectangle(cenX - 10 + offsX, cenY + 110 + offsY, 40, 40);
                b.FillRectangle(BrLegs, Leg1);
                b.FillRectangle(BrLegs, Leg2);
                b.DrawRectangle(p, Leg1);
                b.DrawRectangle(p, Leg2);
 
                Point leg1_1 = new Point(cenX - 110 + offsX, cenY + 150 + offsY);
                Point leg1_2 = new Point(cenX - 110 + offsX, cenY + 210 + offsY);
 
                Point leg2_1 = new Point(cenX + 10 + offsX, cenY + 150 + offsY);
                Point leg2_2 = new Point(cenX + 10 + offsX, cenY + 210 + offsY);
 
                b.DrawLine(p, leg1_1, leg1_2);
                b.DrawLine(p, leg2_1, leg2_2);
 
                Rectangle leg1_3 = new Rectangle(cenX - 160 + offsX, cenY + 190 + offsY, 70, 30);
                b.FillEllipse(BrFoot, leg1_3);
                b.DrawEllipse(p, leg1_3);
 
                Rectangle leg2_3 = new Rectangle(cenX - +10 + offsX, cenY + 190 + offsY, 70, 30);
                b.FillEllipse(BrFoot, leg2_3);
                b.DrawEllipse(p, leg2_3);
            }
 
        }
 
        //класс для рисования манжетов и галстука
        //никуда не сдвигается при анимации
        public class Cuffs
        {
            int cenX;
            int cenY;
            int offsX;
            int offsY;
            SolidBrush BrCuffs = new SolidBrush(Color.White);
 
            public Cuffs(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx;
                cenY = Cy;
                offsX = offX;
                offsY = offY;
            }
 
            public void Draw(Graphics b, Pen p)
            {
                Point[] Cuffs1 = new Point[]{
                new Point(cenX + offsX - 90, cenY + offsY ), 
                new Point(cenX + offsX - 70, cenY + offsY  + 25),
 
                new Point(cenX + offsX - 50, cenY + offsY  ),
                //new Point(cenX + offsX - 150, cenY + offsY  + 50)
 
            };
                b.FillPolygon(BrCuffs, Cuffs1);
                b.DrawPolygon(p, Cuffs1);
 
                Point[] Cuffs2 = new Point[]{
                new Point(cenX + offsX + 10, cenY + offsY ), 
                new Point(cenX + offsX - 10, cenY + offsY  + 25),
 
                new Point(cenX + offsX - 30, cenY + offsY  ),
                //new Point(cenX + offsX - 150, cenY + offsY  + 50)
 
            };
                b.FillPolygon(BrCuffs, Cuffs2);
                b.DrawPolygon(p, Cuffs2);
 
                SolidBrush BrCuffs3 = new SolidBrush(Color.Red);
                Point[] Cuffs3_1 = new Point[]{
                new Point(cenX + offsX - 50, cenY + offsY ), 
                new Point(cenX + offsX - 40, cenY + offsY  + 15),
 
                new Point(cenX + offsX - 30, cenY + offsY  ),
                //new Point(cenX + offsX - 150, cenY + offsY  + 50)
            };
 
                b.FillPolygon(BrCuffs3, Cuffs3_1);
                b.DrawPolygon(p, Cuffs3_1);
 
                Point[] Cuffs3_2 = new Point[]{ 
                new Point(cenX + offsX - 40, cenY + offsY  + 15),
                new Point(cenX + offsX - 50, cenY + offsY + 60), 
                new Point(cenX + offsX - 40, cenY + offsY  + 75),
                new Point(cenX + offsX - 30, cenY + offsY + 60 )
            };
 
                b.FillPolygon(BrCuffs3, Cuffs3_2);
                b.DrawPolygon(p, Cuffs3_2);
            }
        }
 
        //классы для рисования левой и правой руки
        //задействованы в анимации
        public class LHand
        {
            int cenX;
            int cenY;
 
            SolidBrush BrHand = new SolidBrush(Color.Yellow);
 
            public LHand(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx + offX - 155;
                cenY = Cy + offY - 20;
            }
            public void setOffset(int x, int y)
            {
                cenX += x;
                cenY += y;
            }
            public void Draw(Graphics b, Pen p)
            {
                Point[] shoulder = new Point[]{
                    new Point(cenX, cenY),
                    new Point(cenX - 15, cenY - 5),
                    new Point(cenX - 40, cenY + 40),
                    new Point(cenX, cenY + 50)
                };
                b.FillPolygon(BrHand, shoulder);
                b.DrawPolygon(p, shoulder);
 
                Point Hand1 = new Point(cenX - 20, cenY + 45);
                Point Hand2 = new Point(cenX - 35, cenY + 100);
 
                Point Palm1 = new Point(cenX - 50, cenY + 110);
                Point Palm2 = new Point(cenX - 30, cenY + 115);
                Point Palm3 = new Point(cenX - 45, cenY + 120);
                b.DrawLine(p, Hand1, Hand2);
                b.DrawLine(p, Hand2, Palm1);
                b.DrawLine(p, Hand2, Palm2);
                b.DrawLine(p, Hand2, Palm3);
            }
        }
 
        public class RHand
        {
            int cenX;
            int cenY;
 
            SolidBrush BrHand = new SolidBrush(Color.Yellow);
 
            public RHand(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx + offX + 70;
                cenY = Cy + offY - 30;
            }
            public void setOffset(int x, int y)
            {
                cenX += x;
                cenY += y;
            }
            public void Draw(Graphics b, Pen p)
            {
                Point[] shoulder = new Point[]{
                    new Point(cenX, cenY),
                    new Point(cenX, cenY - 15),
                    new Point(cenX + 40, cenY - 40),
                    new Point(cenX + 45, cenY - 5)
                };
                b.FillPolygon(BrHand, shoulder);
                b.DrawPolygon(p, shoulder);
 
                Point Hand1 = new Point(cenX + 43, cenY - 20);
                Point Hand2 = new Point(cenX + 93, cenY - 50);
 
                Point Palm1 = new Point(cenX + 105, cenY - 65);
                Point Palm2 = new Point(cenX + 110, cenY - 35);
                Point Palm3 = new Point(cenX + 110, cenY - 50);
                b.DrawLine(p, Hand1, Hand2);
                b.DrawLine(p, Hand2, Palm1);
                b.DrawLine(p, Hand2, Palm2);
                b.DrawLine(p, Hand2, Palm3);
            }
        }
 
        //класс для рисования глаз
        //двигается вместе с туловищем
        public class Eye
        {
            int cenX;
            int cenY;
            int r1, r2, r3;
 
            SolidBrush e1 = new SolidBrush(Color.Black);
            SolidBrush e2 = new SolidBrush(Color.Cyan);
            SolidBrush e3 = new SolidBrush(Color.White);
 
            public Eye(int Cx, int Cy, int offX, int offY, int ra1, int ra2, int ra3)
            {
                cenX = Cx + offX - 40;
                cenY = Cy + offY - 150;
                r1 = ra1;
                r2 = ra2;
                r3 = ra3;
            }
            public void setOffset(int x, int y)
            {
                cenX += x;
                cenY += y;
            }
 
            public void Draw(Graphics b, Pen p)
            {
                b.FillEllipse(e3, cenX, cenY, r3, r3);
                b.DrawEllipse(p, cenX, cenY, r3, r3);
 
                b.FillEllipse(e2, cenX + r3 / 4 - 1, cenY + r3 / 4 - 1, r2, r2);
                b.DrawEllipse(p, cenX + r3 / 4 - 1, cenY + r3 / 4 - 1, r2, r2);
 
                b.FillEllipse(e1, cenX + r3 / 3 + 4, cenY + r3 / 3 + 4, r1, r1);
                b.DrawEllipse(p, cenX + r3 / 3 + 4, cenY + r3 / 3 + 4, r1, r1);
 
                Point b1 = new Point(cenX, cenY - 5);
                Point b2 = new Point(cenX + 10, cenY + 10);
                Point b3 = new Point(cenX + 20, cenY - 5);
                Point b4 = new Point(cenX + 30, cenY - 5);
 
                b.DrawBezier(p, b1, b2, b3, b4);
            }
 
        }
 
        //класс дли рисования рта
        //двигается вместе с туловищем
        public class Mouth
        {
            int cenX;
            int cenY;
            SolidBrush BrTongue = new SolidBrush(Color.Salmon);
            SolidBrush BrTooth = new SolidBrush(Color.White);
            SolidBrush BrNose = new SolidBrush(Color.Gold);
            public Mouth(int Cx, int Cy, int offX, int offY)
            {
                cenX = Cx + offX - 20;
                cenY = Cy + offY - 50;
 
            }
 
            public void setOffset(int x, int y)
            {
                cenX += x;
                cenY += y;
            }
            public void Draw(Graphics b, Pen p)
            {
                Point p1 = new Point(cenX - 50, cenY - 20);
                Point p2 = new Point(cenX - 10, cenY + 20);
                Point p3 = new Point(cenX + 20, cenY + 5);
                Point p4 = new Point(cenX + 40, cenY - 10);
 
                Point p5 = new Point(cenX - 50, cenY - 20);
                Point p6 = new Point(cenX - 20, cenY + 60);
                Point p7 = new Point(cenX + 40, cenY + 70);
                Point p8 = new Point(cenX + 40, cenY - 10);
 
 
                b.DrawBezier(p, p1, p2, p3, p4);
                b.DrawBezier(p, p5, p6, p7, p8);
 
                b.FillPie(BrTongue, cenX - 30, cenY + 20, 40, 40, 15, -150);
                b.DrawPie(p, cenX - 30, cenY + 20, 40, 40, 15, -150);
 
                Point[] tooth = new Point[]{
                 new Point(cenX - 10, cenY +5),
                 new Point(cenX - 10, cenY + 15),
                 new Point(cenX + 5, cenY + 15),
                 new Point(cenX + 5, cenY + 5)
             };
 
                b.FillPolygon(BrTooth, tooth);
                b.DrawPolygon(p, tooth);
 
                Rectangle nose = new Rectangle(cenX - 20, cenY - 35, 50, 30);
                b.FillEllipse(BrNose, nose);
                b.DrawEllipse(p, nose);
 
 
            }
 
        }
 
        //класс для обрамления рисуемой области
        //хранит центры и радиус кругов
        //функция рисования реализуется при помощи двух циклов,
        //которые рисуют кружки на противоположных сторонах PictureBox
        public class Circles
        {
 
            public int radius;
            public int x;
            public int y;
 
 
            SolidBrush crlB = new SolidBrush(Color.Green);
 
            public Circles()
            {
                radius = 20;
                x = 5;
                y = 5;
            }
            public void Draw(Pen p, Graphics b, PictureBox pBox)
            {
                while (x <= pBox.Width - radius)
                {
                    b.FillEllipse(crlB, x, y, radius, radius);
                    b.DrawEllipse(p, x, y, radius, radius);
                    b.FillEllipse(crlB, x, pBox.Height - radius, radius, radius);
                    b.DrawEllipse(p, x, pBox.Height - radius, radius, radius);
                    x += radius;
                }
 
                x -= radius;
                while (y <= pBox.Height - radius)
                {
                    b.FillEllipse(crlB, x, y, radius, radius);
                    b.DrawEllipse(p, x, y, radius, radius);
                    b.FillEllipse(crlB, 5, y, radius, radius);
                    b.DrawEllipse(p, 5, y, radius, radius);
                    y += radius;
                }
                x = 5;
                y = 5;
            }
 
 
 
 
 
        }
 
        public Form1()
        {
            InitializeComponent();
        }
 
        //функция обработки нажатия клавиши
        private void button1_Click(object sender, EventArgs e)
        {
            //инициализируем Bitmap, задав его размеры, на которых будем рисовать
            myBitmap = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            //привязываем графику к нашему Bitmap
            gr = Graphics.FromImage(myBitmap);
            // gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            //инициализируем перо и фоновую заливку
            pen = new Pen(Color.Black);
            brush = new SolidBrush(Color.Aqua);
 
            // задаем центр рисуемого изображения и смещение
            centerX = pictureBox1.Width / 2;
            centerY = pictureBox1.Height / 2;
            offsetX = 0;
            offsetY = 0;
 
 
            //закрашиваем фон
            gr.FillRectangle(brush, 0, 0, pictureBox1.Width, pictureBox1.Height);
 
            //инициализируем объекты, в соответствии с описанными конструкторами
            //передав центр и смещение относительно центра
            circ = new Circles();
            ch = new Chest(centerX, centerY, offsetX, offsetY);
            sh = new Shirt(centerX, centerY, offsetX, offsetY);
            pa = new Pants(centerX, centerY, offsetX, offsetY);
            le = new Legs(centerX, centerY, offsetX, offsetY);
            cu = new Cuffs(centerX, centerY, offsetX, offsetY);
            lha = new LHand(centerX, centerY, offsetX, offsetY);
            rha = new RHand(centerX, centerY, offsetX, offsetY);
            bEye = new Eye(centerX, centerY, offsetX, offsetY, 20, 40, 70);
            fEye = new Eye(centerX - 50, centerY, offsetX, offsetY, 20, 40, 70);
            mo = new Mouth(centerX, centerY, offsetX, offsetY);
 
            //рисуем НА БУФЕРЕ!:
 
            // кружочки
            circ.Draw(pen, gr, pictureBox1);
 
            // тело
            ch.Draw(gr, pen);
 
            // Рубашка
            sh.Draw(gr, pen);
 
            //Штаны
            pa.Draw(gr, pen);
 
            // Ноги
            le.Draw(gr, pen);
 
            // манжеты
            cu.Draw(gr, pen);
 
            // руки
            lha.Draw(gr, pen);
            rha.Draw(gr, pen);
 
            // глаза
            bEye.Draw(gr, pen);
            fEye.Draw(gr, pen);
 
            //рот
            mo.Draw(gr, pen);
 
            //переносим изображение с буфера на PictureBox
            pictureBox1.Image = myBitmap;
 
            // обнуляем переменные для анимации
            movX = 0;
            movY = 0;
 
            //запускаем таймер (тик опять указан на 150мс)
            timer1.Enabled = true;
 
        }
 
        //обработка тика таймера (анимация)
        private void timer1_Tick(object sender, EventArgs e)
        {
            //присваиваем значение смещения  анимации
            movX += 5;
            movY -= 2;
            if (movX > 40) // контролируем перемещение
            {
                movX = -40;
                movY = 16;
            }
 
            //задаем смещение для анимации
            setOffset(movX, movY);
 
            // опять закрашиваем фон
            gr.FillRectangle(brush, 0, 0, pictureBox1.Width, pictureBox1.Height);
 
            // аналогично рисуем картинку по частям
            // и в конце "переносим" изображение с Bitmap на PictureBox
            // кружочки
            circ.Draw(pen, gr, pictureBox1);
 
            // тело
            ch.Draw(gr, pen);
 
            // Рубашка
            sh.Draw(gr, pen);
 
            //Штаны
            pa.Draw(gr, pen);
 
            // Ноги
            le.Draw(gr, pen);
 
            // манжеты
            cu.Draw(gr, pen);
 
            // руки
            lha.Draw(gr, pen);
            rha.Draw(gr, pen);
 
            // глаза
            bEye.Draw(gr, pen);
            fEye.Draw(gr, pen);
 
            //рот
            mo.Draw(gr, pen);
 
 
            pictureBox1.Image = myBitmap;
 
        }
 
    }
}

И вот полученный результат, в котором мы избавились от мигания.

Но наш Спанч Боб получился какой-то корявенький, поэтому можно добавить что-то вроде улучшенной графики, в которой включено сглаживание и регулировка прозрачности для цвета.
Это делается добавлением строчки
gr.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Сразу после инициализации графики (в приведенном выше кода данная строка закомментирована)

Вот теперь уже самый последний результат

Проект прикреплен ниже

Прикрепленный файлРазмер
Skopinskiy_LessonAnimationPart2.zip70.44 кб