Image:draw() in sprite:draw() callback with sourceRect draw at x*2,y*2 in v1.13.1

There seems to be an issue of how image:draw() draws images that use a sourceRect in v1.13 . My game Jezzak works by drawing a section of an image using image:draw() and sourceRect, in order to show an area has been captured. In the most recent release the image seems to be drawn at x2,y2.

Correct Behavior

aFoldInSpaceTime

Current > 1.13 Behavior

imageDrawIssue

Here is an example with the provided reference code. The left example is draw in the sprites draw call back the right is drawn directly in playdate.update() and works as expected.

imageDrawIssueRef

Reference Code:
drawIssueReference.zip (23.9 KB)

import 'CoreLibs/sprites.lua'
import 'CoreLibs/graphics.lua'

local gfx = playdate.graphics

-- Sprite
local x1 = 20
local y1 = 20 
local w1 = 100
local h1 = 100

-- Update 
local x2 = 250
local y2 = 20 
local w2 = 100
local h2 = 100

local bgImg = gfx.image.new('img.png') -- Background image
local fgImg = gfx.image.new('img-fg.png') -- Foreground image


class("Block").extends(gfx.sprite)


function Block:init(x,y,w,h)
	
	Block.super.init(self)
	
	self.fgImg = gfx.image.new('img-fg.png')

	self:setCenter(0,0)
	self:setSize(w, h)
	self:moveTo(x, y)
	
	self:addSprite()
	
end


function Block:draw(x,y,w,h)
	
	gfx.drawRect(x,y,w,h)
	self.fgImg:draw(self.x,self.y,playdate.graphics.kImageUnflipped,self.x,self.y,self.width,self.height)
	
end

bgImg:draw(0,0)
Block(x1,y1,w1,h1)

function playdate.update()
	
	playdate.graphics.sprite.update()
	
	fgImg:draw(x2,y2,playdate.graphics.kImageUnflipped,x2,y2,w2,h2)
	gfx.drawRect(x2,y2,w2,h2)

end

I will also add that it is possible that I am just not implementing this correctly so if that is in the case maybe you can point me in the right direct.

Also, in previous version I needed to multiply the sourceRect coordinate by 2 ( x2,y2) in order to the correct section of the image. I do not know why this is.

Example:

gfx.image:draw(self.x,self.y,playdate.graphics.kImageUnflipped,self.x*2,self.y*2,self.width,self.height)
1 Like

Okay, I think I see what's going on. Two things: First, what the docs don't make clear at all is the sprite system moves the drawing offset in the draw callback so that (0,0) is the top left of the sprite bounds. I'm pretty sure that's regardless of the sprite center, which was.. ehhhhh not a great decision on my part, but here we are and if I change it now it'll break too much stuff. So in the sprite draw callback you'll want

    self.fgImg:draw(0,0,playdate.graphics.kImageUnflipped,self.x,self.y,self.width,self.height)

instead. BUT! It looks like there's also a bug in image:draw() when using both a source rect and a drawing offset, it goofs up the clip rect. But the system sets up a clip rect to the sprite bounds before calling your draw callback, so we can just draw the whole image offset to the screen origin:

    self.fgImg:draw(-self.x,-self.y,playdate.graphics.kImageUnflipped)

That works the same under the hood, you're not taking a penalty here by not using a source rect.

Let me know if that does the trick!

1 Like