Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions animation/infinite-scroll-animation/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091)
*.animationset linguist-language=JSON5
*.atlas linguist-language=JSON5
*.camera linguist-language=JSON5
*.collection linguist-language=JSON5
*.collectionfactory linguist-language=JSON5
*.collectionproxy linguist-language=JSON5
*.collisionobject linguist-language=JSON5
*.cubemap linguist-language=JSON5
*.display_profiles linguist-language=JSON5
*.factory linguist-language=JSON5
*.font linguist-language=JSON5
*.gamepads linguist-language=JSON5
*.go linguist-language=JSON5
*.gui linguist-language=JSON5
*.input_binding linguist-language=JSON5
*.label linguist-language=JSON5
*.material linguist-language=JSON5
*.mesh linguist-language=JSON5
*.model linguist-language=JSON5
*.particlefx linguist-language=JSON5
*.render linguist-language=JSON5
*.sound linguist-language=JSON5
*.sprite linguist-language=JSON5
*.spinemodel linguist-language=JSON5
*.spinescene linguist-language=JSON5
*.texture_profiles linguist-language=JSON5
*.tilemap linguist-language=JSON5
*.tilesource linguist-language=JSON5

# Defold JSON Files
*.buffer linguist-language=JSON

# Defold GLSL Shaders
*.fp linguist-language=GLSL
*.vp linguist-language=GLSL

# Defold Lua Files
*.editor_script linguist-language=Lua
*.render_script linguist-language=Lua
*.script linguist-language=Lua
*.gui_script linguist-language=Lua
11 changes: 11 additions & 0 deletions animation/infinite-scroll-animation/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/.editor_settings
/.internal
/build
.externalToolBuilders
.DS_Store
Thumbs.db
.lock-wscript
*.pyc
.project
.cproject
builtins
91 changes: 91 additions & 0 deletions animation/infinite-scroll-animation/example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
title: Infinite Scroll Animation
brief: Learn how to make infinite scroll for all objects on your level with only two scripts
author: Evgenii Starostin
scripts: scroll_item.script, scroll_controller.script
thumbnail: thumbnail.webp
tags: animation
---
This example demonstrates a reusable infinite scrolling system for Defold. The setup works with any type of game object and allows you to build multiple scrolling layers, making it useful for parallax backgrounds, decorations, or endlessly moving scenery.

The project uses assets from the [Shape Characters](https://kenney.nl/assets/shape-characters) by Kenney.


## Project Structure
The scene is built from several independent scrolling layers.

```
main.collection
├── floor.collection
├── background.collection
├── middle.collection
└── foreground.collection
```
Each layer is a collection containing:

a root game object with `scroll_controller.script`
one or more scrolling game objects
`scroll_item.script` attached to every scrolling object

Each layer can have its own speed, direction and scrolling bounds.

## Registering Objects
Every scrolling object contains a small helper script.

During initialization it registers itself with the layer controller by sending its game object id.
```lua
function init(self)
msg.post("root#scroll_controller", "prop:register", {
id = go.get_id()
})
end
```
The controller collects all registered objects before starting the scrolling logic.

## Controller Properties
Each scrolling layer can be configured using script properties.
```lua
go.property("SPEED", 90)
go.property("DIRECTION", -1)
go.property("LEFT_BOUND", -1000)
go.property("RIGHT_BOUND", 1000)
go.property("COUNT_OBJECTS", 1)
```
| Property | Description |
| -------- | ------- |
| SPEED | Scrolling speed in pixels per second. |
| DIRECTION | Scroll direction (-1 for left, 1 for right). |
| LEFT_BOUND | Position where objects wrap when scrolling left. |
| RIGHT_BOUND | Position where objects wrap when scrolling right. |
| COUNT_OBJECTS | Number of scrolling objects expected in the layer. |

Different collection instances can override these values to create parallax effects without changing any code.

## How It Works
Once all objects have registered, the controller:
- Reads the position of every object.
- Sorts them from left to right.
- Calculates the distance between each object and its neighbour.

Instead of using a fixed spacing value, the controller stores the original distance between neighbouring objects. This means the objects can be placed freely in the editor while preserving their layout during scrolling.

Every frame, all objects move by the same amount.

When the leftmost object reaches the left boundary, it is moved to the right side of the layer using the previously calculated spacing. The same logic can also be applied when scrolling in the opposite direction.

Because the original spacing is preserved, the scrolling loop appears seamless even when objects are unevenly distributed.

## Customizing
The system is designed to be reusable.

You can:
- Add or remove scrolling objects.
- Use sprites, animated game objects, labels, or any other game object.
- Create multiple scrolling layers with different speeds.
- Adjust the scrolling bounds for each layer.
- Reverse the scrolling direction.

No changes to the scripts are required when creating additional layers.

## Summary
By separating object registration from movement logic, the same scrolling system can be reused across many collections. Each layer manages its own objects independently, making it easy to build infinite scrolling scenes and parallax backgrounds while keeping the project structure simple
24 changes: 24 additions & 0 deletions animation/infinite-scroll-animation/game.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[bootstrap]
main_collection = /main/main.collectionc

[script]
shared_state = 1

[display]
width = 720
height = 720
high_dpi = 1

[android]
input_method = HiddenInputField

[physics]
gravity_y = -1000.0
scale = 0.01

[html5]
scale_mode = stretch

[project]
title = infinite-scroll-animation

4 changes: 4 additions & 0 deletions animation/infinite-scroll-animation/input/game.input_binding
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mouse_trigger {
input: MOUSE_BUTTON_1
action: "touch"
}
20 changes: 20 additions & 0 deletions animation/infinite-scroll-animation/main/atlas.atlas
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
images {
image: "/main/images/tile_grey.png"
}
images {
image: "/main/images/blue_body_square.png"
pivot_y: 1.0
}
images {
image: "/main/images/green_body_square.png"
pivot_y: 1.0
}
images {
image: "/main/images/purple_body_square.png"
pivot_y: 1.0
}
images {
image: "/main/images/red_body_square.png"
pivot_y: 1.0
}
extrude_borders: 2
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 48 additions & 0 deletions animation/infinite-scroll-animation/main/main.collection
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: "main"
collection_instances {
id: "floor"
collection: "/main/scroll_manager/floor.collection"
position {
x: 363.0
z: 0.9
}
}
collection_instances {
id: "foreground"
collection: "/main/scroll_manager/red.collection"
position {
x: 360.0
y: 80.0
z: 0.5
}
instance_properties {
id: "root"
properties {
id: "scroll_controller"
properties {
id: "SPEED"
value: "70.0"
type: PROPERTY_TYPE_NUMBER
}
}
}
}
collection_instances {
id: "middle"
collection: "/main/scroll_manager/green.collection"
position {
x: 358.0
y: 80.0
z: 0.9
}
}
collection_instances {
id: "background"
collection: "/main/scroll_manager/puprple.collection"
position {
x: 396.0
y: 80.0
z: 0.2
}
}
scale_along_z: 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: "scroll"
instances {
id: "floor_object"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: -90.0
y: 40.0
}
}
instances {
id: "floor_object1"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: -270.0
y: 40.0
}
}
instances {
id: "floor_object2"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: 270.0
y: 40.0
}
}
instances {
id: "floor_object3"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: 90.0
y: 40.0
}
}
instances {
id: "floor_object4"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: 450.0
y: 40.0
}
}
instances {
id: "floor_object5"
prototype: "/main/scroll_manager/floor_object.go"
position {
x: -450.0
y: 40.0
}
}
scale_along_z: 0
embedded_instances {
id: "root"
children: "floor_object"
children: "floor_object1"
children: "floor_object2"
children: "floor_object3"
children: "floor_object4"
children: "floor_object5"
data: "components {\n"
" id: \"scroll_controller\"\n"
" component: \"/main/scroll_manager/scroll_controller.script\"\n"
" properties {\n"
" id: \"LEFT_BOUND\"\n"
" value: \"-540.0\"\n"
" type: PROPERTY_TYPE_NUMBER\n"
" }\n"
" properties {\n"
" id: \"RIGHT_BOUND\"\n"
" value: \"540.0\"\n"
" type: PROPERTY_TYPE_NUMBER\n"
" }\n"
" properties {\n"
" id: \"COUNT_OBJECTS\"\n"
" value: \"6.0\"\n"
" type: PROPERTY_TYPE_NUMBER\n"
" }\n"
"}\n"
""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
components {
id: "prop_controller"
component: "/main/scroll_manager/scroll_item.script"
}
embedded_components {
id: "sprite"
type: "sprite"
data: "default_animation: \"tile_grey\"\n"
"material: \"/builtins/materials/sprite.material\"\n"
"slice9 {\n"
" x: 32.0\n"
" y: 32.0\n"
" z: 32.0\n"
" w: 32.0\n"
"}\n"
"size {\n"
" x: 180.0\n"
" y: 80.0\n"
"}\n"
"size_mode: SIZE_MODE_MANUAL\n"
"textures {\n"
" sampler: \"texture_sampler\"\n"
" texture: \"/main/atlas.atlas\"\n"
"}\n"
""
}
Loading