|
-
Jun 17th, 2013, 06:51 AM
#1
Thread Starter
New Member
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
-
Jun 17th, 2013, 07:07 AM
#2
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.
-
Jun 17th, 2013, 09:00 AM
#3
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
 
-
Jun 17th, 2013, 09:08 AM
#4
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.]
-
Jun 17th, 2013, 09:15 AM
#5
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
 
-
Jun 17th, 2013, 09:37 AM
#6
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.
-
Jun 17th, 2013, 12:14 PM
#7
Thread Starter
New Member
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 :-((
-
Jun 17th, 2013, 01:04 PM
#8
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!
-
Jun 17th, 2013, 02:05 PM
#9
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
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|