How to do a "Fade In" or "Fade Out" in Pulp

I've spent a little bit of time figuring out how to do a fade in or fade out effect for the cutscenes in my game, so I thought I'd share the results here.


-- FADE OUT --

Fade out is the easier of the two, and uses an animated player tile with transparency and increasingly darker dither patterns:
fadeTest2
In this example, I called a custom event fadeOut on the confirm event

on confirm do
	tell event.game to
		log "calling fadeOut event"
		call "fadeOut"
	end
end

Then in the custom event, I tell every single tile on screen to play the fade out animation:

on fadeOut do
	log "fadeOut event answered"
	
	// row 0
	tell 0,0 to
		play "fade_out"
	end
	tell 1,0 to
		play "fade_out"
	end
	tell 2,0 to
		play "fade_out"
	end
    ...
    ...
    ...
    etc.
end

This works well enough on-device. Keep in mind I'm only planning on using these during cutscenes so there won't be any player input effected by performance dips.

In this case, there is a slight pause while the entire screen is set to play the tile, but then the tile's animation plays out smoothly at Pulp's full 20fps


-- FADE IN --

Now fading in is a little trickier and causes some performance issues on-device. But again, for my cutscene use-case that's not an issue.

*(See the end of this post for an aside on how transparency works in Pulp, and why we needed to change methods for fade in as opposed to doing the same thing as fade out)

Essentially the same dither patterns from the fade out animation are used, but instead of being in one animated tile each frame is split into their own single tile. Then we draw those frames sequentially to get this:
https://gfycat.com/immediatesoulfulaustraliancattledog

Which absolutely tanks performance. But that was expected when you set a draw over every single tile on the screen.

What is happening specifically is on A press I call a custom event, just like before. This custom event though is stepping through each individual tile at a specified rate (as if they were frames of an animation) and setting them to a variable fadeInFrame.

on fadeIn do
	log "fadeIn answered"
	
	ignore
	drawFadeIn = 1
	// step through animation frames
	fadeInFrame = "fade_in 1"
	wait 0 then
		fadeInFrame = "fade_in 2"
		wait 0 then
			fadeInFrame = "fade_in 3"
			wait 0 then
			...
			...
			...
			etc.

I also enable the draw flag drawFadeIn at the start of the event and set it back to zero at the end. This allows this block of code to start drawing in the player's draw event:

on draw do
	
	// fadeIn effect
	if drawFadeIn==1 then
		// row 0
		draw fadeInFrame at 0,0
		draw fadeInFrame at 1,0
		draw fadeInFrame at 2,0
		draw fadeInFrame at 3,0
		draw fadeInFrame at 4,0
		...
		...
		...
		etc.

And this code lists out draw "_" at .x,y for every single tile on screen.

So... what do we do about the terribly slow fade in when playing on-device? Well we're not going to be able to make drawing to every single tile more performant, so I just cut out animation frames!

After going from stepping through 27 dither frames, down to 8 frames, this is now what the "sped up" fade in looks like on-device:
https://gfycat.com/elderlyenergeticdrake

Which I think for my use of fading in from a cutscene is perfectly usable! (Keep in mind though if you have music playing during this it will also slow down and be very noticeable)


-- WRAP UP --

So, this is what I came up with in a night. I'm sure someone smarter than me could make better pulp script to do something like dynamically stepping through each tile coordinate so that you wouldn't need to type them all manually like I did, but as far as I know I don't think there will be any way to actually improve the performance of these methods. Hopefully they're useful to someone though!

Both of my pulp test games will be attached. If you have any questions just let me know.


*Notes on transparency in Pulp:

So, as you probably know transparency is only possible on Player tiles. But what you may not know is that when a pixel is marked to be transparent, it's not actually "revealing" what should be underneath that pixel. It simply says, "don't update this pixel."

This is fine when doing a fade out, because the entire tile starts as transparent then gradually adds more black pixels. But when going the other way (fade in), you start with an all-black tile, so adding transparent pixels to that only says, "don't change these," therefore making the whole thing remain black.

So, to get around this, we don't use one animating tile, but step through completely separate tiles to "make" our own animation. What I think is happening is since you tell it to change to a completely different tile, it sort of "refreshes" the underlying pixels between tiles, allowing the proper image to show through the transparency.

Honestly, I'm not 100% why it works, but it does!


Pulp Fade Tests.zip (12.4 KB)

6 Likes

(NOTE: The gifs in this post are not of my game) lol
For anyone curious, I'm making HatTrick (itch.io page). Here's the WIP scene where I'm using the fade in effect (there will probably be an actual cutscene preceding this in the final game):
https://gfycat.com/unlawfuljollydobermanpinscher

3 Likes

I'd imagine you could adjust this code from my frame tiling technique to fit this use case? Make it a custom event and adjust what happens for each while loop.

I used this method to do full screen art but yeah there's a definite frame dip. Not such a big deal when you're in some kind of transition tho.

on enter do
	x = 0
	y = 0
	f = 0
	while y<=14 do
		while x<=24 do
			tell x,y to
				frame f
			end
			x++
			f++
		end
		y++
		x = 0
	end
end
1 Like