Sprite image does not update when rotation is set

I have been trying to rotate my game graphics and encountered some odd quirks with things not drawing.

My need for rotation is simple: I render my stage into the image of a sprite with 0,0 being the usual top,left of the screen. I want to rotate the sprite 180' so that bottom,right of the screen appears to be the origin. This should be easier than changing the co-ordinate maths throughout my game, and it will allow changing stage rotation on demand.

And I managed to reduce it to this bug report.

  • dot moves down the screen based on time
  • dot is drawn to sprite image
  • pressing A to set rotation on sprite
  • dot stops moving (sprite image stops updating)

I've tried some things, to no avail:

  • forcing sprite image update
  • setting dirty rect for whole screen

What is going on here?

Tested:

  • 1.11.1 SDK (macOS Simulator)
  • 1.13.7 SDK (macOS Simulator)
  • 2.0.0-beta4 (hardware)

rotation.loop

Controls

  • A to set rotation to 180'
  • B to reset rotation to 0'

Downloads

import "CoreLibs/graphics"
import "CoreLibs/sprites"

local gfx <const> = playdate.graphics

SCREEN_W = playdate.display.getWidth()
SCREEN_H = playdate.display.getHeight()

gfx.setBackgroundColor(gfx.kColorBlack)

testImage = gfx.image.new( SCREEN_W,SCREEN_H, gfx.kColorClear )
gfx.pushContext(testImage)
	gfx.setColor(gfx.kColorWhite)
	gfx.fillCircleAtPoint(SCREEN_W//2,SCREEN_H//2,5)
gfx.popContext()
test = gfx.sprite.new( testImage )
test:moveTo(SCREEN_W//2,SCREEN_H//2)
test:add()

function playdate.AButtonDown()
	test:setRotation(-180)
end

function playdate.BButtonDown()
	test:setRotation(0)
end

function playdate.update()
	gfx.pushContext(testImage)
		testImage:clear(gfx.kColorClear)
		gfx.setColor(gfx.kColorWhite)
		gfx.fillCircleAtPoint(20,playdate.getCurrentTimeMilliseconds() % (SCREEN_H*10)//10,8)
	gfx.popContext()

	-- test:setImage(testImage)
	-- playdate.graphics.sprite.addDirtyRect(0, 0, SCREEN_W,SCREEN_H)

	gfx.sprite.update()
end

I'm wondering if I'm doing something intrinsically wrong here?

@dave any ideas on this? Is it fallout from the sprite rework?

No, I'm pretty sure this bug has always been there. :confused:

The problem is rotation and scale are implemented in the Lua wrapper by keeping a reference to the source image and setting a rotated/scaled image on the underlying C sprite. We do track when images are drawn into, and then sprites know they need to redraw if that flag is set, but that doesn't touch the Lua environment so it can't follow the link back to the source image to see that it needs to redraw.

I've got a fix that adds a check for this case in the Lua sprite update callback. I don't love adding overhead to all sprites for this fairly rare case, though it's probably not a measurable difference. The right way to fix this is to move sprite rotation and scaling down to the C layer, something we should have done a long time ago. I'll file a separate issue for that, if it's not already in there.

In the mean time, an ugly workaround is to first clear the image then set it again:

    test:setImage(nil)
    test:setImage(testImage)
1 Like

Thanks Dave!

I'll use the workaround.

1 Like

I just noticed this was a dupe of Strangeness when updating the image of a sprite that is :setScale(2) and was fixed in 2.3.

1 Like