Onscreen feedback effect

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search

Written for CEGUI 0.8


Works with versions 0.8.x (stable)

Works with latest CEGUI stable!

This is a simple tutorial on how to make a cool effect for Onscreen Feedback for players in a game.

Examples are when a player gets hit, there is some indicator of the attack (often in First Person Shooters there is some sense of which direction the attack came from, but this won't get that detailed).

This tutorial comes from a vampire game; when the player attacks an NPC to suck his/her blood there is an onscreen effect to indicate the player is successfully feeding off the NPC, this is done by having blood fade on and off the screen.

You could also fade the entire screen to black for transition effects.

First some variables:

CEGUI::Window *BloodScreen; // Window to display blood
bool showBlood; // Bool as to whether blood is shown or not
float bloodTime; // Amount of time blood will be visible on screen
float bloodCount; // Used to set alpha value for fading on/off screen
bool bloodUp; // Whether to add to or subtract from bloodCount

These are pretty straightforward.

These variables need to be setup within either a constructor or initializing method:

bloodCount = 0.0;
bloodUp = false;
showBlood = false;
 
if(!BloodScreen) {
    BloodScreen = CEGUI::WindowManager::getSingleton().createWindow("TaharezLook/StaticImage","BloodUI");
    BloodScreen->setPosition(CEGUI::UVector2(CEGUI::UDim(0, 0), CEGUI::UDim(0, 0)));
    BloodScreen->setSize(CEGUI::USize(CEGUI::UDim(1, 0), CEGUI::UDim(1, 0)));
    BloodScreen->setProperty("Image", "CustomImages/Blood");
    BloodScreen->setAlpha(0);
    BloodScreen->setVisible(false);
    ceguiContext->getRootWindow()->addChild(BloodScreen);
}

This sets up the window to display the blood onscreen; it simply uses a StaticImage in this case from TaharezLook (though you can customize one). The trouble with TaharezLook/StaticImage is that it will have a border around your image as well as a background. You will probably want to make a custom one by simply removing the frames and background. A hacked up version of the TaharezLook will be posted at the end.

Next the size is set by setting the first parameter of each UDim within the USize to 1, this will cause the blood effect to take up the entire screen. Because of this, the position should be top left at 0, 0.

Next an image property is set, which is an image made to show on the screen. You'll want transparency on the image so it doesn't hide too much on screen as this will frustrate players.

Next within a logical update method in your game, you need to check whether the effect needs to be executed:

void Player::update(const flooat timeSinceLastFrame) {
...
if (PLAYER_FEED) { // Check if player attempted to feed
    disableAction(PLAYER_FEED); // Disable feeding action
    feedSuccess(); // Player has fed
}
 
if (showBlood)
    displayBlood(timeSinceLastFrame);
}

This is within the player update method to see if the player has attempted to feed off an NPC, if the player has, then PLAYER_FEED will be true; so you will need to change this to handle events in whichever way you've built you game.

Next is the feedSuccess method:

void Player::feedSuccess() {
    BloodScreen->setVisible(true); // Set BloodScreen visibility to true
    showBlood = true; // show blood is true
    bloodTime = getCurrentTime() + 4000;  // Show blood on screen for 4000 milliseconds
    bloodCount = 0.0; // Blood is off, so it will fade on
}

This method will prepare the related variables so the blood can start to be shown on the screen.

And finally the display blood method:

void Player::displayBlood(const float timeSinceLastFrame) {
    if (bloodTime < getCurrentTime()) { // Check if alotted time has passed
        showBlood = false;              // Set showBlood to false
        BloodScreen->setVisible(false); // Hide blood window
        return;
    }
 
    if (bloodCount <= 0)  // If blood is completely transparent, turn alpha up
        bloodUp = true;
    else if (bloodCount >= 1.0) // Otherwise turn alpha down
        bloodUp = false;
    if (bloodUp)
        bloodCount += 0.4 * timeSinceLastFrame;
    else
        bloodCount -= 0.4 * timeSinceLastFrame;
    BloodScreen->setAlpha(bloodCount);
    BloodScreen->invalidate();
}

Essentially here we check if enough time has passed for displaying the onscreen effect, if it has then we turn it off.

Otherwise we need to check if the alpha of the onscreen effect needs to increase or decrease, this allows for the fade on/off effect.

Next the alpha level is calculated depending on how much time has passed. The alpha level of the window is set and then it's invalidated.

The invalidate() tells CEGUI this window has changed and needs to be redrawn, otherwise nothing will appear to happen.

And all done.