Legend of Bob: Title Screen
The day of the hand was today, so myself and my housemates did an all nighter to add the finishing touches to our AGT projects, and despite not liking coffee, by the end of the night I was drinking it.
One of my housemates, Johnny, made me a great loading screen and title screen. The loading screen, would have been better if the candle flickered, but I didn't have time to multithread it.
More research is needed to know if Ogre3D can be multithreaded safely.
The title screen is just as basic as the loading screen, after I created a Lua script to control it. It has only two options, "Start New Game" and "Exit".
I wish, as with the loading screen I had time to improve it, maybe some ambient music for the background, and the ability to save and load.
Legend of Bob: Bloom and Cel Shading
I finally rewrote my Cel Shading shader from DirectX to Cg, giving a very nice effect compared with the old one. The one I was using previously was per vertex shading, which gave an ugly look, however the one I've converted over from DirectX I wrote a while ago uses per pixel shading.
However there is a downside, the black outline edge is current done by drawing backfaces in wireframe with line thickness, the lower the anti-aliasing, the worse it appears. I'm thinking that if I use the depth buffer I can generate my own outlines based on depth change per pixel.
I have also modified the texture splat ARGB map to be smoother and use more toon like textures rather than realistic to go more with the overall theme of the game.
The contrast before was noticable, however the lack of shadows does give the impression now that the character is hovering above the ground, so I added basic shadows to solve this.
To finish off the post process effects, I added a Bloom shader.
Early Bird Gets the Worm, but Second Mouse Gets the Cheese
Lots more work done on Tales of Phantasia last night, animations, NPC interaction and a bit more framework optimization. Screenshots to be added soon.
Not only did I do that, but I finally got around to putting the finishing touches to my event system, now it now the type of variable that is being set, and I also finally found a use for template functions (thats right, functions, not classes, didn't know they existed til last month).
What use you say? Quick function overloading, not really much point, but it saves the hassle of type casts. I'm currently using a 32bit unsigned integer for storing the variable type, which gives me 32 potential arguments for my events, I only use 5 at the moment, and I think I can remove one of them.
template<typename T>
void SetArgumentAsNumber( const unsigned int inIndex, const T inValue )
{
Arg[inIndex].d = (double)inValue;
m_type &= ~( 1 << inIndex );
}
void SetArgumentAsString( const unsigned int inIndex, const char *string )
{
Arg[inIndex].text = string;
m_type |= ( 1 << inIndex );
}
bool IsArgumentAString( const unsigned int inIndex ) const
{
return ( m_type & ( 1 << inIndex ) ) ? true : false;
}
Legend of Bob: Night
After a bit of thinking, I've decided that it would be better if the game was in a night time mode.
So I've changed the skybox for my AGT project to be of a night sky with stars.
I've also reduced the fog near and far distance to be closer, and then darkened the colour. These worked together quite well, and the night effect was achieved.
I think with a bit of Bloom, the snow would look great like this.
Legend of Bob: Snow
I decided to change the grass texture to a snow texture, and make the town a snowy scene. However it didn't look right. So I decided to add a snow particle effect.
The snowflakes are additive and alpha blended, and so give a glow, and stop at ground level, this is ruining slightly with the river since it is just slightly less than ground level.
Also the fact that a vertex shader is being for the water to make it look like it is moving, the snow shouldn't settle on it, but it does.
Unfortunately that is not much I can do about it, at some point I may go through and setup multiple emitters that bypass the areas that the snow has a problem with, or adjust it so that it stops at a different ground level.
Legend of Bob: Playing Sound with FMOD
A few month ago I gave up on the idea on using OpenAL for playing sound effect since trying to get MP3s to play with it was getting annoying. A friend recommended whilst in the Student Union to use FMOD, so I switched over and found it did everything I needed, plus there was plenty of documentation and examples.
So here is some basic code for getting audio playing using FMOD, as well as a few additional functions. I've only allocated blocks for playing 10 sounds (if more than 10 sounds are attempted to be loaded, LoadSoundByFile() returns -1).
Here is the header for my sound manager.
#ifndef SOUNDMANAGER_H_INCLUDED
#define SOUNDMANAGER_H_INCLUDED
// --- [ libraries ] ------------------------------------------
#pragma comment(lib, "fmodex_vc.lib")
// --- [ includes ] -------------------------------------------
#include <fmod.hpp>
// --- [ definitions ] ----------------------------------------
#define SOUND_LOOP_INFINITE -1
#define MAX_NUM_SOUNDS 10
// --- [ class ] ----------------------------------------------
class SoundManager
{
// Attributes
private
FMOD::System * m_pSystem;
FMOD::Sound * m_pSound[MAX_NUM_SOUNDS];
// Functions
public:
// Constructor
SoundManager();
// Destructor
~SoundManager();
// Load Sound from File
int LoadSoundFromFile( const char * inFilename );
// Free Sound
void FreeSound( const int inSoundId );
// Play Sound
void PlaySound( const int inSoundId );
// Set Position
void SetSoundPosition( const int inSoundId, const int inPositionInMilliseconds );
// Set Loop Count
void SetSoundLoopCount( const int inSoundId, const int inCount );
// Set Loop Points
void SetSoundLoopPoints( const int inSoundId, const int inStartInMilliseconds, const int inEndInMilliseconds );
};
#endif
For background music, I've also included code so that the sound can be looped forever, and since not all sounds will be looping from the beginning, I've added a function to set where the loop repeats from and begins again. When a sound is not being used anymore, FreeSound() should be called for the id returned by LoadSoundFromFile().
// --- [ includes ] -------------------------------------------
#include "SoundManager.h"
// --- [ constructor / destructor ] ---------------------------
SoundManager::SoundManager()
{
for( unsigned int i = 0; i < MAX_NUM_EFFECTS; ++i )
{
m_pSound[i] = 0;
}
// Create FMOD SoundSystem
FMOD::System_Create( &m_pSystem );
// Check FMOD Version
unsigned int fmodVersion;
m_pSystem->getVersion( &fmodVersion );
assert( fmodVersion >= FMOD_VERSION )
// Initialize FMOD SoundSystem
m_pSystem->init(32, FMOD_INIT_NORMAL, 0);
}
SoundManager::~SoundManager()
{
// Free FMOD Sounds
for( unsigned int i = 0; i < MAX_NUM_SOUNDS; ++i )
{
if( m_pSound[i] )
{
m_pSound[i]->release();
}
}
// Free FMOD SoundSystem
if( m_pSystem )
{
m_pSystem->close();
m_pSystem->release();
m_pSystem = 0;
}
}
// --- [ functions ] ------------------------------------------
int SoundManager::LoadSoundFromFile( const char * inFilename )
{
for( int i = 0; i < MAX_NUM_SOUNDS; ++i )
{
if( !m_pSound[i] )
{
m_pSystem->createSound( inFilename, FMOD_SOFTWARE, 0, &m_pSound[i] );
return i;
}
}
return -1;
}
void SoundManager::FreeSound( const int inSoundId )
{
assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
if( m_pSound[inSoundId] )
{
m_pSound[inSoundId]->release();
m_pSound[inSoundId] = 0;
}
}
void SoundManager::PlaySound( const int inSoundId )
{
assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
if( m_pSound[inSoundId] )
{
FMOD::Channel * channel;
m_pSystem->playSound( FMOD_CHANNEL_FREE, m_pSound[inSoundId], false, &channel );
}
}
void SetSoundPosition( const int inSoundId, const int inPositionInMilliseconds )
{
assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
if( m_pSound[inSoundId] )
{
m_pSound[inSoundId]->setPosition( inPositionInMilliseconds, FMOD_TIMEUNIT_MS );
}
}
void SoundManager::SetSoundLoopCount( const int inSoundId, const int inCount )
{
assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
if( m_pSound[inSoundId] )
{
m_pSound[inSoundId]->setLoopCount( inCount );
}
}
void SoundManager::SetSoundLoopPoints( const int inSoundId, const int inStartInMilliseconds, const int inEndInMilliseconds )
{
assert( inSoundId >= 0 && inSoundId < MAX_NUM_SOUNDS );
if( m_pSound[inSoundId] )
{
m_pSound[inSoundId]->setLoopPoints( inStartInMilliseconds, FMOD_TIMEUNIT_MS, inEndInMilliseconds, FMOD_TIMEUNIT_MS );
}
}
All timing in my code is in milliseconds, but it can be changed to another supported FMOD time unit.



