<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Custom Controls &#8211; Xojo Programming Blog</title>
	<atom:link href="https://blog.xojo.com/tag/custom-controls/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.xojo.com</link>
	<description>Blog about the Xojo programming language and IDE</description>
	<lastBuildDate>Wed, 04 Dec 2024 23:33:08 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>Create a Tic-Tac-Toe Game in Xojo &#8211; Step-by-Step Tutorial</title>
		<link>https://blog.xojo.com/2024/12/05/create-a-tic-tac-toe-game-in-xojo-step-by-step-tutorial/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Thu, 05 Dec 2024 15:30:00 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[Fun]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Custom Controls]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<category><![CDATA[Games]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=13994</guid>

					<description><![CDATA[Tic-tac-toe, a classic two-player strategy game where players take turns marking spaces in a 3&#215;3 grid. The objective is simple: be the first to get&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Tic-tac-toe, a classic two-player strategy game where players take turns marking spaces in a 3&#215;3 grid. The objective is simple: be the first to get three of your symbols (X or O) in a row, either horizontally, vertically, or diagonally.</p>



<p>By the end of this tutorial, you will learn how to:</p>



<ul class="wp-block-list">
<li>Create a desktop game application in Xojo</li>



<li>Use DesktopCanvas for game board rendering</li>



<li>Implement game logic and state management</li>



<li>Handle user interactions</li>



<li>Add visual effects and animations</li>
</ul>


<div class="wp-block-image is-style-default">
<figure class="aligncenter is-resized"><img decoding="async" src="https://storage.googleapis.com/co-writer/images/HRIwK4xjWLXvNRyAbzXbq5t8wJF3/-1731493084073.webp" alt="Modern TicTacToe game in Xojo" style="width:482px;height:auto"/></figure>
</div>


<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Setting Up the Project</h2>



<h3 class="wp-block-heading">Launch Xojo and Create a New Project</h3>



<ul class="wp-block-list">
<li>Open Xojo IDE</li>



<li>Select &#8220;Desktop&#8221; project type</li>



<li>Set an Application Name (e.g., &#8220;TicTacToe&#8221;)</li>



<li>Click &#8220;Create&#8221;</li>
</ul>



<h3 class="wp-block-heading">Creating the TicTacToeGame Custom Control</h3>



<p>To have a clear and modular code structure, the game logic and user interface will be implemented in a subclassed DesktopCanvas control.</p>



<p>Here are several key advantages for this approach:</p>



<ul class="wp-block-list">
<li><strong>Encapsulation:</strong> It neatly bundles all the game&#8217;s logic (like checking for wins or handling player turns) and visual elements (drawing the board, animating moves) into a single, self-contained unit. This makes your code cleaner, easier to understand, and simpler to maintain. You can reuse this control in other projects without rewriting everything.</li>



<li><strong>Organization:</strong> A custom control promotes better code organization by separating the game&#8217;s functionality from the rest of your application&#8217;s code. This reduces complexity, especially if your application grows larger and includes other features.</li>



<li><strong>Reusability:</strong> Once you&#8217;ve created the TicTacToeGame control, you can easily reuse it in other Xojo projects. Just drag and drop it onto a window!</li>



<li><strong>Abstraction:</strong> The custom control provides an abstraction layer. The rest of your application doesn&#8217;t need to know the internal workings of the TicTacToe game; it only needs to interact with the control&#8217;s interface (like starting a new game or getting the current score). This makes it easier to modify or update the game logic without affecting other parts of your application.</li>
</ul>



<p>Now, here are the steps to create this custom control based on DesktopCanvas:</p>



<ol class="wp-block-list">
<li>Click the &#8220;Insert&#8221; menu</li>



<li>Select &#8220;Class&#8221;</li>



<li>Name the class &#8220;TicTacToeGame&#8221;</li>



<li>Set the &#8220;Super&#8221; to &#8220;DesktopCanvas&#8221;</li>
</ol>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img fetchpriority="high" decoding="async" width="618" height="342" src="https://blog.xojo.com/wp-content/uploads/2024/11/image.png" alt="" class="wp-image-13998" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/image.png 618w, https://blog.xojo.com/wp-content/uploads/2024/11/image-300x166.png 300w" sizes="(max-width: 618px) 100vw, 618px" /></figure>
</div>



<div class="wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow">
<figure class="wp-block-image size-full"><img decoding="async" width="596" height="236" src="https://blog.xojo.com/wp-content/uploads/2024/11/image-1.png" alt="" class="wp-image-13999" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/image-1.png 596w, https://blog.xojo.com/wp-content/uploads/2024/11/image-1-300x119.png 300w" sizes="(max-width: 596px) 100vw, 596px" /></figure>
</div>
</div>



<h2 class="wp-block-heading">TicTacToeGame Class Structure</h2>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img decoding="async" width="554" height="950" src="https://blog.xojo.com/wp-content/uploads/2024/11/image-2.png" alt="" class="wp-image-14001" style="width:263px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/image-2.png 554w, https://blog.xojo.com/wp-content/uploads/2024/11/image-2-175x300.png 175w" sizes="(max-width: 554px) 100vw, 554px" /></figure>
</div>


<p>First, we start by defining some important constants and properties that will be used by the game class.</p>



<h3 class="wp-block-heading">Constants</h3>



<ol class="wp-block-list">
<li><code>Private Const kBoardSize as Number = 3</code>
<ul class="wp-block-list">
<li>Defines the grid dimensions (3&#215;3)</li>



<li>Used for iterating through board cells</li>



<li>Provides flexibility for potential future grid size changes</li>
</ul>
</li>



<li><code>Private Const kCellsPadding as Number = 40</code>
<ul class="wp-block-list">
<li>Controls spacing around X and O symbols</li>



<li>Ensures symbols don&#8217;t touch cell borders</li>



<li>Provides visual breathing room in cell drawings</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">Properties</h3>



<h4 class="wp-block-heading">Game State Properties</h4>



<ol class="wp-block-list">
<li><code>Public Property boardState(2,2) As Integer</code>
<ul class="wp-block-list">
<li>2D array representing game board</li>



<li>Values:
<ul class="wp-block-list">
<li>0 = Empty cell</li>



<li>1 = Player X</li>



<li>2 = Player O</li>
</ul>
</li>
</ul>
</li>



<li><code>Public Property currentPlayer As Integer = 1</code>
<ul class="wp-block-list">
<li>Tracks current turn</li>



<li>1 = Player X</li>



<li>2 = Player O</li>
</ul>
</li>



<li><code>Public Property isGameOver As Boolean = False</code>
<ul class="wp-block-list">
<li>Indicates game completion status</li>



<li>Prevents further moves after game ends</li>
</ul>
</li>
</ol>



<h4 class="wp-block-heading">Rendering Properties</h4>



<pre class="wp-block-code"><code>Public Property CellHeight As Integer
Get
  Return Height / 3
End Get

Set
  
End Set
End Property

Public Property CellWidth As Integer
Get
  Return Width / 3
End Get

Set
  
End Set
End Property</code></pre>



<ol class="wp-block-list">
<li><code>CellHeight</code>, <code>CellWidth As Integer</code>
<ul class="wp-block-list">
<li>Computed properties</li>



<li>Dynamically calculate cell dimensions based on canvas size</li>



<li>Divide width/height by 3 for equal grid cells</li>
</ul>
</li>



<li><code>ColorBoard</code>, <code>ColorX</code>, <code>ColorO</code><code>As Color</code>
<ul class="wp-block-list">
<li>Store color schemes for board elements</li>



<li>Support dark/light mode themes</li>
</ul>
</li>
</ol>



<h4 class="wp-block-heading">Animation Properties</h4>



<ol class="wp-block-list">
<li><code>Public Property animationProgress As Double</code>
<ul class="wp-block-list">
<li>Tracks symbol drawing animation</li>



<li>Ranges from 0 to 1</li>



<li>Controls symbol scaling during placement</li>
</ul>
</li>



<li><code>Public Property animationTimer As Timer</code>
<ul class="wp-block-list">
<li>Manages animation timing</li>



<li>Triggers smooth symbol rendering</li>
</ul>
</li>
</ol>



<h4 class="wp-block-heading">Interaction Tracking</h4>



<ol class="wp-block-list">
<li><code>Public Property HoverCol As Integer = -1</code>and <code>Public Property HoverCol As Integer = -1</code>
<ul class="wp-block-list">
<li>Track mouse position over grid</li>



<li>Enable hover effect on empty cells</li>



<li>Provide visual feedback during gameplay</li>
</ul>
</li>
</ol>



<h4 class="wp-block-heading">Scoring Properties</h4>



<ol class="wp-block-list">
<li><code>scoreX</code> and <code>scoreO</code><code>As Integer</code>
<ul class="wp-block-list">
<li>Track win counts for each player</li>



<li>Updated after each game</li>
</ul>
</li>
</ol>



<p>The constants and properties defined above will be crucial in the next steps, allowing us to implement the key features: encapsulation of game logic and rendering, flexible customization, responsive dynamic sizing and interactions, and an enhanced user experience through animations and hover effects.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Event Definitions</h2>


<div class="wp-block-image">
<figure class="alignright size-full is-resized"><img loading="lazy" decoding="async" width="552" height="236" src="https://blog.xojo.com/wp-content/uploads/2024/11/image-3.png" alt="" class="wp-image-14003" style="width:263px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/image-3.png 552w, https://blog.xojo.com/wp-content/uploads/2024/11/image-3-300x128.png 300w" sizes="auto, (max-width: 552px) 100vw, 552px" /></figure>
</div>


<p>To make sure our game class is complete, we will create two custom event definitions that will be used later throughout the game.</p>



<h3 class="wp-block-heading">GameStatus Event</h3>



<pre class="wp-block-code"><code>Event GameStatus(info As String, playerTurn As String = "", scoreX As Integer, scoreO As Integer)</code></pre>



<ul class="wp-block-list">
<li>Purpose: Tracks and communicates the current state of the game</li>



<li>Parameters:
<ol class="wp-block-list">
<li><code>info</code>: A string describing the current game status</li>



<li><code>playerTurn</code>: Optional parameter indicating which player&#8217;s turn it is</li>



<li><code>scoreX</code>: Current score for Player X</li>



<li><code>scoreO</code>: Current score for Player O</li>
</ol>
</li>
</ul>



<h3 class="wp-block-heading">GameOver Event</h3>



<pre class="wp-block-code"><code>Event GameOver(result As String, scoreX As Integer, scoreO As Integer)</code></pre>



<ul class="wp-block-list">
<li>Purpose: Signals the conclusion of the game with a winner or draw</li>



<li>Parameters:
<ol class="wp-block-list">
<li><code>result</code>: A string describing the game&#8217;s final outcome (e.g., &#8220;X Wins&#8221;, &#8220;O Wins&#8221;, &#8220;Draw&#8221;)</li>



<li><code>scoreX</code>: Final score for Player X</li>



<li><code>scoreO</code>: Final score for Player O</li>
</ol>
</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Event Handlers in Tic-Tac-Toe Game</h2>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="542" height="458" src="https://blog.xojo.com/wp-content/uploads/2024/11/image-4.png" alt="" class="wp-image-14005" style="width:222px;height:auto" srcset="https://blog.xojo.com/wp-content/uploads/2024/11/image-4.png 542w, https://blog.xojo.com/wp-content/uploads/2024/11/image-4-300x254.png 300w" sizes="auto, (max-width: 542px) 100vw, 542px" /></figure>



<h3 class="wp-block-heading">Closing Event</h3>



<pre class="wp-block-code"><code>Sub Closing() Handles Closing
  // This event ensures that the animation timer is properly disabled and its handler is removed to prevent memory leaks or unexpected behavior.
  // Clean up the animation timer when the control is closing
  If animationTimer &lt;&gt; Nil Then
    animationTimer.Enabled = False
    RemoveHandler animationTimer.Action, AddressOf AnimationStep
    animationTimer = Nil
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Ensures clean resource management</li>



<li>Disables and removes timer to prevent memory leaks</li>



<li>Called when the control is being destroyed</li>
</ul>



<h3 class="wp-block-heading">MouseDown Event</h3>



<pre class="wp-block-code"><code>Function MouseDown(x As Integer, y As Integer) Handles MouseDown as Boolean
  // This event handles mouse click actions on the game board.
  // It checks if the game is over; if not, it calculates the row and column of the click.
  // If the clicked cell is empty, it records the player's move, checks for a winner, and toggles the current player.
  
  // Handle mouse clicks on the game board
  If isGameOver Then
    Return True
  End If
  
  // Calculate the row and column based on the click position
  Var row As Integer = y \ CellHeight
  Var col As Integer = x \ CellWidth
  
  // If the clicked cell is empty, make a move
  If boardState(row, col) = 0 Then
    boardState(row, col) = currentPlayer
    StartAnimation(row, col)
    
    // Reset hover position after a move
    hoverRow = -1
    hoverCol = -1
    
    // Refresh only the affected cell
    Refresh(col * CellWidth, row * CellHeight, CellWidth, CellHeight)
    
    // Check for a winner or a draw
    Var winner As Integer = CheckWinner()
    If winner &gt; 0 Then
      UpdateScore(winner)
      GameStatus("Player " + PlayerSymbol(winner) + " wins!", scoreX, scoreO)
      isGameOver = True
      GameOver("Player " + PlayerSymbol(winner) + " wins!", scoreX, scoreO)
      
      // Refresh the entire board to show the winning line
      Refresh(True)
    ElseIf Me.IsBoardFull() Then
      GameStatus("It's a draw!", scoreX, scoreO)
      isGameOver = True
      GameOver("Draw", scoreX, scoreO)
    Else
      // Switch to the other player
      currentPlayer = If(currentPlayer = 1, 2, 1)
      GameStatus("Player " + PlayerSymbol(currentPlayer) + "'s turn", PlayerSymbol(currentPlayer), scoreX, scoreO)
    End If
  End If
  
  Return True
End Function</code></pre>



<ul class="wp-block-list">
<li>Handles player moves</li>



<li>Validates move legality</li>



<li>Checks for win/draw conditions</li>



<li>Switches players</li>
</ul>



<h3 class="wp-block-heading">MouseExit and MouseMove Events</h3>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Sub MouseExit() Handles MouseExit
  // This event is triggered when the mouse cursor exits the game board area.
  // It clears the hover effect to avoid leaving any visual artifacts on the board when the mouse is moved away.
  
  If hoverRow &gt;= 0 And hoverRow &lt; kBoardSize And hoverCol &gt;= 0 And hoverCol &lt; kBoardSize Then
    Var oldHoverRow As Integer = hoverRow
    Var oldHoverCol As Integer = hoverCol
    
    hoverRow = -1
    hoverCol = -1
    
    // Refresh only the cell that was previously hovered
    Refresh(oldHoverCol * CellWidth, oldHoverRow * CellHeight, CellWidth, CellHeight)
  End If
End Sub</code></pre>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Sub MouseMove(x As Integer, y As Integer) Handles MouseMove
  // This event handles mouse movement over the game board.
  // It updates the hover effect when the mouse moves to a new cell, providing visual feedback.
  
  If Not isGameOver Then
    Var newHoverRow As Integer = y \ CellHeight
    Var newHoverCol As Integer = x \ CellWidth
    
    If newHoverRow &lt;&gt; hoverRow Or newHoverCol &lt;&gt; hoverCol Then
      Var oldHoverRow As Integer = hoverRow
      Var oldHoverCol As Integer = hoverCol
      
      hoverRow = newHoverRow
      hoverCol = newHoverCol
      
      // Refresh the old hover cell (if it was valid)
      If oldHoverRow &gt;= 0 And oldHoverRow &lt; 3 And oldHoverCol &gt;= 0 And oldHoverCol &lt; 3 Then
        Refresh(oldHoverCol * CellWidth, oldHoverRow * CellHeight, CellWidth, CellHeight)
      End If
      
      // Refresh the new hover cell
      Refresh(hoverCol * CellWidth, hoverRow * CellHeight, CellWidth, CellHeight)
    End If
  End If
End Sub</code></pre>
</div>
</div>



<ul class="wp-block-list">
<li>Provides visual hover feedback</li>



<li>Tracks mouse movement across grid</li>



<li>Refreshes only changed cells</li>
</ul>



<h3 class="wp-block-heading">Opening Event</h3>



<pre class="wp-block-code"><code>Sub Opening() Handles Opening
  // This event initializes the board colors based on the current system theme (dark mode or light mode) and starts a new game.
  
  // Set up colors of the board lines, for the X's and O's
  If Color.IsDarkMode = True Then
    ColorBoard = Color.RGB(178, 161, 149)
    ColorX = Color.RGB(228, 182, 88)
    ColorO = Color.RGB(253, 161, 97)
  Else
    ColorBoard = Color.RGB(130, 110, 92)
    ColorX = Color.RGB(228, 182, 88)
    ColorO = Color.RGB(253, 161, 97)
  End If
  
  NewGame()
End Sub</code></pre>



<ul class="wp-block-list">
<li>Initializes color theme</li>



<li>Supports dark and light modes</li>



<li>Starts a new game automatically</li>
</ul>



<h3 class="wp-block-heading">Paint Event</h3>



<pre class="wp-block-code"><code>Sub Paint(g As Graphics, areas() As Rect) Handles Paint
  // This event is responsible for drawing the game board, hover effects, player symbols (X's and O's), and the winning line.
  // It is called whenever the game board needs to be redrawn.
  
  // Draw the board
  g.DrawingColor = ColorBoard
  g.DrawLine(Width/3, 0, Width/3, Height)
  g.DrawLine(2*Width/3, 0, 2*Width/3, Height)
  g.DrawLine(0, Height/3, Width, Height/3)
  g.DrawLine(0, 2*Height/3, Width, 2*Height/3)
  
  // Draw hover effect
  DrawHoverEffect(g)
  
  // Draw X's and O's
  g.PenSize = 8
  For row As Integer = 0 To 2
    For col As Integer = 0 To 2
      If boardState(row, col) = 1 Then
        DrawX(g, row, col)
      ElseIf boardState(row, col) = 2 Then
        DrawO(g, row, col)
      End If
    Next
  Next
  
  // Draw winning line if the game is over
  If isGameOver Then
    DrawWinningLine(g)
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Renders game board</li>



<li>Draws grid lines</li>



<li>Manages visual game state</li>



<li>Supports dynamic rendering</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Animation and Drawing Methods</h2>



<h3 class="wp-block-heading">1. AnimationStep</h3>



<pre class="wp-block-code"><code>Public Sub AnimationStep(sender As Timer)
  // This method is called by the animation timer (animationTimer property) to progress the animation of a newly placed symbol.
  // It increments the animation progress and stops the timer once the animation is complete.
  
  // Progress the animation
  animationProgress = animationProgress + 0.1
  If animationProgress &gt;= 1 Then
    animationTimer.Enabled = False
    animationProgress = 1
  End If
  
  // Refresh only the cell being animated
  Refresh(lastPlayedCol * CellWidth, lastPlayedRow * CellHeight, CellWidth, CellHeight)
  
  // If the animation is complete, stop the timer
  If animationProgress &gt;= 1 Then
    animationTimer.Enabled = False
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Manages symbol placement animation</li>



<li>Gradually scales symbol from 0 to 1</li>



<li>Updates only the recently played cell</li>
</ul>



<h3 class="wp-block-heading">2. DrawX and DrawO</h3>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Sub MouseExit() Handles MouseExit
  // This event is triggered when the mouse cursor exits the game board area.
  // It clears the hover effect to avoid leaving any visual artifacts on the board when the mouse is moved away.
  
  If hoverRow &gt;= 0 And hoverRow &lt; kBoardSize And hoverCol &gt;= 0 And hoverCol &lt; kBoardSize Then
    Var oldHoverRow As Integer = hoverRow
    Var oldHoverCol As Integer = hoverCol
    
    hoverRow = -1
    hoverCol = -1
    
    // Refresh only the cell that was previously hovered
    Refresh(oldHoverCol * CellWidth, oldHoverRow * CellHeight, CellWidth, CellHeight)
  End If
End Sub</code></pre>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Sub MouseMove(x As Integer, y As Integer) Handles MouseMove
  // This event handles mouse movement over the game board.
  // It updates the hover effect when the mouse moves to a new cell, providing visual feedback.
  
  If Not isGameOver Then
    Var newHoverRow As Integer = y \ CellHeight
    Var newHoverCol As Integer = x \ CellWidth
    
    If newHoverRow &lt;&gt; hoverRow Or newHoverCol &lt;&gt; hoverCol Then
      Var oldHoverRow As Integer = hoverRow
      Var oldHoverCol As Integer = hoverCol
      
      hoverRow = newHoverRow
      hoverCol = newHoverCol
      
      // Refresh the old hover cell (if it was valid)
      If oldHoverRow &gt;= 0 And oldHoverRow &lt; 3 And oldHoverCol &gt;= 0 And oldHoverCol &lt; 3 Then
        Refresh(oldHoverCol * CellWidth, oldHoverRow * CellHeight, CellWidth, CellHeight)
      End If
      
      // Refresh the new hover cell
      Refresh(hoverCol * CellWidth, hoverRow * CellHeight, CellWidth, CellHeight)
    End If
  End If
End Sub</code></pre>
</div>
</div>



<ul class="wp-block-list">
<li>Draws X and O symbols with animation</li>



<li>Centers symbol in cell</li>



<li>Scales symbol based on animation progress</li>
</ul>



<h3 class="wp-block-heading">3. DrawHoverEffect</h3>



<pre class="wp-block-code"><code>Public Sub DrawHoverEffect(g As Graphics)
  // This method draws a semi-transparent hover effect over the cell that the mouse is currently hovering over.
  // It only draws the effect if the game is not over and the hovered cell is empty.
  
  If Not isGameOver And hoverRow &gt;= 0 And hoverRow &lt; 3 And hoverCol &gt;= 0 And hoverCol &lt; 3 Then
    If boardState(hoverRow, hoverCol) = 0 Then
      g.DrawingColor = Color.RGB(255, 255, 255, 250) // Semi-transparent white
      g.FillRectangle(hoverCol * CellWidth, hoverRow * CellHeight, CellWidth, CellHeight)
    End If
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Provides visual feedback on hoverable cells</li>



<li>Applies semi-transparent white overlay</li>



<li>Only affects empty, unplayed cells</li>
</ul>



<h3 class="wp-block-heading">4. DrawWinningLine</h3>



<pre class="wp-block-code"><code>Public Sub DrawWinningLine(g As Graphics)
  // This method draws a semi-transparent green line over the winning combination on the board if a player has won.
  
  // Draw the winning line if there is a winner
  If winningLine.Count = 6 Then
    g.DrawingColor = Color.RGB(0, 255, 0, 128) // Semi-transparent green
    g.PenSize = 2
    
    Var startX As Integer = winningLine(1) * cellWidth + cellWidth / 2
    Var startY As Integer = winningLine(0) * cellHeight + cellHeight / 2
    Var endX As Integer = winningLine(5) * cellWidth + cellWidth / 2
    Var endY As Integer = winningLine(4) * cellHeight + cellHeight / 2
    
    g.DrawLine(startX, startY, endX, endY)
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Draws a semi-transparent green line</li>



<li>Highlights the winning combination</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Game Logic Methods</h2>



<h3 class="wp-block-heading">1. CheckWinner</h3>



<pre class="wp-block-code"><code>Public Function CheckWinner() As Integer
  // This method checks the board for a winner by evaluating rows, columns, and diagonals.
  // It returns the winning player (1 or 2) or 0 if there is no winner.
  
  
  // Check rows
  For i As Integer = 0 To kBoardSize - 1
    If boardState(i, 0) &lt;&gt; 0 And boardState(i, 0) = boardState(i, 1) And boardState(i, 1) = boardState(i, 2) Then
      winningLine = Array(i, 0, i, 1, i, 2)
      Return boardState(i, 0)
    End If
  Next
  
  // Check columns
  For j As Integer = 0 To 2
    If boardState(0, j) &lt;&gt; 0 And boardState(0, j) = boardState(1, j) And boardState(1, j) = boardState(2, j) Then
      winningLine = Array(0, j, 1, j, 2, j)
      Return boardState(0, j)
    End If
  Next
  
  // Check diagonals
  If boardState(0, 0) &lt;&gt; 0 And boardState(0, 0) = boardState(1, 1) And boardState(1, 1) = boardState(2, 2) Then
    winningLine = Array(0, 0, 1, 1, 2, 2)
    Return boardState(0, 0)
  End If
  
  If boardState(0, 2) &lt;&gt; 0 And boardState(0, 2) = boardState(1, 1) And boardState(1, 1) = boardState(2, 0) Then
    winningLine = Array(0, 2, 1, 1, 2, 0)
    Return boardState(0, 2)
  End If
  
  winningLine.ResizeTo(-1)
  Return 0 // No winner yet
End Function</code></pre>



<ul class="wp-block-list">
<li>Scans board for winning combinations</li>



<li>Returns winning player or 0</li>



<li>Stores winning line coordinates</li>
</ul>



<h3 class="wp-block-heading">2. IsBoardFull</h3>



<pre class="wp-block-code"><code>Public Function IsBoardFull() As Boolean
  // This method checks if the board is completely filled with no empty cells.
  // It returns true if the board is full, otherwise false.
  
  // Check if the board is full (no empty cells)
  For i As Integer = 0 To kBoardSize - 1
    For j As Integer = 0 To kBoardSize - 1
      If boardState(i, j) = 0 Then
        Return False
      End If
    Next
  Next
  Return True
End Function</code></pre>



<ul class="wp-block-list">
<li>Checks if all cells are occupied</li>



<li>Determines if game is a draw</li>
</ul>



<h3 class="wp-block-heading">3. NewGame</h3>



<pre class="wp-block-code"><code>Public Sub NewGame()
  // This method resets the game state to start a new game.
  // It clears the board, resets the current player to Player 1, and updates the game status.
  
  // Reset the game state for a new game
  For i As Integer = 0 To 8
    boardState(i \ 3, i Mod 3) = 0
  Next
  currentPlayer = 1
  isGameOver = False
  animationProgress = 1
  If animationTimer &lt;&gt; Nil Then
    animationTimer.Enabled = False
  End If
  GameStatus("Player " + PlayerSymbol(currentPlayer) + "'s turn", scoreX, scoreO)
  winningLine.ResizeTo(-1)
  Refresh()
End Sub</code></pre>



<ul class="wp-block-list">
<li>Resets game to initial state</li>



<li>Clears board</li>



<li>Resets player turn</li>
</ul>



<h3 class="wp-block-heading">4. UpdateScore</h3>



<pre class="wp-block-code"><code>Public Sub UpdateScore(winner As Integer)
  // This method updates the score for the winning player by incrementing the respective score counter.
  
  // Update the score for the winning player
  If winner = 1 Then
    scoreX = scoreX + 1
  ElseIf winner = 2 Then
    scoreO = scoreO + 1
  End If
End Sub</code></pre>



<ul class="wp-block-list">
<li>Increments score for winning player</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Utility Methods</h2>



<h3 class="wp-block-heading">1. PlayerSymbol</h3>



<pre class="wp-block-code"><code>Public Function PlayerSymbol(player As Integer) As String
  // This method returns the symbol ('X' or 'O') corresponding to the player number (1 or 2).
  Return If(player = 1, "X", "O")
End Function</code></pre>



<ul class="wp-block-list">
<li>Converts player number to symbol</li>
</ul>



<h3 class="wp-block-heading">2. StartAnimation</h3>



<pre class="wp-block-code"><code>Public Sub StartAnimation(row As Integer, col As Integer)
  // This method initializes and starts the animation for a newly placed symbol,
  // by setting the target cell and resetting the animation progress.
  
  // Start the animation for a newly placed symbol
  lastPlayedRow = row
  lastPlayedCol = col
  animationProgress = 0
  
  If animationTimer = Nil Then
    animationTimer = New Timer
    animationTimer.Period = 16 // equivalent of 60 FPS
    AddHandler animationTimer.Action, AddressOf AnimationStep
  End If
  
  animationTimer.Enabled = True
  animationTimer.RunMode = Timer.RunModes.Multiple
End Sub</code></pre>



<ul class="wp-block-list">
<li>Initializes symbol animation</li>



<li>Sets up timer for smooth rendering</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Usage Instructions</h2>



<p>To use the <code>TicTacToeGame</code> control in your Xojo project:</p>



<ol class="wp-block-list">
<li><strong>Drag and Drop:</strong> Drag the <code>TicTacToeGame</code> icon (it should look like a small canvas) from the Navigator (the left side of the IDE) onto your <code>Window1</code> or any other window you want to use.
<ul class="wp-block-list">
<li>A <code>TicTacToeGame</code> instance will appear on the window. You can resize and position it as needed.</li>
</ul>
</li>



<li><strong>Initialize:</strong> While not strictly required, you might want to initialize the game in the <code>Window1.Open</code> event handler. This ensures the game is ready to play as soon as the window opens. You can do this by adding the following code to the <code>Window1.Open</code> event:<br><code>// Assuming 'TicTacToeGame1' is the name of your control instance on the window</code><br><code>TicTacToeGame1.NewGame</code><br>This will call the <code>NewGame</code> method of your custom control, setting up the board and starting a new game.</li>



<li><strong>Run the Project:</strong> Run your Xojo project. You should see the TicTacToe board on your window, ready to play!</li>
</ol>



<p>I highly suggest downloading the complete TicTacToe Xojo project for the game. If you find anything unclear, refer to this tutorial for explanations. <a href="https://files.xojo.com/BlogExamples/Tic-Tac-Toe Game.xojo_binary_project">Download the Xojo project</a>.</p>



<h2 class="wp-block-heading">Next Steps:</h2>



<p>Congratulations! You&#8217;ve successfully built a fully functional, modern tic-tac-toe game in Xojo. This project is a great foundation for exploring more advanced game development concepts, animations and how to make custom UI elements based on Xojo&#8217;s powerful <a href="https://documentation.xojo.com/api/user_interface/desktop/desktopcanvas.html#desktopcanvas" data-type="link" data-id="https://documentation.xojo.com/api/user_interface/desktop/desktopcanvas.html#desktopcanvas" target="_blank" rel="noreferrer noopener">DesktopCanvas</a> control.</p>



<p>Now that you understand the basics, here are some ideas to take your TicTacToe game to the next level:</p>



<ul class="wp-block-list">
<li><strong>Artificial Intelligence (AI):</strong> Implement a simple AI opponent so players can play against the computer. You could start with a random move generator and then explore more sophisticated algorithms like Minimax. Xojo already provides fully working AI integration examples.</li>



<li><strong>Different Game Modes:</strong> Add options for different board sizes (e.g., 4&#215;4, 5&#215;5) or variations of tic-tac-toe.</li>



<li><strong>Online Multiplayer:</strong> Enable players to challenge each other online using Xojo&#8217;s networking capabilities.</li>



<li><strong>Enhanced UI/UX:</strong> Improve the user interface with custom graphics, sound effects, and a more polished look and feel. Consider adding a timer.</li>



<li><strong>Go Multiplatform</strong>: Port the TicTacToeGame class to Mobile and Web projects.</li>
</ul>



<p>We encourage you to experiment, get creative, and explore these possibilities. Share your creations and connect with other Xojo developers in <a target="_blank" rel="noreferrer noopener" href="https://forum.xojo.com/">the forums</a> to learn and grow together. Happy coding!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Beyond Static UI: Create Dynamic Loading Animations with Xojo Graphics</title>
		<link>https://blog.xojo.com/2024/11/05/beyond-static-ui-create-dynamic-loading-animations-with-xojo-graphics/</link>
		
		<dc:creator><![CDATA[Gabriel Ludosanu]]></dc:creator>
		<pubDate>Tue, 05 Nov 2024 15:10:24 +0000</pubDate>
				<category><![CDATA[Desktop]]></category>
		<category><![CDATA[General]]></category>
		<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[Animation]]></category>
		<category><![CDATA[Custom Controls]]></category>
		<category><![CDATA[DesktopCanvas]]></category>
		<category><![CDATA[Graphics]]></category>
		<category><![CDATA[Phase-Animation]]></category>
		<category><![CDATA[UI-Design]]></category>
		<category><![CDATA[Visual Feedback]]></category>
		<category><![CDATA[Xojo-Graphics]]></category>
		<guid isPermaLink="false">https://blog.xojo.com/?p=13975</guid>

					<description><![CDATA[Ever wondered how to create those sleek, professional-looking loading animations you see in modern apps? In this blog post, we&#8217;re going to unlock the power&#8230;]]></description>
										<content:encoded><![CDATA[
<p>Ever wondered how to create those sleek, professional-looking loading animations you see in modern apps?</p>



<p>In this blog post, we&#8217;re going to unlock the power of Xojo&#8217;s DesktopCanvas and its Graphics capabilities to recreate one of the popular <a href="https://tobiasahlin.com/spinkit/">SpinKit loading animations originally created by Tobias Ahlin</a>. We&#8217;ll be implementing the &#8220;Three Bounce&#8221; animation, transforming this beloved CSS animation into native Xojo code!</p>



<p>Not only will you learn how to create this specific animation, but you&#8217;ll also gain valuable insights into animation principles in Xojo that you can use to create your own custom animations. By the end of this tutorial, you&#8217;ll understand how to:</p>



<ul class="wp-block-list">
<li>Harness the power of DesktopCanvas for custom graphics</li>



<li>Create smooth animations using Timers</li>



<li>Implement phase-based animations</li>



<li>Use Graphics methods to draw dynamic shapes</li>



<li>Manage animation lifecycles properly</li>
</ul>



<h3 class="wp-block-heading">Why This Matters</h3>



<p>Loading animations are more than just eye candy – they&#8217;re essential UI elements that keep users engaged while your app processes data. Instead of using static images or third-party libraries, creating your own animations gives you complete control over the look and feel of your application while keeping your dependencies minimal.</p>



<h3 class="wp-block-heading">What We&#8217;re Building</h3>



<p>We&#8217;ll create a smooth, professional-looking three-dot loading animation where dots gracefully scale up and down in sequence. The result is a lightweight, customizable loading indicator that you can drop into any Xojo project. Here&#8217;s what makes this implementation special:</p>



<ul class="wp-block-list">
<li>Pure Xojo code &#8211; no external dependencies</li>



<li>Smooth, fluid animation</li>



<li>Easily customizable colors and timing</li>



<li>Efficient resource usage</li>



<li>Clean, object-oriented design</li>
</ul>



<figure class="wp-block-video"><video height="184" style="aspect-ratio: 360 / 184;" width="360" controls loop preload="auto" src="https://blog.xojo.com/wp-content/uploads/2024/10/spinkit_animation.mp4" playsinline></video></figure>



<p>Ok, let&#8217;s start building our awesome animation class.</p>



<h2 class="wp-block-heading">Step 1: Setting Up the Base Class</h2>



<p>First, create a new class (Insert &gt; Class) that inherits from DesktopCanvas:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" src="https://storage.googleapis.com/co-writer/images/HRIwK4xjWLXvNRyAbzXbq5t8wJF3/-1730379923862.webp" alt="IMAGE"/></figure>
</div>


<pre class="wp-block-code"><code>Protected Class SpinKitClass Inherits DesktopCanvas</code></pre>



<h2 class="wp-block-heading">Step 2: Defining Core Properties</h2>



<p>Add these essential properties to control the animation:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" src="https://storage.googleapis.com/co-writer/images/HRIwK4xjWLXvNRyAbzXbq5t8wJF3/-1730380034310.webp" alt="IMAGE"/></figure>
</div>


<pre class="wp-block-code"><code>Private animationPhases() As Double      // Stores phase offsets for each dot
Private animationSpeed As Integer = 60   // Animation refresh rate in milliseconds
Private animationTimer As Timer         // Timer to drive the animation
Private currentPhase As Double = 0.0    // Current animation phase
Private dotSize As Integer = 20         // Size of each dot
Private dotSpacing As Integer = 20      // Space between dots</code></pre>



<h2 class="wp-block-heading">Step 3: Setting Up Constants</h2>



<p>Define the constants that control the animation behavior:</p>


<div class="wp-block-image">
<figure class="aligncenter"><img decoding="async" src="https://storage.googleapis.com/co-writer/images/HRIwK4xjWLXvNRyAbzXbq5t8wJF3/-1730380079168.webp" alt="IMAGE"/></figure>
</div>


<pre class="wp-block-code"><code>Private Const kDefaultColor As Color = &amp;c333333    // Dot color
Private Const kPhaseIncrement As Double = 0.05    // Animation speed</code></pre>



<h2 class="wp-block-heading">Step 4: Implementing Animation Control Methods</h2>



<p>Add methods to start and stop the animation:</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-9d6595d7 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Public Sub StartAnimation()
  /// Initializes and starts the animation
  /// Sets up initial phase offsets for the dots
  /// Creates and configures the animation timer
  
  If animationTimer = Nil Then
    animationPhases = Array(0.0, 0.16, 0.32)
    
    animationTimer = New Timer
    AddHandler animationTimer.Action, AddressOf UpdateAnimation
    animationTimer.Period = animationSpeed
    animationTimer.RunMode = Timer.RunModes.Multiple
  End If
End Sub</code></pre>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<pre class="wp-block-code"><code>Public Sub StopAnimation()
  /// Stops the running animation
  /// Removes the timer handler and cleans up
  /// Refreshes the canvas to clear the animation
  
  If animationTimer &lt;&gt; Nil Then
    RemoveHandler animationTimer.Action, AddressOf UpdateAnimation
    animationTimer = Nil
    Refresh
  End If
End Sub</code></pre>
</div>
</div>



<h2 class="wp-block-heading">Step 5: Creating the Animation Update Logic</h2>



<p>Implement the timer callback that drives the animation:</p>



<pre class="wp-block-code"><code>Private Sub updateAnimation(sender As Timer)
  /// Timer callback that updates the animation state
  /// Increments the phase and triggers a redraw
  /// @param sender The Timer that triggered this callback
  
  #Pragma Unused sender
  
  // Increment the current phase (spin08)
  currentPhase = currentPhase + kPhaseIncrement
  // Reset currentPhase if it exceeds 1.0
  If currentPhase &gt; 1.0 Then currentPhase = 0
  
  // Invalidate the canvas to trigger a repaint
  Refresh()
End Sub</code></pre>



<h2 class="wp-block-heading">Step 6: Implementing the Drawing Logic</h2>



<p>Add the core animation rendering code:</p>



<pre class="wp-block-code"><code>Private Sub animation08(g As Graphics)
  /// Renders a single frame of the three-dot loading animation
  /// Draws 3 dots that scale up and down in sequence
  /// @param g The graphics context to draw into
  
  Var centerX As Integer = Me.Width / 2
  Var centerY As Integer = Me.Height / 2
  
  For i As Integer = 0 To 2
    Var phase As Double = currentPhase + animationPhases(i)
    
    // Ensure phase is within 0 to 1
    If phase &gt; 1.0 Then phase = phase - 1.0
    
    Var scale As Double
    If phase &lt; 0.4 Then
      scale = phase / 0.4
    Else
      scale = (1.0 - phase) / 0.6
    End If
    
    Var size As Integer = dotSize * scale
    Var x As Integer = centerX + (i - 1) * dotSpacing - size / 2
    Var y As Integer = centerY - size / 2
    
    g.DrawingColor = kDefaultColor
    g.FillOval(x, y, size, size)
  Next
End Sub</code></pre>



<h2 class="wp-block-heading">Step 7: Handling the Paint Event</h2>



<p>Implement the Paint event to trigger the animation rendering:</p>



<pre class="wp-block-code"><code>Sub Paint(g As Graphics, areas() As Rect) Handles Paint
  /// Paint event handler that renders the animation
  /// Called automatically when the canvas needs to be redrawn
  /// If animation is running, calls animation08, otherwise clears the canvas
  
  If animationTimer &lt;&gt; Nil Then
    animation08(g)
  Else
    g.ClearRectangle(0, 0, Width, Height)
  End If
End Sub
</code></pre>



<h2 class="wp-block-heading">How It Works</h2>



<ol class="wp-block-list">
<li>The animation uses a phase-based system where each dot is offset in its animation cycle.</li>



<li>The dots scale up and down based on their current phase.</li>



<li>A timer drives the animation by incrementing the phase and triggering redraws.</li>



<li>The dots are positioned horizontally with equal spacing around the center.</li>



<li>Each dot&#8217;s size is calculated based on its current phase in the animation.</li>
</ol>



<h2 class="wp-block-heading">Using the Animation</h2>



<p>To use this animation in your project, all you have to do is simply drag and drop the class on a DesktopWindow and then start or stop the animation when needed.</p>



<pre class="wp-block-code"><code>// Start the animation
SpinKit1.StartAnimation()

// Stop the animation when done
SpinKit1.StopAnimation()</code></pre>



<h2 class="wp-block-heading">Customization</h2>



<p>You can customize the animation by adjusting:</p>



<ul class="wp-block-list">
<li><code>dotSize</code> for larger or smaller dots</li>



<li><code>dotSpacing</code> to change the spread of the dots</li>



<li><code>animationSpeed</code> to make it faster or slower</li>



<li><code>kDefaultColor</code> to change the dot color</li>



<li><code>kPhaseIncrement</code> to adjust the animation speed</li>
</ul>



<h2 class="wp-block-heading">Taking It Further</h2>



<p>The &#8220;Three Bounce&#8221; animation we&#8217;ve created is just one of many amazing animations in the <a href="https://tobiasahlin.com/spinkit/">SpinKit collection</a>. Now that you understand the fundamentals, why not try recreating other SpinKit animations? Here are some exciting challenges to tackle:</p>



<ul class="wp-block-list">
<li>Modify the current animation to use different shapes (squares, rectangles).</li>



<li>Experiment with different timing functions for varied animation effects.</li>



<li>Try implementing the &#8220;Rotating Plane&#8221; or &#8220;Chasing Dots&#8221; animations from SpinKit.</li>



<li>Create your own unique variations by combining what you&#8217;ve learned.</li>



<li>Optimize the class further.</li>
</ul>



<h2 class="wp-block-heading">Share Your Creations!</h2>



<p>Have you created an awesome variation or implemented another SpinKit animation in Xojo? Share it with the community! The <a target="_blank" rel="noreferrer noopener" href="https://forum.xojo.com/">Xojo Forums</a> and social media are great places to showcase your work and inspire others.</p>



<h2 class="wp-block-heading">Resources for Further Exploration</h2>



<ul class="wp-block-list">
<li>Original SpinKit animations by Tobias Ahlin: <a href="https://tobiasahlin.com/spinkit/" target="_blank" rel="noreferrer noopener">https://tobiasahlin.com/spinkit/</a></li>



<li>Xojo Graphics documentation: <a href="https://documentation.xojo.com/api/graphics/graphics.html" target="_blank" rel="noreferrer noopener">https://documentation.xojo.com/api/graphics/graphics.html</a></li>



<li>Xojo DesktopCanvas documentation: <a href="https://documentation.xojo.com/api/user_interface/desktop/desktopcanvas.html" target="_blank" rel="noreferrer noopener">https://documentation.xojo.com/api/user_interface/desktop/desktopcanvas.html</a></li>
</ul>



<p><strong>Remember</strong>: Every great application deserves great animations and now you have the tools to create them! Keep experimenting, keep creating, and most importantly, keep animating!</p>



<p><em>Gabriel is a digital marketing enthusiast who loves coding with Xojo to create cool software tools for any platform. He is always eager to learn and share new ideas!</em></p>



<ul class="wp-block-social-links has-normal-icon-size is-content-justification-center is-layout-flex wp-container-core-social-links-is-layout-16018d1d wp-block-social-links-is-layout-flex"><li class="wp-social-link wp-social-link-facebook  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.facebook.com/goxojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"></path></svg><span class="wp-block-social-link-label screen-reader-text">Facebook</span></a></li>

<li class="wp-social-link wp-social-link-x  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://x.com/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M13.982 10.622 20.54 3h-1.554l-5.693 6.618L8.745 3H3.5l6.876 10.007L3.5 21h1.554l6.012-6.989L15.868 21h5.245l-7.131-10.378Zm-2.128 2.474-.697-.997-5.543-7.93H8l4.474 6.4.697.996 5.815 8.318h-2.387l-4.745-6.787Z" /></svg><span class="wp-block-social-link-label screen-reader-text">X</span></a></li>

<li class="wp-social-link wp-social-link-linkedin  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.linkedin.com/company/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z"></path></svg><span class="wp-block-social-link-label screen-reader-text">LinkedIn</span></a></li>

<li class="wp-social-link wp-social-link-github  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://github.com/topics/xojo" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M12,2C6.477,2,2,6.477,2,12c0,4.419,2.865,8.166,6.839,9.489c0.5,0.09,0.682-0.218,0.682-0.484 c0-0.236-0.009-0.866-0.014-1.699c-2.782,0.602-3.369-1.34-3.369-1.34c-0.455-1.157-1.11-1.465-1.11-1.465 c-0.909-0.62,0.069-0.608,0.069-0.608c1.004,0.071,1.532,1.03,1.532,1.03c0.891,1.529,2.341,1.089,2.91,0.833 c0.091-0.647,0.349-1.086,0.635-1.337c-2.22-0.251-4.555-1.111-4.555-4.943c0-1.091,0.39-1.984,1.03-2.682 C6.546,8.54,6.202,7.524,6.746,6.148c0,0,0.84-0.269,2.75,1.025C10.295,6.95,11.15,6.84,12,6.836 c0.85,0.004,1.705,0.114,2.504,0.336c1.909-1.294,2.748-1.025,2.748-1.025c0.546,1.376,0.202,2.394,0.1,2.646 c0.64,0.699,1.026,1.591,1.026,2.682c0,3.841-2.337,4.687-4.565,4.935c0.359,0.307,0.679,0.917,0.679,1.852 c0,1.335-0.012,2.415-0.012,2.741c0,0.269,0.18,0.579,0.688,0.481C19.138,20.161,22,16.416,22,12C22,6.477,17.523,2,12,2z"></path></svg><span class="wp-block-social-link-label screen-reader-text">GitHub</span></a></li>

<li class="wp-social-link wp-social-link-youtube  wp-block-social-link"><a rel="noopener nofollow" target="_blank" href="https://www.youtube.com/c/XojoInc" class="wp-block-social-link-anchor"><svg width="24" height="24" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><path d="M21.8,8.001c0,0-0.195-1.378-0.795-1.985c-0.76-0.797-1.613-0.801-2.004-0.847c-2.799-0.202-6.997-0.202-6.997-0.202 h-0.009c0,0-4.198,0-6.997,0.202C4.608,5.216,3.756,5.22,2.995,6.016C2.395,6.623,2.2,8.001,2.2,8.001S2,9.62,2,11.238v1.517 c0,1.618,0.2,3.237,0.2,3.237s0.195,1.378,0.795,1.985c0.761,0.797,1.76,0.771,2.205,0.855c1.6,0.153,6.8,0.201,6.8,0.201 s4.203-0.006,7.001-0.209c0.391-0.047,1.243-0.051,2.004-0.847c0.6-0.607,0.795-1.985,0.795-1.985s0.2-1.618,0.2-3.237v-1.517 C22,9.62,21.8,8.001,21.8,8.001z M9.935,14.594l-0.001-5.62l5.404,2.82L9.935,14.594z"></path></svg><span class="wp-block-social-link-label screen-reader-text">YouTube</span></a></li></ul>
]]></content:encoded>
					
		
		<enclosure url="https://blog.xojo.com/wp-content/uploads/2024/10/spinkit_animation.mp4" length="308355" type="video/mp4" />

			</item>
	</channel>
</rss>
