Hi:
I have used the method getMaskImage to create a mask image in my scene.
The problem I have is that the resulting mask (works perfect) is over all of the other sprites in the scene, the gui I created and everything. Is there a way to set z-index of the mask? I have tried to create de mask after update strites and many other solutions and none of them works. What am I doing wrong?
Regards.
Hard to answer without a better understanding of what you're doing. Can you share any of the code or some screenshots?
Hi, sorry for not adding images or code.
This is what I am trying to get (this is a mask with a flashlight) and the hearts for the gui:
but this is what I got:
and when I move the flashlight to the coordinates of the gui I got this:
I am sure my code is wrong but I do not know where, this is the simple version of the code:
local shadeImage = playdate.graphics.image.new(400, 240, playdate.graphics.kColorBlack)
shadeImage:addMask()
local sprite = playdate.graphics.sprite.new(shadeImage)
sprite:moveTo(100, 100)
sprite:add()
local shadeAsset = playdate.graphics.image.new( 'shadepng' )
local lightAsset = playdate.graphics.image.new( 'light' )
local gfx = playdate.graphics
gfx.setColor(gfx.kColorWhite)
gfx.fillRect(0, 0, 400, 240)
gfx.setBackgroundColor(gfx.kColorWhite)
local dx, dy = 0, 0
local player = gfx.sprite:new()
player:setImage(gfx.image.new('player'))
player:moveTo(100,100)
player:addSprite()
local heart = gfx.sprite:new()
heart:setImage(gfx.image.new('hearts'))
heart:setCenter(0,0)
heart:moveTo(370,10)
heart:setZIndex(200)
heart:addSprite()
function playdate.update()
gfx.sprite.update()
player:moveBy(dx, dy)
local shadeMask = shadeImage:getMaskImage()
playdate.graphics.pushContext( shadeMask )
shadeAsset:getMaskImage():draw( 0, 0)
lightAsset:drawRotated( player.x, player.y,playdate.getCrankPosition())
playdate.graphics.popContext()
shadeImage:draw(0, 0)
end
Regards and thanks so much for the help
The issue is that first all of the sprites are drawn all when gfx.sprite.update()
is called, but then shadeImage
is drawn on top of everything at the end of the update function. Since shadeImage
is a full screen black image with a small alpha cutout, that's all you're seeing on screen, covering everything else.
Instead of drawing that image directly, I think what you want to do is to call :setImage()
on your sprite
variable to assign your modified image to act as a mask for the sprites behind it. So instead of shadeImage:draw(0, 0)
, you'd do sprite:setImage(shadeImage)
. You will need to assign z-indexes accordingly to make sure it's drawing overtop of the sprites to be masked.
A maybe better solution: Rather than doing the work in your main update loop, another option is to override the sprite's drawing function to draw the masked-out area directly, using something like the same code you have now (I'm not 100% sure what shadeAsset
and lightAsset
look like, so I am a bit unclear as to why you're drawing the mask image from shadeAsset
there instead of maybe just calling shadeImage:clearMask(1)
before pushContext()
is called):
function sprite:draw(x, y, width, height)
local shadeMask = shadeImage:getMaskImage()
playdate.graphics.pushContext(shadeMask)
shadeAsset:getMaskImage():draw(0, 0)
lightAsset:drawRotated(player.x, player.y,playdate.getCrankPosition())
playdate.graphics.popContext()
shadeImage:draw(0, 0)
end
Alternatively, if you want to mask only that sprite, you could use sprite:setStencilImage(shadeImage)
.
Thanks so much, now I understand my mistakes and with draw method works like a charm.
Regards.