NobleRobot / NobleEngine

A li'l game engine for Playdate.
https://noblerobot.github.io/NobleEngine/
Other
408 stars 31 forks source link

Animated sprites render incorrectly when drawn offscreen #74

Closed sourencho closed 4 months ago

sourencho commented 4 months ago

Describe the bug When an animated sprite is drawn in the negative bounds (either x or y), the image will get rendered incorrectly. The image will slide such that the left most part of the frame is drawn starting from the x or y 0 coordinate rather than off the screen.

To reproduce

  1. Create an animated sprite
  2. Move it to a coordinate where x or y is negative either with add or moveTo
  3. Observe that the sprite is rendered incorrectly

Expected behavior I expect to see the correct half of the sprite drawn on the screen.

Screenshots/Code snippets In the code below, I draw an animated sprite and a static sprite that are somewhat offscreen. Notice how the animated sprite slides over, whereas the static one draws as expected.

local animSprite= NobleSprite("assets/images/bwird_cabbage", true, true)
animSprite:setSize(80, 60)
animSprite:setCenter(0, 0)
animSprite:add(-20, 50)

local staticSprite = NobleSprite("assets/images/bwird.png")
staticSprite:setCenter(0, 0)
staticSprite:add(-20, 120)

anim_cut2

Assets used: bwird_cabbage-table-80-60 bwird

Additional context

Mark-LaCroix commented 4 months ago

This issue happened when calling the SDK's playdate.graphics.sprite:draw(x, y) method, which is extended by Noble Engine as NobleSprite:draw(__x, __y). For some reason, when a playdate.graphics.sprite is positioned at a negative x or y position, the value fed into that method by the SDK is value * -1, but equally oddly, when the playdate.graphics.sprite is positioned at a positive position, the value is 0.

So what was happening was that the sprite itself was positioned correctly at -20, 50, but the SDK is calling animSprite:draw(20,0) for some reason, and we pass those values into animSprite.animation:draw(), which is why it draws incorrectly. When the sprite is positioned at a point greater than 0, no matter what the value is, it calls animSprite:draw(0,0), and it draws correctly. This happens in the C code of the SDK, so I didn't go tracking down exactly why it does this.

Basically, because a sprite has its own internal coordinates, we never want it to call anything other than animSprite:draw(0,0). I don't know why it feeds in incorrect values in this case, but the actual bug is in Noble Engine because it erroneously passes those values on to the animation object when it should just ignore them.

Still leaves a minor mystery, but fixed all the same!

Thanks for providing the thorough bug report. It made this a lot easier to solve.

sourencho commented 4 months ago

tysm!