Results 1 to 9 of 9

Thread: Best approach to animating lots of images?

  1. #1

    Thread Starter
    New Member
    Join Date
    Jun 2013
    Location
    United Kingdom
    Posts
    8

    Best approach to animating lots of images?

    I need to do simple 2D modelling of atoms & molecules (random walk motion etc) but am not sure of the best approach as there seems to be many ways of animating on a form.

    My own simple experiment was to use (in very basic outline):

    Code:
    Dim graWindow As Graphics
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            graWindow = Me.CreateGraphics     'initialise "canvas"
        End Sub
    
        Private Sub btnGo_Click(sender As Object, e As EventArgs) Handles btnGo.Click
            iterations = 0
            Do until iterations = maxIterations
                 atoms = 0
                 Do Until atoms = numberOfAtoms
                     <...code to calculate new "atom co-ords"...>
                     graWindow.FillEllipse(<...some colour...>,<...new "atom" co-ords & size data...>) 'put atom on screen
                     <...some sort of delay...>
                     graWindow.FillEllipse(<...background colour...>,<...new "atom" co-ords & size data....>)   'delete atom from screen
                     atoms += 1
                  Loop
                  iterations += 1
            Loop
        End Sub

    However, I don't know if this is the accepted/standard way to animate things in VB. I've seen one code where animation was done (on a single image) using a picture box control to contain the drawn shape. But would this work for 500-1000 little picture boxes?

    I'm (obviously) not experienced in VB 2012 so any detailed help on this would be great.

    Thx
    Last edited by pyeeyp; Jun 17th, 2013 at 06:52 AM. Reason: Formatting error

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Best approach to animating lots of images?

    If animation is fundamental to your application then you may be better off looking into WPF. It's more work to learn than Windows Forms but has native support for animation.

    If you are going to stick with WinForms then you definitely don't do it that way. You should pretty much never be calling CreateGraphics. If you want to draw on a control then you do so on that control's Paint event, either in the event handler or an overridden OnPaint method. To animate, you would use a Timer, set up the data for the drawing in the Tick event and then do the drawing in the Paint event handler.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  3. #3
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Best approach to animating lots of images?

    That number of animations is probably going to be too much for GDI, so WPF or XNA is likely to be the only way that works. The way you might be able to get that many animations to work in GDI is if you can build up a library of pre-rendered images and just swap them in and out. That will handle hundreds of images pretty well using GDI, but if you have to do the actual drawing each time, then the performance will likely suffer. Both WPF and XNA make use of the graphics system on the computer, so they are going to do much better with graphics than GDI, which uses the CPU for all graphics work.
    My usual boring signature: Nothing

  4. #4
    PowerPoster Evil_Giraffe's Avatar
    Join Date
    Aug 2002
    Location
    Suffolk, UK
    Posts
    2,555

    Re: Best approach to animating lots of images?

    GDI cannot handle 500-1000 calls to DrawEllipse in a single frame? I would not immediately assume that. (Noting of course that the position calculation will be moved out of the rendering phase and that the second set of ellipse drawings will vanish as there is no need to delete them again.)

    [Edit: Also, I don't think this is the sort of animation that WPF is a natural fit for. I see no advantage in going WPF for this at all.]

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Best approach to animating lots of images?

    That's true. There's no real substitue for testing. However, I was drawing far less than that in rectangles and found the performance was dogging down. Drawing ellipses should be more problematic than drawing rectangles, so I'd be a bit surprised to find that ellipses work when rectangles weren't so good at that number.
    My usual boring signature: Nothing

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    111,221

    Re: Best approach to animating lots of images?

    You'd certainly want to be using double-buffering at least, i.e. draw everything to a single Bitmap first and then, on the Paint event, draw that Bitmap with a single call to DrawImage.
    Why is my data not saved to my database? | MSDN Data Walkthroughs
    VBForums Database Development FAQ
    My CodeBank Submissions: VB | C#
    My Blog: Data Among Multiple Forms (3 parts)
    Beginner Tutorials: VB | C# | SQL

  7. #7

    Thread Starter
    New Member
    Join Date
    Jun 2013
    Location
    United Kingdom
    Posts
    8

    Re: Best approach to animating lots of images?

    Oh dear, way over my head. Tried going through the WPF stuff at msdn library but... Oh well :-((

  8. #8
    PowerPoster dunfiddlin's Avatar
    Join Date
    Jun 2012
    Posts
    8,245

    Re: Best approach to animating lots of images?

    Before we get too carried away, what exactly do you want from these animations? If they're simple start at the start, end at the end, go round again if required sort of things, pictureboxes support animated gifs. If you want a little more control over where it starts, how fast it goes, and so on there is also a VB animation class which is a bit quirky but works reasonably well.
    As the 6-dimensional mathematics professor said to the brain surgeon, "It ain't Rocket Science!"

    Reviews: "dunfiddlin likes his DataTables" - jmcilhinney

    Please be aware that whilst I will read private messages (one day!) I am unlikely to reply to anything that does not contain offers of cash, fame or marriage!

  9. #9
    Super Moderator dday9's Avatar
    Join Date
    Mar 2011
    Posts
    12,375

    Re: Best approach to animating lots of images?

    Here is a quick XNA example I worked up:
    Code:
    Option Strict On
    Option Explicit On
    
    Imports Microsoft.Xna.Framework
    Imports Microsoft.Xna.Framework.Graphics
    Public Class Form1
        Private grafix As Graphics.GraphicsDevice = Nothing
        Private s_Batch As SpriteBatch
        Private sprite As New List(Of Texture2D)
        Private atoms As New List(Of Atom)
        Private r As New Random
    
        Private Function initialize(ByRef surface As PictureBox) As Boolean
            Try
                'Sets up some parameters
                Dim pparam As New PresentationParameters
                pparam.DeviceWindowHandle = surface.Handle
                pparam.IsFullScreen = False
    
                'Set up the graphicsadapter
                Dim grafixAdapt As GraphicsAdapter = GraphicsAdapter.DefaultAdapter
    
                grafix = New GraphicsDevice(grafixAdapt, GraphicsProfile.HiDef, pparam)
    
                'Return a true value
                initialize = True
            Catch ex As Exception
                initialize = False
            End Try
        End Function
    
        Public Shared Function BitmapToTexture2D(GraphicsDevice As GraphicsDevice, image As System.Drawing.Bitmap) As Texture2D
            'Essential to convert the Bitmap to a Texture2d
            Dim bufferSize As Integer = image.Height * image.Width * 4
    
            Dim memoryStream As New System.IO.MemoryStream(bufferSize)
            image.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png)
    
            memoryStream.Seek(0, IO.SeekOrigin.Begin)
            Dim texture As Texture2D = Texture2D.FromStream(GraphicsDevice, memoryStream, image.Width, image.Height, False)
    
            memoryStream.Close()
            Return texture
        End Function
    
        Private Sub GetRandomAtoms()
            'Loop from 0 - 1000
            For int As Integer = 0 To 1000
                'Get a random integer
                Dim i As Integer = r.Next
    
                'Set up a new atom and a new bitmap
                Dim atm As New Atom
                Dim b As New Bitmap(50, 50)
                Dim g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(b) 'Have to clarrify it's from System and not XNA
    
                'Set the atom's properties
                With atm
                    .Mass = i
                    .IsStable = CBool(i Mod 2)
                    .Size = New Size(50, 50)
                    .Location = New Point(r.Next(0, 100), r.Next(0, 100))
                    If CBool(i Mod 2) Then
                        .Charge = Atom.IonicCharge.Negative
                        g.FillEllipse(Brushes.Red, 0, 0, 50, 50)
                        g.Save()
                    Else
                        .Charge = Atom.IonicCharge.Positive
                        g.FillEllipse(Brushes.Blue, 0, 0, 50, 50)
                        g.Save()
                    End If
                    .Image = b
                    .Path = RandomPoints()
                End With
    
                'Add the atom to the atom list and to the sprite list
                atoms.Add(atm)
                sprite.Add(BitmapToTexture2D(grafix, b))
            Next
        End Sub
    
        Private Function RandomPoints() As List(Of Point)
            'Gets some random x/y coordinates
            RandomPoints = New List(Of Point)
    
            For i As Integer = 0 To 9
                RandomPoints.Add(New Point(r.Next(0, 50), r.Next(0, 50)))
            Next
    
            Return RandomPoints
        End Function
    
        Private Sub Load_Content()
            'If we initialized the grafix then...
            If initialize(pb_surface) = True Then
                'Set up a new instance of the spritebatch
                s_Batch = New SpriteBatch(grafix)
    
                'Get some random atoms
                Call GetRandomAtoms()
    
                'Run baby run!
                BackgroundWorker1.RunWorkerAsync()
            Else
                Throw New ArgumentNullException("Grafix")
                Exit Sub
            End If
    
        End Sub
    
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            'Infinate loop
            Do Until True = False
    
                'Static value to keep count of the trajectory path
                Static atm_path As Integer = 0
    
                'Clear the grafix
                grafix.Clear(Color.CornflowerBlue)
    
                With s_Batch
                    'Loop through each atom
                    For atm_count As Integer = 0 To sprite.Count - 1
                        If atm_path < atoms.Item(atm_count).Path.Count - 1 Then
                            'Begin...
                            .Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend)
    
                            'Draw...
                            .Draw(sprite.Item(atm_count), New Rectangle(atoms.Item(atm_count).Location.X, atoms.Item(atm_count).Location.Y, atoms.Item(atm_count).Size.Width, atoms.Item(atm_count).Size.Height), Color.CornflowerBlue)
    
                            'End...
                            .End()
    
                            'Increment by 1
                            atm_path += 1
                        Else
                            atm_path = 0
                        End If
                    Next
                End With
    
                'Present the spritebatch
                grafix.Present()
            Loop
    
        End Sub
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Call Load_Content()
        End Sub
    End Class
    
    Public Class Atom
    
        Private _mass As Integer = 0
        Public Property Mass() As Integer
            Get
                Return _mass
            End Get
            Set(ByVal value As Integer)
                _mass = value
            End Set
        End Property
    
        Public Enum IonicCharge
            Positive
            Negative
            Neutral
        End Enum
    
        Private _charge As IonicCharge = IonicCharge.Neutral
        Public Property Charge() As IonicCharge
            Get
                Return _charge
            End Get
            Set(ByVal value As IonicCharge)
                _charge = value
            End Set
        End Property
    
        Private _stable As Boolean
        Public Property IsStable() As Boolean
            Get
                Return _stable
            End Get
            Set(ByVal value As Boolean)
                _stable = value
            End Set
        End Property
    
        Private _image As Bitmap
        Public Property Image() As Bitmap
            Get
                Return _image
            End Get
            Set(ByVal value As Bitmap)
                _image = value
            End Set
        End Property
    
        Private coordinates As Point
        Public Property Location() As Point
            Get
                Return coordinates
            End Get
            Set(ByVal value As Point)
                coordinates = value
            End Set
        End Property
    
        Private _size As Size
        Public Property Size() As Size
            Get
                Return _size
            End Get
            Set(ByVal value As Size)
                _size = value
            End Set
        End Property
    
        Private _path As List(Of Point)
        Public Property Path() As List(Of Point)
            Get
                Return _path
            End Get
            Set(ByVal value As List(Of Point))
                _path = value
            End Set
        End Property
    
    End Class
    It's very unrealistic, but it gets the point across that it can move 1001 atoms in a random path at once with 0 slow down.

    Edit - Something else I forgot to mention is that each atom has 10 points in it's Path() list. So not only is it running 1001 different atoms, but it's moving altogether 10,010 times each time the for loop ends.
    Last edited by dday9; Jun 17th, 2013 at 03:10 PM. Reason: Added comments to the code
    "Code is like humor. When you have to explain it, it is bad." - Cory House
    VbLessons | HtmlLessons | CssLessons | Code Tags | Sword of Fury - Jameram

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width