Skip to content

Commit e9bc302

Browse files
authored
Add repeating background example with scrolling texture (#144)
* Add repeating background example with scrolling texture * Add thumbnail image
1 parent 9491c35 commit e9bc302

File tree

12 files changed

+364
-0
lines changed

12 files changed

+364
-0
lines changed
5.24 KB
Loading
2.99 KB
Loading
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
font: "/builtins/fonts/vera_mo_bd.ttf"
2+
material: "/builtins/fonts/font-df.material"
3+
size: 50
4+
outline_alpha: 1.0
5+
outline_width: 5.0
6+
shadow_alpha: 1.0
7+
shadow_y: -4.0
8+
output_format: TYPE_DISTANCE_FIELD
9+
render_mode: MODE_MULTI_LAYER
10+
characters: " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
images {
2+
image: "/assets/coin_06.png"
3+
}
4+
extrude_borders: 2
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
tags: material
3+
title: Repeating Background
4+
brief: Create a scrolling background using a repeating texture on a model quad.
5+
author: Artsiom Trubchyk
6+
scripts: repeating_background.script, repeating_background.vp, repeating_background.fp
7+
thumbnail: thumbnail.png
8+
---
9+
10+
A repeating, scrolling texture can add visual interest to a static background. This example demonstrates how to create an infinitely tiling background using a model quad with a repeating texture. The effect is achieved by scrolling the UV coordinates over time, creating smooth, continuous motion.
11+
12+
The script driving the effect works as follows:
13+
14+
* Each frame it reads the current window size and scales the `background` game object so the quad covers the full viewport. The rotation is set via `euler.z` (Rotation Z in the IDE).
15+
* It converts the window size into a UV repeat scale (`uv_params.x/y`) so the texture tiles across the screen.
16+
* It advances a scrolling offset based on `scroll_speed` and `tile_size`, wraps it to the 0..1 range, and sends `uv_params` to the model material.
17+
18+
The asset used in this example is from Kenney's [Puzzle Pack 2](https://www.kenney.nl/assets/puzzle-pack-2), licensed under CC0.
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
name: "repeating_background"
2+
scale_along_z: 0
3+
embedded_instances {
4+
id: "background"
5+
data: "components {\n"
6+
" id: \"repeating_background\"\n"
7+
" component: \"/example/repeating_background.script\"\n"
8+
"}\n"
9+
"embedded_components {\n"
10+
" id: \"model\"\n"
11+
" type: \"model\"\n"
12+
" data: \"mesh: \\\"/builtins/assets/meshes/quad.dae\\\"\\n"
13+
"name: \\\"{{NAME}}\\\"\\n"
14+
"materials {\\n"
15+
" name: \\\"default\\\"\\n"
16+
" material: \\\"/example/repeating_background.material\\\"\\n"
17+
" textures {\\n"
18+
" sampler: \\\"texture0\\\"\\n"
19+
" texture: \\\"/assets/bg_icon.png\\\"\\n"
20+
" }\\n"
21+
"}\\n"
22+
"\"\n"
23+
"}\n"
24+
""
25+
rotation {
26+
z: 0.13052619
27+
w: 0.9914449
28+
}
29+
scale3 {
30+
x: 512.0
31+
y: 512.0
32+
}
33+
}
34+
embedded_instances {
35+
id: "camera"
36+
data: "embedded_components {\n"
37+
" id: \"camera\"\n"
38+
" type: \"camera\"\n"
39+
" data: \"aspect_ratio: 1.0\\n"
40+
"fov: 0.7854\\n"
41+
"near_z: -1.0\\n"
42+
"far_z: 1.0\\n"
43+
"orthographic_projection: 1\\n"
44+
"\"\n"
45+
"}\n"
46+
""
47+
}
48+
embedded_instances {
49+
id: "ui"
50+
data: "embedded_components {\n"
51+
" id: \"label1\"\n"
52+
" type: \"label\"\n"
53+
" data: \"size {\\n"
54+
" x: 512.0\\n"
55+
" y: 60.0\\n"
56+
"}\\n"
57+
"text: \\\"YOU EARNED\\\"\\n"
58+
"font: \\\"/assets/custom.font\\\"\\n"
59+
"material: \\\"/builtins/fonts/label-df.material\\\"\\n"
60+
"\"\n"
61+
" position {\n"
62+
" y: 187.0\n"
63+
" z: 0.1\n"
64+
" }\n"
65+
" scale {\n"
66+
" x: 0.75\n"
67+
" y: 0.75\n"
68+
" }\n"
69+
"}\n"
70+
"embedded_components {\n"
71+
" id: \"label2\"\n"
72+
" type: \"label\"\n"
73+
" data: \"size {\\n"
74+
" x: 512.0\\n"
75+
" y: 60.0\\n"
76+
"}\\n"
77+
"text: \\\"999 COINS!\\\"\\n"
78+
"font: \\\"/assets/custom.font\\\"\\n"
79+
"material: \\\"/builtins/fonts/label-df.material\\\"\\n"
80+
"\"\n"
81+
" position {\n"
82+
" y: -169.0\n"
83+
" z: 0.1\n"
84+
" }\n"
85+
"}\n"
86+
"embedded_components {\n"
87+
" id: \"coin3\"\n"
88+
" type: \"sprite\"\n"
89+
" data: \"default_animation: \\\"coin_06\\\"\\n"
90+
"material: \\\"/builtins/materials/sprite.material\\\"\\n"
91+
"size {\\n"
92+
" x: 96.0\\n"
93+
" y: 96.0\\n"
94+
"}\\n"
95+
"size_mode: SIZE_MODE_MANUAL\\n"
96+
"textures {\\n"
97+
" sampler: \\\"texture_sampler\\\"\\n"
98+
" texture: \\\"/assets/sprites.atlas\\\"\\n"
99+
"}\\n"
100+
"\"\n"
101+
" position {\n"
102+
" x: 20.0\n"
103+
" y: 41.0\n"
104+
" z: 0.1\n"
105+
" }\n"
106+
"}\n"
107+
"embedded_components {\n"
108+
" id: \"coin1\"\n"
109+
" type: \"sprite\"\n"
110+
" data: \"default_animation: \\\"coin_06\\\"\\n"
111+
"material: \\\"/builtins/materials/sprite.material\\\"\\n"
112+
"size {\\n"
113+
" x: 96.0\\n"
114+
" y: 96.0\\n"
115+
"}\\n"
116+
"size_mode: SIZE_MODE_MANUAL\\n"
117+
"textures {\\n"
118+
" sampler: \\\"texture_sampler\\\"\\n"
119+
" texture: \\\"/assets/sprites.atlas\\\"\\n"
120+
"}\\n"
121+
"\"\n"
122+
" position {\n"
123+
" x: -41.0\n"
124+
" y: 15.0\n"
125+
" z: 0.1\n"
126+
" }\n"
127+
"}\n"
128+
"embedded_components {\n"
129+
" id: \"coin2\"\n"
130+
" type: \"sprite\"\n"
131+
" data: \"default_animation: \\\"coin_06\\\"\\n"
132+
"material: \\\"/builtins/materials/sprite.material\\\"\\n"
133+
"size {\\n"
134+
" x: 96.0\\n"
135+
" y: 96.0\\n"
136+
"}\\n"
137+
"size_mode: SIZE_MODE_MANUAL\\n"
138+
"textures {\\n"
139+
" sampler: \\\"texture_sampler\\\"\\n"
140+
" texture: \\\"/assets/sprites.atlas\\\"\\n"
141+
"}\\n"
142+
"\"\n"
143+
" position {\n"
144+
" x: 6.0\n"
145+
" y: -30.0\n"
146+
" z: 0.1\n"
147+
" }\n"
148+
"}\n"
149+
"embedded_components {\n"
150+
" id: \"glow\"\n"
151+
" type: \"sprite\"\n"
152+
" data: \"default_animation: \\\"anim\\\"\\n"
153+
"material: \\\"/builtins/materials/sprite.material\\\"\\n"
154+
"size {\\n"
155+
" x: 600.0\\n"
156+
" y: 600.0\\n"
157+
"}\\n"
158+
"size_mode: SIZE_MODE_MANUAL\\n"
159+
"textures {\\n"
160+
" sampler: \\\"texture_sampler\\\"\\n"
161+
" texture: \\\"/builtins/graphics/particle_blob.tilesource\\\"\\n"
162+
"}\\n"
163+
"\"\n"
164+
"}\n"
165+
""
166+
position {
167+
z: 0.5
168+
}
169+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#version 140
2+
3+
in mediump vec2 var_texcoord0;
4+
5+
out vec4 out_fragColor;
6+
7+
uniform mediump sampler2D texture0;
8+
9+
void main()
10+
{
11+
out_fragColor = texture(texture0, var_texcoord0);
12+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: "repeating_background"
2+
tags: "model"
3+
vertex_program: "/example/repeating_background.vp"
4+
fragment_program: "/example/repeating_background.fp"
5+
vertex_space: VERTEX_SPACE_WORLD
6+
vertex_constants {
7+
name: "mtx_worldview"
8+
type: CONSTANT_TYPE_WORLDVIEW
9+
}
10+
vertex_constants {
11+
name: "mtx_proj"
12+
type: CONSTANT_TYPE_PROJECTION
13+
}
14+
vertex_constants {
15+
name: "uv_params"
16+
type: CONSTANT_TYPE_USER
17+
value {
18+
x: 1.0
19+
y: 1.0
20+
z: 0.0
21+
w: 0.0
22+
}
23+
}
24+
samplers {
25+
name: "texture0"
26+
wrap_u: WRAP_MODE_REPEAT
27+
wrap_v: WRAP_MODE_REPEAT
28+
filter_min: FILTER_MODE_MIN_LINEAR
29+
filter_mag: FILTER_MODE_MAG_LINEAR
30+
max_anisotropy: 0.0
31+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
-- Size of a single tile in pixels
2+
go.property("tile_size", 128)
3+
-- Scroll speed vector (x, y, z) in pixels per second
4+
go.property("scroll_speed", vmath.vector3(50, 0, 0))
5+
6+
-- Applies layout based on current window size
7+
-- Scales the game object to fill the entire window and calculates UV scale
8+
local function apply_layout(self)
9+
local width, height = window.get_size()
10+
-- Scale the game object to match window dimensions
11+
go.set(".", "scale", vmath.vector3(width, height, 1))
12+
13+
-- Calculate how many tiles fit in the window (for UV tiling)
14+
self.uv_scale = vmath.vector3(width / self.tile_size, height / self.tile_size, 0)
15+
16+
-- Send UV parameters to the shader: scale (x, y) and offset (z, w)
17+
local uv_params = vmath.vector4(self.uv_scale.x, self.uv_scale.y, self.offset.x, self.offset.y)
18+
go.set("#model", "uv_params", uv_params)
19+
end
20+
21+
-- Updates UV offset for scrolling animation
22+
-- Moves the texture offset based on scroll speed and wraps it using modulo
23+
local function update_uv_params(self, dt)
24+
-- Calculate offset delta in tile units (0-1 range)
25+
local delta = self.scroll_speed * dt / self.tile_size
26+
-- Update offset (subtract because we want to scroll in the direction of scroll_speed)
27+
self.offset = self.offset - delta
28+
-- Wrap offset to 0-1 range to create seamless repeating
29+
self.offset.x = self.offset.x % 1
30+
self.offset.y = self.offset.y % 1
31+
32+
-- Send updated UV parameters to the shader
33+
local uv_params = vmath.vector4(self.uv_scale.x, self.uv_scale.y, self.offset.x, self.offset.y)
34+
go.set("#model", "uv_params", uv_params)
35+
end
36+
37+
-- Initialize the script
38+
-- Sets up the initial UV offset to zero
39+
function init(self)
40+
self.offset = vmath.vector3(0)
41+
end
42+
43+
function final(self)
44+
end
45+
46+
-- Update function called every frame
47+
-- Applies layout and updates UV parameters for scrolling
48+
function update(self, dt)
49+
apply_layout(self)
50+
update_uv_params(self, dt)
51+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#version 140
2+
3+
in vec4 position;
4+
in vec2 texcoord0;
5+
uniform vp_uniforms
6+
{
7+
mat4 mtx_worldview;
8+
mat4 mtx_proj;
9+
vec4 uv_params;
10+
};
11+
12+
out vec2 var_texcoord0;
13+
14+
void main()
15+
{
16+
// uv_params.x = repeat scale on U axis (tiles across width)
17+
// uv_params.y = repeat scale on V axis (tiles across height)
18+
// uv_params.z = scroll offset on U axis (normalized 0..1)
19+
// uv_params.w = scroll offset on V axis (normalized 0..1)
20+
var_texcoord0 = texcoord0 * uv_params.xy + uv_params.zw;
21+
gl_Position = mtx_proj * mtx_worldview * vec4(position.xyz, 1.0);
22+
}

0 commit comments

Comments
 (0)