Onscreen feedback effect
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.