Sprite

Draw textured quads with Sprite2D.

▶ Run in browser

Tags: 2d

A Sprite2D draws one texture as a quad centred on its position. Its texture takes a file path, encoded PNG bytes, or an RGBA uint8 NumPy array of shape (height, width, 4); this example builds three arrays with NumPy, so it needs no image files.

  • width and height give the quad’s size in pixels before scale. Leave them unset and the quad takes the texture’s native size.

  • colour multiplies every texel, so it tints the image and its alpha fades the whole sprite.

  • position, rotation and scale are the usual Node2D transform, and a child inherits them: the caption under the star is the star’s child, so it turns with it.

On screen: a checkerboard at 128 pixels; a green-tinted gradient that bobs up and down; a star whose alpha falls off towards its tips, rotating; and the same checkerboard with width 64 and scale 0.5, so it draws at 32 pixels, tinted yellow and slightly transparent. The sprites are placed as fractions of the window, so they follow a resize.

Source

 1# /// simvx
 2# web = { width = 900, height = 600 }
 3# ///
 4"""Sprite: Draw textured quads with Sprite2D.
 5
 6A `Sprite2D` draws one texture as a quad centred on its position. Its `texture`
 7takes a file path, encoded PNG bytes, or an RGBA `uint8` NumPy array of shape
 8`(height, width, 4)`; this example builds three arrays with NumPy, so it needs
 9no image files.
10
11- `width` and `height` give the quad's size in pixels before `scale`. Leave
12  them unset and the quad takes the texture's native size.
13- `colour` multiplies every texel, so it tints the image and its alpha fades
14  the whole sprite.
15- `position`, `rotation` and `scale` are the usual `Node2D` transform, and a
16  child inherits them: the caption under the star is the star's child, so it
17  turns with it.
18
19On screen: a checkerboard at 128 pixels; a green-tinted gradient that bobs up
20and down; a star whose alpha falls off towards its tips, rotating; and the
21same checkerboard with width 64 and `scale` 0.5, so it draws at 32 pixels,
22tinted yellow and slightly transparent. The sprites are placed as fractions
23of the window, so they follow a resize.
24"""
25
26import math
27
28import numpy as np
29
30from simvx.core import Node2D, Sprite2D, Text2D
31from simvx.graphics import App
32
33SIZE = 64
34
35
36def checkerboard(cell: int = 8) -> np.ndarray:
37    ys, xs = np.mgrid[:SIZE, :SIZE]
38    even = ((xs // cell + ys // cell) % 2 == 0)[..., None]
39    return np.where(even, (200, 60, 60, 255), (60, 60, 200, 255)).astype(np.uint8)
40
41
42def gradient() -> np.ndarray:
43    t = np.linspace(0.0, 1.0, SIZE)
44    img = np.empty((SIZE, SIZE, 4), dtype=np.uint8)
45    img[..., 0] = 255 * t
46    img[..., 1] = 255 * (1 - t)
47    img[..., 2:] = (80, 255)
48    return img
49
50
51def star(points: int = 5) -> np.ndarray:
52    ys, xs = np.mgrid[:SIZE, :SIZE] - SIZE // 2
53    dist = np.hypot(xs, ys)
54    radius = SIZE * 0.4 * (0.5 + 0.5 * np.abs(np.cos(points / 2 * np.arctan2(ys, xs))))
55    img = np.empty((SIZE, SIZE, 4), dtype=np.uint8)
56    img[..., :3] = (255, 220, 50)
57    img[..., 3] = np.where(dist < radius, 255 * (1 - dist / radius), 0)
58    return img
59
60
61class SpriteScene(Node2D):
62    def on_ready(self):
63        self.time = 0.0
64        checker = checkerboard()
65        self.checker = self.add_child(Sprite2D(texture=checker, width=128, height=128))
66        self.gradient = self.add_child(Sprite2D(texture=gradient(), width=128, height=128, colour=(0.8, 1.0, 0.8, 1.0)))
67        self.star = self.add_child(Sprite2D(texture=star(), width=192, height=192))
68        self.star.add_child(Text2D(text="turning with the star", position=(-80, 110)))
69        self.small = self.add_child(
70            Sprite2D(texture=checker, width=64, height=64, scale=(0.5, 0.5), colour=(1.0, 1.0, 0.5, 0.8))
71        )
72        self.add_child(Text2D(text="Sprite2D", position=(10, 10), font_scale=1.5))
73        self.add_child(
74            Text2D(text="Checker | Gradient (tinted) | Star (rotating) | Checker (scaled, tinted)", position=(10, 40))
75        )
76
77    def on_update(self, dt: float):
78        self.time += dt
79        w, h = self.viewport_size
80        self.checker.position = (w * 0.22, h / 3)
81        self.gradient.position = (w * 0.56, h / 3 + 30 * math.sin(self.time * 2))
82        self.star.position = (w * 0.39, h * 2 / 3)
83        self.star.rotation = self.time * 0.5
84        self.small.position = (w * 0.78, h * 2 / 3)
85
86
87if __name__ == "__main__":
88    App(width=900, height=600, title="Sprite2D").run(SpriteScene())