Building Curved Arrows: A Slay the Spire UI Implementation
Tue, Sep 05, 2023
logo

Creating Smooth Card-targeting Animations with Bezier Curves

In card games, players frequently need to select targets for their abilities and attacks. Creating an intuitive and visually appealing way to show this targeting process is a crucial aspect of game UI design. Over time, dynamic arrow indicators have emerged as a widely adopted solution.

From Slay the Spire to Monster Train, we often see this pattern: when a player drags a card that requires a target, a smooth arrow follows the mouse movement, elegantly pointing towards potential targets. This design choice not only makes the game mechanics more intuitive but also adds a satisfying visual element to the interaction. This seemingly simple interaction design significantly enhances the overall user experience.




In this article, we'll explore how to implement this dynamic arrow effect using Bezier curves.

Bezier Curves

A Bézier curve is a parametric curve used in computer graphics and related fields. A set of discrete "control points" defines a smooth, continuous curve by means of a formula.

Bezier curves are fundamental tools in computer graphics, widely used for creating smooth curves in everything from font design to animation. While there are several types of Bezier curves, the quadratic (defined by three points) and cubic (defined by four points) variations are the most commonly used in practical applications.

For our arrow UI implementation, we'll be using cubic Bezier curves. A cubic Bezier curve is defined by four points: a start point (P0), an end point (P3), and two control points (P1 and P2) that determine the curve's shape. By adjusting these control points, we can create a wide variety of smooth curves that are perfect for our dynamic arrow visualization.

If you're interested in the mathematical details behind Bezier curves, you can find a comprehensive explanation in the Wikipedia article. However, for our implementation, we'll focus more on the practical aspects of using these curves to create engaging UI elements.


Cubic Bezier Curve

The cubic Bezier curve is mathematically defined by the following formula:

B(t) = (1-t)^3\cdot P_0 + 3(1-t)^2\cdot t \cdot P_1 + 3(1-t)\cdot t^2 \cdot P_2 + t^3\cdot P_3

where:

  • P_0 is the start point
  • P_3 is the end point
  • P_1 and P_2 are the control points
  • t is the parameter that ranges from 0 to 1


As t increases from 0 to 1, the curve traces a path from P_0 to P_3. The behavior of this path is quite intuitive:

  • When t = 0, the curve starts at P_0
  • When t = 1, the curve ends at P_3
  • For values in between, the curve creates a smooth path influenced by the control points P_1 and P_2

An interesting characteristic of cubic Bezier curves is that they typically don't pass through their control points (P_1 and P_2). Instead, these points act like magnets pulling the curve in their direction. This gives us precise control over the curve's shape:

  • P_1 influences the direction and "strength" of the curve as it leaves P_0
  • P_2 influences how the curve approaches P_3


This property makes cubic Bezier curves perfect for our arrow UI, as we can easily adjust the curve's shape by moving these control points while maintaining smooth and natural-looking results.

Implementation



In our implementation, the cubic Bezier curve creates a smooth arrow that responds to user input. Let's break down how the control points are determined:

  • P_0 The fixed starting point where the arrow originates (the emitter point)
  • P_3 The dynamic endpoint that follows the mouse cursor position
  • P_1 and P_2 control points that are dynamically calculated based on P_0 and P_3

To calculate the positions of P₁ and P₂, we use the vector from P_0 to P_3, then multiply this vector by different scaling factors to determine our control points:

\begin{align} \vec{V}&=(P_3-P_0) \\\\ P_1&=P_0+(x_1,\ y_1) \cdot \vec{V} \\\\ P_2&=P_0+(x_2,\ y_2) \cdot \vec{V} \\\\ \end{align}

By adjusting these scaling factors (k_1 and k_2), we can control how "curved" our arrow appears. Smaller values will create a tighter curve, while larger values will result in a more elongated curve. Through experimentation, I found that values of k_1 = 0.3 and k_2 = 0.6 create a visually pleasing curve that mimics Slay the Spire's arrow behavior.



Conclusion

In this article, we've explored how to recreate one of the most elegant UI elements in card games - the dynamic targeting arrow. By leveraging the power of cubic Bezier curves, we've implemented a smooth, responsive arrow system similar to what you might find in Slay the Spire and Monster Train.

The key takeaways from this implementation are:

  • Cubic Bezier curves provide an excellent foundation for creating smooth, natural-looking curves
  • Strategic placement of control points can create visually appealing animations
  • Simple vector mathematics can drive complex-looking UI behaviors

While our implementation focuses on a targeting arrow, the principles we've discussed can be applied to many other UI elements that require smooth curves or paths. Whether you're developing a card game, a strategy game, or any interactive application, understanding how to work with Bezier curves opens up numerous possibilities for creating engaging user interfaces.

Feel free to experiment with the control point calculations and scaling factors to achieve different curve styles that best suit your specific needs. The beauty of this approach lies in its flexibility and simplicity.

Happy coding! 🎮✨

Video version of this blog: