UI Animation

UI Animation

So I started working on something that really probably wasn't at all needed at this point, but I decided to work on it anyway. I started adding in UI Animation, such as having a UI element slowly fade out, or fade in, or move across the screen etc.

Splash Screen

For some reason I really wanted to see a nifty splash screen for the app, it is not at all what I should have been working on, but it will still be valuable in the future.

To begin I created a new panel type "AnimatedPanel" that extended my "Panel" class. It provided an additional function AddAnimation.

AddAnimation
This function allows me to provide it with an object (of type Panel), an animation type (opacity, linear move, etc), start and end variables (which will probably change as I get more complex animation types), duration, delay, and an animation callback.

The delay is how long after the panel becomes visible should it wait to start the animation, duration is how long the effect should last, and the callback fires once the animation has finished. For the splashscreen I created an AnimatedPanel, and then created a SubPanel for the actual image, this is what the animation was supplied to.

AddAnimation(m_pSiosphere, t_AnimateOpacity, 1000, 0, 255, 0);
AddAnimation(m_pSiosphere, t_AnimateOpacity, 1000, 255, 0, 3000, Splash::EndAnimation);

I combined two different animations, one fades it in, with a duration of 1 second, and no delay, the second one fades it out in one second, with a delay of 3 seconds, and then calls my end animation callback, which then fires up the main menu

Actually interpolating the variables was rather easy, right now it uses a simple linear approach,

void PanelAnimation::Animate(){
	if(m_bFinished){
		return;
	}
	if(!m_iStartTime){
		m_iStartTime = g_Engine->GetCurTime();
		m_iEndTime = m_iStartTime + m_iDuration;
		m_dCurrent = m_iStart; //we are at our starting value

		int diff = abs(m_iEnd - m_iStart);

		m_fStep = (float) diff / m_iDuration; //this should be taken each step, and then applied
	}

	if(m_iDelay > 0 && g_Engine->GetCurTime() < m_iStartTime + m_iDelay){
		return;
	}

	m_bAnimating = true;

	

	if(m_iEnd > m_iStart){
		m_dCurrent += m_fStep;
	} else{
		m_dCurrent -= m_fStep;
	}

	if((int)m_dCurrent == m_iEnd){
		//we are now finished
		m_bFinished = true;
		m_bAnimating = false;
		if(m_pCallback){
			m_pCallback(m_pPanel);
		}
	}
}

I simply get the difference between the values, and compute a step by taking that difference and dividing it by the duration, this gets me how much it should change for each ms that passes.

To Create the callback, I searched online and combined a few sources, essentially I just did:

typedef void (*animation_callback)(Panel *);

Very simple to create the callback, I then call that at the end of the animation event if it is provided.

This allowed me to rather quickly get a rudimentary animation system for UI, and I will continue to build it out as I need it, but it did motivate me to make a beta menu screen, which was what was displayed at the top.

Touch Events

I also started building out a panel to track touch events, since I\'m prototyping this on a PC, I\'m using the mouse as a proxy, with essentially 3 functions, OnTouchStart, OnTouch, and OnTouchEnd. Using some of the same code as I did on my Button Elements, I detect if the mouse is clicked within the boundaries of the panel, it does the OnTouchStart event if it wasn't already clicked, otherwise it does the OnTouch event. Then once you release it calls the OnTouchEnd event)

To make sure that it worked I just set it up so it would change the opacity of the panel depending on where the cursor was when you clicked and drag. It worked perfectly which I was excited about.

Engine Overview

I think in each post I'll write a little bit about how the whole engine is structured. Essentially it is a series of systems that operate together, right now I have a Renderer, Input Manager, Material Manager, Entity Manager, and UI Manager

//load systems
	m_pRenderer = CreateRenderer();
	g_pRenderer = (Renderer*) m_pRenderer;
	if(!m_pRenderer->Init()){
		return false;
	}
	//load system for our run
	m_aSystems[SYS_RENDERER] = m_pRenderer;


	g_pInputManager = new InputManager();
	g_pInputManager->Init();
	m_aSystems[SYS_INPUT_MANAGER] = g_pInputManager;

	g_pMaterialManager = new MaterialManager();
	g_pMaterialManager->Init();
	m_aSystems[SYS_MATERIAL_MANAGER] = g_pMaterialManager;

	g_pEntityManager = new EntityManager();
	g_pEntityManager->Init();
	m_aSystems[SYS_ENTITY_MANAGER] = g_pEntityManager;

	g_pUIManager = new UIManager();
	g_pUIManager->Init();
	m_aSystems[SYS_UI_MANAGER] = g_pUIManager;

I load them up in the initalization, then once they are all created, it goes through them and does a PreRun event for each, and then they are ready to go and be used.

void Engine::Run(){
	while(m_pRenderer->IsDrawing()){
		m_pGame->Run(); //game logic
		for(int i = 1; i < NUM_SYSTEMS; i++){
			m_aSystems[i]->Run();
		}
		
		for(int i = 1; i < NUM_SYSTEMS; i++){
			m_aSystems[i]->AfterRun();
		}
	}
}

My Engine Run Loop is very simple, as long as the game is drawing, it will do the game logic, which is controlled in a separate dll/exe/lib and then go through all the systems and run those, and then do an after run.

This setup will also allow me to do a multi-threaded application rather easily, as I could split off various systems into their own threads at anytime, but for the project I am working on, it is not needed.

Comments
comments powered by Disqus