Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tilemap: Animated tiles sometimes vanish between repeats of the loop #82286

Closed
Proggle opened this issue Sep 25, 2023 · 2 comments · Fixed by #82360
Closed

Tilemap: Animated tiles sometimes vanish between repeats of the loop #82286

Proggle opened this issue Sep 25, 2023 · 2 comments · Fixed by #82360

Comments

@Proggle
Copy link
Contributor

Proggle commented Sep 25, 2023

Godot version

v4.1.1.stable.official [bd6af8e]

System information

Windows 10

Issue description

Animated tiles will occasionally vanish for one frame when looping back from the last frame to the first frame.

Here's a video, you can see the animated grass vanish at ~4 seconds and again right before the end

TileGlitchSquare.mp4

Steps to reproduce

I am unsure exactly what triggers this, but it appears high cpu load makes it more likely, as does alt-tabbing back and forth.
That said, it happens without my CPU being slammed and without alt-tabbing, and running a bunch of CPU-heavy other processes and furiously alt-tabbing couldn't get it to reproduce in a minimal project with an animated tileset and nothing else.

From messing around with the animated tiles rendering code, when working on the pingpong, my guess is that this segment of tile_map.cpp might be the culprit.

//starting at line 3123
			real_t speed = atlas_source->get_tile_animation_speed(p_atlas_coords);
			real_t animation_duration = atlas_source->get_tile_animation_total_duration(p_atlas_coords) / speed;
			real_t time = 0.0;
			for (int frame = 0; frame < atlas_source->get_tile_animation_frames_count(p_atlas_coords); frame++) {
				real_t frame_duration = atlas_source->get_tile_animation_frame_duration(p_atlas_coords, frame) / speed;
				RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, animation_duration, time, time + frame_duration, p_animation_offset);

				Rect2i source_rect = atlas_source->get_runtime_tile_texture_region(p_atlas_coords, frame);
				tex->draw_rect_region(p_canvas_item, dest_rect, source_rect, modulate, transpose, p_tile_set->is_uv_clipping());

				time += frame_duration;
			}
			RenderingServer::get_singleton()->canvas_item_add_animation_slice(p_canvas_item, 1.0, 0.0, 1.0, 0.0);

The way it currently works, if send too few frames to the renderingserver to occupy the entirety of animation_duration, the animated tile vanishes when it runs out (rather than keeping the previous frame onscreen)

I believe that's basically happening here; with the right level of slowdown, it's possible for the game to skip a frame or something right when the tile animation loops, and since the new frames don't immediately get sent to the renderingserver, in the next frame the animated tile vanishes, then godot catches up and sends all the frames properly, restoring the animated tile.

If that's the case, there's an easy (if dumb) fix: send the first frame to the rendering server twice, once at the beginning and once at the end. (Or in a similar vein, give the last frame a duration of a million years)

When working on pingpong I added the new frames before changing animation_duration, and noticed that at start of a new cycle, any frame data that extended past the animation_duration period seems to get discarded harmlessly.

Minimal reproduction project

I don't have a minimal project at the moment, it looks like I'm going to have to chop down the project that I'm seeing the glitch in rather than building a tiny one from scratch. As a random bug that can't be triggered on demand I can't say whether or not my speculative fix would actually address the real issue, and I want to ask other people who know the tile system if they can reproduce and maybe come up with a better explanation.

@kleonc
Copy link
Member

kleonc commented Sep 25, 2023

Here's a video, you can see the animated grass vanish at ~4 seconds and again right before the end

For that grass tile what's the animation_speed and duration for each individual frame? And how many frames are there etc.
In case they're non-default best if you'd share the exact values from the resource file (e.g. from the .tscn file if it's saved as a subresource within a scene).

E.g. for:
yjJafwlpYe
the lines starting with 0:0 (tile coords within the TileSet):

[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_wit5m"]
texture = ExtResource("1_6g4wg")
texture_region_size = Vector2i(32, 32)
0:0/animation_columns = 2
0:0/animation_speed = 0.3
0:0/animation_frame_0/duration = 0.9975
0:0/animation_frame_1/duration = 1.003
0:0/animation_frame_2/duration = 1.0025
0:0/0 = 0

(if the values are default then they're not being saved within the resource file as there's no point to do so)

@Proggle
Copy link
Contributor Author

Proggle commented Sep 26, 2023

Will have more time to screw with this on the weekend, but here's one of the long grass tiles

27:0/animation_columns = 1
27:0/animation_separation = Vector2i(0, 4)
27:0/animation_speed = 6.0
27:0/animation_frame_0/duration = 6.0
27:0/animation_frame_1/duration = 1.0
27:0/animation_frame_2/duration = 1.0
27:0/animation_frame_3/duration = 1.0
27:0/0 = 0
27:0/0/physics_layer_0/linear_velocity = Vector2(0, 0)
27:0/0/physics_layer_0/angular_velocity = 0.0
27:0/0/physics_layer_1/linear_velocity = Vector2(0, 0)
27:0/0/physics_layer_1/angular_velocity = 0.0
27:0/0/physics_layer_2/linear_velocity = Vector2(0, 0)
27:0/0/physics_layer_2/angular_velocity = 0.0
27:0/0/physics_layer_2/polygon_0/points = PackedVector2Array(-16, -16, 16, -16, 16, 16, -4, 1.5)
27:0/0/physics_layer_3/linear_velocity = Vector2(0, 0)
27:0/0/physics_layer_3/angular_velocity = 0.0
27:0/0/physics_layer_3/polygon_0/points = PackedVector2Array(16, -16, -16, -16, -16, -1.5, 4, 16, 16, 16)
27:0/0/custom_data_1 = "GrassTop"
27:0/0/custom_data_3 = 16.0``

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants