Animation jitter introduced after 2.3.0 system update

System: Simulator 2.3.x MacOS 14.3.1 & On Device 2.3.x
Expected: No visible jitter on animations via setAnimator
Actual: Jitter is noticeable on animations for shipped title that were not there previously

In some recorded footage of Hermit on youtube, I noticed a left to right jitter visible on sprites that I have not seen before. Here's a gif showing the jitter in action:
2.3.0-bug

This is a recording of the game being built in 2.3.0/2.3.1. The code is unchanged since it's launch on Catalog and if I build the game using an older version, the jitter disappears.
2.1.1-nobug

This recording is from a build on 2.1.1.

Playing my own game on device, I can anecdotally say that I have not seen this before the recent system updates.

The hover effect in the game is achieved as follows:

function SpriteGroup:animateHover(x, y)
    local moveUp = geometry.lineSegment.new(x, y, x, y + hoverOffset)
    local moveDown = geometry.lineSegment.new(x, y + hoverOffset, x, y)
    local hover = gfx.animator.new({ 500, 500 }, { moveUp, moveDown }, { easing.linear, easing.linear })
    hover.repeatCount = -1
    self.sprite:setAnimator(hover)
end

I have not had a chance to build a fully isolated test case to reproduce, but posting this bug report as there does appear to be some kind of regression in the SDK (given the game performed without any visual artifacting before recent updates). Let me know if I can help provide any additional details.

Found it! The interpolation code there looked like (1.0-t)*x1 + t*x2 but in 2.3 I changed the 1.0 to 1.0f so that it wasn't doing slower double-precision math. It didn't cross my mind that in the case where x1 == x2 that could cause problems. If x1 and x2 there are 200 then occasionally the result is something like 199.999998, which gets truncated to 199. I can't remember exactly why we're using floorf() instead of rintf() but I think that's intentional, that we were rounding previously and it caused other problems. To fix this I'll add checks for x1 == x2 and y1 == y2 and avoid the interpolation on those axes in those cases.

2 Likes

Nice work tracking it down! I imagine the use of rintf() would have its own edge case graphical inconsistencies that could pop up :sweat_smile: