This project showcases the fundamentals of creating smooth animations. The application features a moving rectangle that glides across the screen, illustrating key concepts such as frame independence and real-time rendering.
In this app, you'll learn how to manage timing, handle graphics rendering, and implement basic animation principles. Whether you're a beginner looking to understand the basics of animation or an experienced developer seeking a refresher, this project provides a hands-on approach to mastering animation techniques.
Welcome to the Animation project! In this lesson, we will break down the code line by line, helping you understand how it works. This project demonstrates the fundamentals of creating smooth animations using a Windows Form application. Let's dive right in!
Animation is the art of creating the illusion of motion by displaying a series of static images in quick succession. In our app, we use animation to make it appear as though our rectangle is moving towards the right. To ensure that our animation runs smoothly on all devices, we have designed it to be frame-independent. This means that our animation is not affected by changes in the frame rate, ensuring a consistent and seamless experience for all users.
This code is shared under the MIT License, which allows you to use, modify, and distribute it freely, as long as you include the original copyright notice.
Option Explicit On
- This line ensures that all variables must be declared before they are used. It helps prevent errors caused by typos in variable names.
Public Class Form1
- This line defines a new class named
Form1
, which represents our main application window. All the code inside this class will define the behavior and appearance of our form.
Private Context As New BufferedGraphicsContext
Private Buffer As BufferedGraphics
Context
is an instance ofBufferedGraphicsContext
, which manages the buffered graphics.Buffer
is an instance ofBufferedGraphics
, which will hold our drawing operations before rendering them on the screen.
Private ReadOnly MinimumMaxBufferSize As New Size(1280, 720)
Private ReadOnly BackgroundColor As Color = Color.Black
Private ReadOnly RectangleBrush As New SolidBrush(Color.Orchid)
Private ReadOnly FpsDisplayBrush As New SolidBrush(Color.MediumOrchid)
Private ReadOnly FpsIdentifier As New String(" FPS")
MinimumMaxBufferSize
sets the minimum size for our graphics buffer.BackgroundColor
defines the color of the background (black).RectangleBrush
defines the color of the rectangle (orchid).FpsDisplayBrush
defines the color for the frames per second (FPS) display (medium orchid).FpsIdentifier
is a string that will be appended to our FPS count for display purposes.
Public Structure RectangleDouble
Public X, Y, Width, Height As Double
- This defines a structure named
RectangleDouble
that represents a rectangle with double-precision coordinates and dimensions.
Public Sub New(x As Double, y As Double, width As Double, height As Double)
Me.X = x
Me.Y = y
Me.Width = width
Me.Height = height
End Sub
- This is the constructor for the
RectangleDouble
structure. It initializes a new rectangle with specified values for itsX
,Y
,Width
, andHeight
.
Public Function GetNearestX() As Integer
Return Math.Round(X)
End Function
- This method rounds the
X
coordinate to the nearest integer. Similar methods exist forY
,Width
, andHeight
.
Private Structure DeltaTimeStructure
Public CurrentFrame As DateTime
Public LastFrame As DateTime
Public ElapsedTime As TimeSpan
- This structure tracks the timing information for our animation, including the current and last frame times and the elapsed time between them.
Public Sub New(currentFrame As Date, lastFrame As Date, elapsedTime As TimeSpan)
Me.CurrentFrame = currentFrame
Me.LastFrame = lastFrame
Me.ElapsedTime = elapsedTime
End Sub
- This constructor initializes the
DeltaTimeStructure
with the current and last frame times.
Private Structure DisplayStructure
Public Location As Point
Public Text As String
Public Font As Font
- This structure holds information about display elements, including their location, text, and font.
Private Structure FrameCounterStructure
Public FrameCount As Integer
Public StartTime As DateTime
Public TimeElapsed As TimeSpan
Public SecondsElapsed As Double
- This structure counts the frames rendered and tracks the timing for calculating frames per second (FPS).
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitializeApp()
Debug.Print($"Running...{DateTime.Now}")
End Sub
- This method initializes the application when the form loads. It calls
InitializeApp()
to set up the necessary components and prints the current time to the debug console.
Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles MyBase.Resize
If Not WindowState = FormWindowState.Minimized Then
ResizeFPS()
ResizeRectangle()
DisposeBuffer()
End If
End Sub
- This method handles resizing the window. It adjusts the FPS display and rectangle size accordingly, ensuring everything looks good when the window is resized.
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
If Not WindowState = FormWindowState.Minimized Then
UpdateFrame()
Invalidate() ' Calls OnPaint Sub
End If
End Sub
- This event is triggered at regular intervals (every 15 milliseconds). It updates the animation frame and redraws the form.
Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
AllocateBuffer()
DrawFrame()
Buffer?.Render(e.Graphics)
UpdateFrameCounter()
MyBase.OnPaint(e)
End Sub
- This method handles the rendering of graphics. It allocates a buffer, draws the current frame, and updates the frame counter. The buffer is then rendered onto the form.
Private Sub DrawFrame()
Buffer?.Graphics.Clear(BackgroundColor)
Buffer?.Graphics.FillRectangle(RectangleBrush, Rectangle.GetNearestX, Rectangle.GetNearestY, Rectangle.GetNearestWidth, Rectangle.GetNearestHeight)
Buffer?.Graphics.DrawString(FPSDisplay.Text, FPSDisplay.Font, FpsDisplayBrush, FPSDisplay.Location)
End Sub
- This method clears the buffer with the background color, fills a rectangle with the specified brush, and draws the FPS display string.
Private Sub MoveRectangle()
Rectangle.X += Velocity * DeltaTime.ElapsedTime.TotalSeconds
If Rectangle.X > ClientRectangle.Right Then
Rectangle.X = ClientRectangle.Left - Rectangle.Width
End If
End Sub
- This method updates the rectangle's position based on its velocity and the elapsed time. If the rectangle moves off the right edge, it reappears on the left.
Private Sub InitializeApp()
InitializeForm()
InitializeBuffer()
Timer1.Interval = 15
Timer1.Start()
End Sub
- This method initializes the application, setting up the form and buffer, and starts the timer.
This walkthrough covers the main components of the animation project. Feel free to experiment with the code, adjust parameters, and see how they affect the animation! Happy coding!
For more information visit GitHub repository.