Scrolling Message         Scrolling messages based on Simple Text Output

Table of contents

Introduction

This is a very simple class that was written in less than 2 hours but is very useful in providing a simple, cool effect. This class is inspired by another code snippet - Simple text. So I took some of the code and merged it with my own and... tadaa... here we are!

The class basically will have 3 lines of messages which can be added by calling the addText() member function. So the old lines (the original line 1, 2 and 3) will be scrolled down and line 3 will be slowly faded out and new comes at the top. Of course you do not have to limit to 3 lines of messages - feel free to increase or decrease the number as the source code is extremely simple ;)

Usage

Firstly, you have to call init() prior to using the class. I didn't include it in the constructor because Ogre may not have been initialized yet.
And then in any of the FrameListener's frameStarted(), call loop member function for example:

mScrollingMessage.loop(evt.timeSinceLastFrame);

Since this is a singleton, you can call the class anywhere and add text to it, eg:

ScrollingMessage::getSingleton().addText("Hello Moto!");

That's all about it.

ScrollingMessage.h

#pragma once

#include <Ogre.h>

class ScrollingMessage : public Ogre::Singleton<ScrollingMessage>
{
protected:
    Ogre::OverlayContainer* mPanel;
    Ogre::Overlay* mOverlay;
    Ogre::OverlayElement* mTextBox[3];
    Ogre::Real mTimeToGo;
    bool mJustAdded;

    // all are in pixel
    enum { POSITION_TOP_X = 5, POSITION_TOP_Y = 30, SPACING = 30 };

public:
    ScrollingMessage();
    void init();
    void addText(const Ogre::String& text);
    void loop(Ogre::Real time);
};


ScrollingMessage.cpp

#include "ScrollingMessage.h"

using namespace Ogre;

template<> ScrollingMessage* Singleton<ScrollingMessage>::ms_Singleton = 0;

ScrollingMessage::ScrollingMessage()
{
    mTimeToGo = 0.0;
    mJustAdded = false;
}

void ScrollingMessage::init()
{
    mOverlay = OverlayManager::getSingleton().create("ScrollingOverlay");

    mPanel = static_cast<OverlayContainer*>(OverlayManager::getSingleton().createOverlayElement("Panel", "container1"));
    mPanel->setMetricsMode(GMM_PIXELS);
    mPanel->setDimensions(800, 400);
    mPanel->setPosition(5, 30);

    // now create the text...
    String name;
    for (int i = 0; i < 3; ++i) {
        name = "ScrollingMessage"+StringConverter::toString(i);
        mTextBox[i] = OverlayManager::getSingleton().createOverlayElement("TextArea", name);
        mTextBox[i]->setMetricsMode(Ogre::GMM_PIXELS);
        mTextBox[i]->setDimensions(20, 5);        
        mTextBox[i]->setWidth(20);
        mTextBox[i]->setHeight(5);

        mTextBox[i]->setPosition(POSITION_TOP_X, POSITION_TOP_Y+i*SPACING);
        mTextBox[i]->setParameter("font_name", "StarWars");
        mTextBox[i]->setParameter("char_height", "16");
        mTextBox[i]->setColour(ColourValue::White);
        mTextBox[i]->setCaption(" ");
        mPanel->addChild(mTextBox[i]);
    }
    mOverlay->add2D(mPanel);

    mOverlay->show();
}

void ScrollingMessage::addText(const String& text) 
{
    // first swap the content...
    mTextBox[2]->setCaption(mTextBox[1]->getCaption());
    mTextBox[1]->setCaption(mTextBox[0]->getCaption());
    mTextBox[0]->setCaption(text);
    // but hide the first textbox first...
    mTextBox[0]->hide();
    // and move the others to upper coordinate...
    mTextBox[1]->setPosition(POSITION_TOP_X, POSITION_TOP_Y);
    mTextBox[2]->setPosition(POSITION_TOP_X, POSITION_TOP_Y+SPACING);
    mTimeToGo = 1.5; // 1.5 seconds...
    mJustAdded = true;
}

void ScrollingMessage::loop(Real time) 
{
    if (mJustAdded) {
        mTimeToGo -= time;
        if (mTimeToGo <= 1.0)
            mTextBox[0]->show();
        if (mTimeToGo < 1e-3) {
            mTimeToGo = 0.0;
            mJustAdded = false;
        }
        // scroll the textbox by this much..
        Real progress = (1.5-mTimeToGo)/1.5;
        Real y = POSITION_TOP_Y+SPACING*progress;
        mTextBox[1]->setPosition(POSITION_TOP_X, y);
        mTextBox[1]->setColour(ColourValue(1,1,1,1.0-progress/4));
        mTextBox[2]->setPosition(POSITION_TOP_X, y+SPACING);
        mTextBox[2]->setColour(ColourValue(1,1,1,1.0-progress*progress));
    }
}