I've written a custom animation handling system for a game I've been working on, and it seems to be having some trouble with partial transparency.
This character's got glasses, and where those glasses don't overlap the face, they're white with ~50% alpha. This gets drawn over the game's background. When I'm just drawing a static single frame (when the dialogue portrait has finished talking), this works just fine. You can see that on the right there (with the lightened black outlines highlighted to distinguish them from the gray floor background.) On the left, though, is what the same sprite looks like when an animation is playing. You can see the pixels underneath the glasses aren't affected as much by the partially transparent glasses. I've messed around in an image editor and determined that there is an effect- the pixels underneath the glasses are slightly lightened- but despite the animation images having the exact same pixels in those locations, it comes out looking different when drawn in-game. (This produces an undesirable flicker effect when transitioning between the static and animated sprites.)
The way my animation code works (github link here) is that it takes a spritesheet, then slices that up into frames by drawing quads of that spritesheet to individual frame canvases, which it pushes to an array. (My custom array class is just a table with some utility functions, nothing suspicious there.) When an AnimatedThing calls its draw, it determines the appropriate frame canvas based on time, and just draws that, same as a static sprite. So, I'm pretty sure the problem here is happening when I'm slicing up the spritesheet and drawing the individual frames to the canvases. Here's the code that does this when the animation is created:
Code: Select all
AnimatedThing = function(xp,yp,zp,filename)
local base = CanvasThing(xp,yp,zp,love.graphics.newCanvas(10,10)); --just setting up a game object
base.thingType = "AnimatedThing"; --and making it a different type
base.jsonstring = love.filesystem.read("json/animations/" .. filename .. ".json"); --reading the animation data
base.data = json.decode(base.jsonstring);
base.anims = {}; --creating a table of separate arrays for different animations the game object can play
base.currentAnim = base.data.default;
--create individual animation frame canvases for each animation
for k,v in pairs(base.data.animations) do
local animdata = base.data.animations[k];
local sheet = love.graphics.newImage(animdata.filepath); --reads the spritesheet image data
base.anims[k] = {};
base.anims[k].fps = animdata.fps;
base.anims[k].frames = Array(); --create the frames array used to store the individual canvases
base.anims[k].framecount = animdata.frames;
base.anims[k].playOnce = animdata.playOnce;
for i = 1, base.anims[k].framecount, 1 do --okay, here's the juicy part where things go wrong somehow
local canv = love.graphics.newCanvas(animdata.width,animdata.height); --create a new canvas to draw to
love.graphics.pushCanvas(canv); --custom method for setting the canvas and pushing it to a stack to be removed after. does not affect the canvas itself.
local code = i - 1;
local cx = math.floor(code%base.anims[k].framecount);
local cy = math.floor(code/base.anims[k].framecount);
local quad = love.graphics.newQuad(cx*animdata.width,cy*animdata.height,animdata.width,animdata.height,sheet:getWidth(),sheet:getHeight());
--^all that is working fine, it's just calculating which frame to slice out of the sheet
love.graphics.draw(sheet,quad,0,0); --here's the problem, i think- looks like this draw is drawing the transparency wrong
love.graphics.popCanvas(); --sets LOVE's active canvas to whatever it was before
base.anims[k].frames.push(canv); --stores the new frame canvas
if k == base.data.default then
base.canvas = canv; --if you just created the default animation, set the game object's animation to that
end
end
end
--a bunch of timing code you can check out at the github
end
<static image, game draws image data
<animation, game draws canvas data
Somewhere along the line, the partially transparent pixels in the spritesheet... are becoming either more transparent than they should be, or the color is getting darker, or something. Not sure what, not sure why, only kinda sure where. There's only two places those get drawn- the slicing code right there, and when the canvas itself is drawn to the screen. (Some difference in how LOVE handles transparency when drawing image data vs canvas data?)
Any idea what could cause this sort of thing to happen?