PDA

View Full Version : Screen fade in/out technique



Damot
15-01-2007, 12:53 PM
I'd like to implement a screen fade out > screen fade in feature between screens in my game.

What would you recommend as the fastest/easiest technique?

dmantione
15-01-2007, 01:06 PM
Well, with 8 bit colour modes this was very easy. In pseudocode:

for i:=0 to 255 do
begin
wait_for_vertical_retrace;
for j:=0 to 255 do
with palette[i] do
begin
if red>0 then
dec(red);
if green>0 then
dec(green);
if red>0 then
dec(blue);
end;
write_new_palette_to_vga;
end;


With higher colour modes, you can also decrease the colours, but then you need to do this on the full framebuffer instead of just the palette. In many situations, it will require a 2d accelerator to do it fast enough in high colour modes.

So check if 8 bit colour is enough for your needs, and then see what to do.

Robert Kosek
15-01-2007, 01:14 PM
There are two ways, but the second is the most efficient.

1. You could, based on a specific event/flag, etc, fade all items out on the screen simultaneously. While this might lead to a neat unorthodox fade-out effect, lots of alpha rendering takes a large amount of video power; it may not work on most systems.

2. The best way is to draw a rectangle over the whole screen for your fade out; you can pick any color you like to make another effect (red pain flashes, white lighting glare, etc) but you must always vary the opacity. And easy way to do so is to use a float value for your fade in/out, 0 is hide and 1 is show, and multiply it by 255 -- for good programming practice wrap that in a "round()" conversion to make certain there wouldn't be an overflow or type assignment bug.

In my recent Asphyre project I do it this way as a "hit effect" that makes the screen invert a little (except using the actual byte value). OnRender: if damagedoverlay > 0 then
AsphyreCanvas1.Rectangle(0,0,ClientWidth,ClientHei ght,cAlpha1(damagedoverlay),cAlpha1(damagedoverlay ),fxSub);
OnProcess (be warned the alpha I set it to is an even number with no variance, I just reduce it by 2 for a rapid fadeout): if damagedoverlay > 0 then
damagedoverlay := damagedoverlay - 2;
I honestly have no clue how to do it in (un)DelphiX. So that's how I do it in my own stuff in a similar fashion, although I declared the project done before I could have implemented any transition effects.

Does that help any?

cairnswm
15-01-2007, 01:47 PM
In openGL you can set the default drawing color. By moving this color from white to black you get a fade out effect.

I dont know if this is possible in DelphiX.

Drawing an alpha blended rectangle over the screen with an increasing alpha value will give you the best effect - but I havn't used it yet.

Traveler
15-01-2007, 10:34 PM
It depends on how you´ve written your game.

I've used the rectangle approach in Village Defense.
However, it wasn't as easy as I had thought and I do recommend giving it some serious thoughts before implementing it in your game.

In VD I used states to go from, for example, the menu to the optionsscreen. You've seen it probably before, but it basically looks something like this:


procedure TMyGame.mainLoop;
begin
(...)
case gameState of
gsMenu : drawMenu();
gsOptions : drawOptions();
gsrunGame : runGame();
end;
end;



In this instance, when the user clicks the menuItem to go to the optionscreen I simply change gameState to gsOptions. Thats all there is to it.

Btw, I must point out that the menu is not an object! Its nothing more than a simple procedure with a few function calls to draw the images and a few others to check mouse activity.

Anyway, it becomes a whole different matter when I add fade effect. How are you going to implement that? Again with gamestates? I did,... but I wont be doing it again, that´s for sure!

Imagine the user clicking on options:
gamestate switches to gsFadeOutMenu :arrow: screen fades out :arrow: gamestate switches to gsFadeInOptions :arrow: screen fades in :arrow: gamestate switches to gsOptions.

Thats a real nightmare to write and it gets worse with each additional section in the game. Especially if you want cross sections, where you can for example go from the game as well as the menu to the options screen or from the menu as well as from the game to highscorelist.

I dont say its impossible, because I was able to get it to work. Be it with a few dirty tricks.

I'm still not entirely sure what is a good solution. I believe a more OO approach might work, but I still need to work out the details on that, I'm afraid.

Huehnerschaender
15-01-2007, 10:49 PM
I always split my functionality in an update and a render procedure.

So in my gameengine.update I do things like this:



if UI.FadeDir = 1 then
begin
UI.FadeAlpha := min($FF, UI.FadeAlpha + 15*time_);
if UI.FadeAlpha = $FF then
begin
// PERFORM THE REASON FOR FADEOUT HERE (eg change gamestate)
UI.FadeDir := 2;
end;
end;

if UI.FadeDir = 2 then
begin
UI.FadeAlpha := max($0, UI.FadeAlpha - 15*time_);
if UI.FadeAlpha = $0 then
UI.FadeDir := 0;
end;


Then in my UI.render I do this:


if &#40;FadeAlpha <> 0&#41; then
begin
DanJetX.Zbuffer &#58;= false;
DanJetX.Primitives2D.Rectangle&#40;0,0,DanJetX.width,D anJetX.height,trunc&#40;FadeAlpha&#41; shl 24&#41;;
DanJetX.Zbuffer &#58;= true;
end;


The point is, I don't need seperate gamestates for fading out or in. I just set UI.FadeDir to 1 and the show begins.



PS: UI is my UserInterface class... and since this is always rendered after all other things, I perform the rectangle there, embedded in the User Interface. This way I can also set a flag if the whole screen should be faded or only game content and the UI remains...
I think DelphiX has a rectangle function, so this is a really easy task to do.

Damot
16-01-2007, 11:17 AM
I use a "gamestate" system like Traveler and therefore after everything has been rendered surely I only need to change the "darkness" of the screen immediately before the .doflip

So how do I darken the surface quickly by a percentage amount?

Robert Kosek
16-01-2007, 01:19 PM
Did you not read my response, or must I quote myself?
2. The best way is to draw a rectangle over the whole screen for your fade out; you can pick any color you like to make another effect (red pain flashes, white lighting glare, etc) but you must always vary the opacity. And easy way to do so is to use a float value for your fade in/out, 0 is hide and 1 is show, and multiply it by 255 -- for good programming practice wrap that in a "round()" conversion to make certain there wouldn't be an overflow or type assignment bug. Although I forgot you could just use a call to Min and be done with it.Alpha := Min(Round(255*Percent,255)); // Percent is 0.0-1.0

Damot
16-01-2007, 02:30 PM
Did you not read my response, or must I quote myself

No, sorry I did read your reply, but I was sort of looking for something equivalent in DelphiX.

Paizo
16-01-2007, 05:05 PM
Alpha := Min(Round(255*Percent,255)); // Percent is 0.0-1.0

Yep, you print a big rectangle using drawalpha with delphix and for alpha value use the code above

Damot
16-01-2007, 06:02 PM
Alpha := Min(Round(255*Percent,255)); // Percent is 0.0-1.0

Yep, you print a big rectangle using drawalpha with delphix and for alpha value use the code above

Great thanks, I'll experiment. Thanks to everyone for their replies.