Easing Example 1

Screen shot of Easing Example 1
easing_example_1.py
  1"""
  2Easing Example 1
  3
  4Demonstrate the different easing functions available in :py:mod:`arcade.anim`.
  5Each ball uses a different easing curve to travel from left to right, making it
  6easy to compare the visual character of each curve.
  7
  8If Python and Arcade are installed, this example can be run from the command line with:
  9python -m arcade.examples.easing_example_1
 10"""
 11
 12import arcade
 13from arcade.anim import ease, Easing
 14
 15# --- Constants ---
 16WINDOW_WIDTH = 1280
 17WINDOW_HEIGHT = 720
 18WINDOW_TITLE = "Easing Example 1"
 19
 20X_START = 40
 21X_END = 1200
 22Y_INTERVAL = 60
 23BALL_RADIUS = 13
 24LINE_WIDTH = 1.0
 25TRAVEL_TIME = 3.0
 26
 27BACKGROUND_COLOR = arcade.types.Color.from_hex_string("#F5D167")
 28TEXT_COLOR = arcade.types.Color.from_hex_string("#4B1DF2")
 29BALL_COLOR = arcade.types.Color.from_hex_string("#42B5EB")
 30LINE_COLOR = arcade.types.Color.from_hex_string("#45E6D0")
 31
 32# Each entry is (label, easing function).
 33EASING_LIST = [
 34    ("LINEAR", Easing.LINEAR),
 35    ("QUAD_OUT", Easing.QUAD_OUT),
 36    ("QUAD_IN", Easing.QUAD_IN),
 37    ("SINE", Easing.SINE),
 38    ("QUAD", Easing.QUAD),
 39    ("ELASTIC_OUT", Easing.ELASTIC_OUT),
 40    ("BACK_IN", Easing.BACK_IN),
 41    ("BACK_OUT", Easing.BACK_OUT),
 42    ("SINE_IN", Easing.SINE_IN),
 43    ("SINE_OUT", Easing.SINE_OUT),
 44    ("BOUNCE_OUT", Easing.BOUNCE_OUT),
 45]
 46
 47
 48class EasingCircle(arcade.SpriteCircle):
 49    """A ball that eases along the x-axis using a specific curve."""
 50
 51    def __init__(self, radius: int, color: arcade.types.RGBOrA255,
 52                 ease_function: Easing):
 53        super().__init__(radius, color)
 54        self.ease_function = ease_function
 55        self.start_time = 0.0
 56
 57
 58class GameView(arcade.View):
 59    """Main view showing all easing balls."""
 60
 61    def __init__(self):
 62        super().__init__()
 63        self.background_color = BACKGROUND_COLOR
 64        self.ball_list: arcade.SpriteList[EasingCircle] | None = None
 65        self.time_elapsed = 0.0
 66
 67    def setup(self):
 68        """Create one ball per easing function."""
 69        self.ball_list = arcade.SpriteList()
 70        self.time_elapsed = 0.0
 71
 72        for index, (label, ease_func) in enumerate(EASING_LIST):
 73            ball = EasingCircle(BALL_RADIUS, BALL_COLOR, ease_func)
 74            ball_y = WINDOW_HEIGHT - (index + 1) * Y_INTERVAL
 75            ball.center_x = X_START
 76            ball.center_y = ball_y
 77            ball.start_time = 0.0
 78            self.ball_list.append(ball)
 79
 80    def on_draw(self):
 81        """Render the scene."""
 82        self.clear()
 83
 84        for index, (label, _ease_func) in enumerate(EASING_LIST):
 85            ball_y = WINDOW_HEIGHT - (index + 1) * Y_INTERVAL
 86
 87            # Horizontal guide line
 88            arcade.draw_line(X_START, ball_y, X_END, ball_y, LINE_COLOR, LINE_WIDTH)
 89
 90            # Label for this easing function
 91            arcade.draw_text(
 92                label,
 93                X_END + 10,
 94                ball_y,
 95                color=TEXT_COLOR,
 96                font_size=10,
 97                anchor_y="center",
 98            )
 99
100        # Draw all balls
101        self.ball_list.draw()
102
103        # Instructions
104        arcade.draw_text(
105            "Click to restart",
106            WINDOW_WIDTH // 2,
107            20,
108            color=TEXT_COLOR,
109            font_size=14,
110            anchor_x="center",
111            anchor_y="center",
112        )
113
114    def on_update(self, delta_time: float):
115        """Update ball positions using the easing functions."""
116        self.time_elapsed += delta_time
117
118        for ball in self.ball_list:
119            eased_x = ease(
120                X_START, X_END,
121                ball.start_time, ball.start_time + TRAVEL_TIME,
122                self.time_elapsed,
123                func=ball.ease_function,
124            )
125            ball.center_x = eased_x
126
127    def on_mouse_press(self, x: int, y: int, button: int, modifiers: int):
128        """Restart the animation on click."""
129        for ball in self.ball_list:
130            ball.start_time = self.time_elapsed
131
132
133def main():
134    """Main function."""
135    window = arcade.Window(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE)
136    game = GameView()
137    game.setup()
138    window.show_view(game)
139    arcade.run()
140
141
142if __name__ == "__main__":
143    main()