www.pudn.com > 2DGameAnimS60C_v1_0.zip > RetroEngine.cpp


//////////////////////////////////////////////////////////////////////// 
// 
// RetroEngine.cpp 
// 
// Copyright (c) 2003 Nokia Mobile Phones Ltd.  All rights reserved. 
// 
//////////////////////////////////////////////////////////////////////// 
 
#include "RetroEngine.h" 
 
//System includes 
#include  
 
//User includes 
#include "KeyHandler.h" 
#include "ImageFactory.h" 
#include "DoublebufferedArea.h" 
#include "RenderableFactory.h" 
#include "BaseAnim.h"          
#include "BitmapAnimFrame.h"   
#include "BitmapTile.h"        
#include "FireAnim.h"          
#include "ParticleSystem.h"    
#include "RetroLeafTileset.h"  
#include "RetroNodeTileset.h"  
#include "ShipAnim.h"          
#include "Tilemap.h"           
#include "Tileset.h"           
#include "GameTimer.h" 
 
//////////////////////////////////////////////////////////////////////// 
//////////////////////////////////////////////////////////////////////// 
 
CRetroEngine* CRetroEngine::NewLC(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow,TKeyHandler& aKeyHandler, CImageFactory& aImageFactory, const TSize& aSize) 
	{ 
	CRetroEngine* self = new (ELeave) CRetroEngine(aClient, aScreenDevice, aWindow, aKeyHandler, aImageFactory, aSize); 
	CleanupStack::PushL(self); 
	self->ConstructL(); 
	return self; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
CRetroEngine* CRetroEngine::NewL(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow,TKeyHandler& aKeyHandler, CImageFactory& aImageFactory, const TSize& aSize) 
	{ 
	CRetroEngine* self = CRetroEngine::NewLC(aClient, aScreenDevice, aWindow, aKeyHandler, aImageFactory, aSize); 
	CleanupStack::Pop(); 
	return self; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
CRetroEngine::CRetroEngine(RWsSession& aClient, CWsScreenDevice& aScreenDevice, RWindow& aWindow,TKeyHandler& aKeyHandler, CImageFactory& aImageFactory, const TSize& aSize) : 
	iClient(aClient), 
	iScreenDevice(aScreenDevice), 
	iWindow(aWindow), 
	iKeyHandler(aKeyHandler), 
	iImageFactory(aImageFactory), 
	iSize(aSize), 
	iDropRenderFrames(ETrue), // Set to "EFalse" to demonstrate ViewSrv 11 problem 
	iFrameCounter(0) 
	{ 
	} 
 
//////////////////////////////////////////////////////////////////////// 
	 
void CRetroEngine::ConstructL() 
	{ 
	iPlaying = EFalse; 
 
	iGameTimer = CGameTimer::NewL(*this); 
	// Direct screen access 
	iDirectScreenAccess = CDirectScreenAccess::NewL(iClient, iScreenDevice, iWindow, *this); 
 
//	ConstructSimpleMapL(); 
	ConstructCompoundMapL(); 
	ConstructShipL(); 
 
	iDoubleBufferedArea = CDoubleBufferedArea::NewL(iSize, EColor4K); 
	iOffscreenContext = &(iDoubleBufferedArea->GetDoubleBufferedAreaContext()); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
CRetroEngine::~CRetroEngine() 
	{ 
	delete iGameTimer; 
	iGameTimer = NULL; 
	 
	delete iDirectScreenAccess; 
	iDirectScreenAccess = NULL; 
	 
	delete iDoubleBufferedArea; 
	iDoubleBufferedArea = NULL; 
 
	delete iMap; 
	iMap = NULL; 
 
	delete iNodeFactory; 
	iNodeFactory = NULL; 
	 
	delete iLeafFactory; 
	iLeafFactory = NULL; 
	 
	delete iEngineExhaust; 
	iEngineExhaust = NULL; 
 
	delete[] iShipVectors; 
	iShipVectors = NULL; 
 
	delete iShipAnim; 
	iShipAnim = NULL; 
	 
	delete iFireAnim; 
	iFireAnim = NULL; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::ConstructSimpleMapL() 
    { 
	TInt mapData[] =  
		{ 
		0,4,0,4,0,4,0,4,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,0,5,2,4,0,4,0,4,0,4,0, 
		0,4,0,4,0,5,3,6,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,1,7,2,4,0,4,0,4,0,4,0, 
		0,4,0,4,0,4,1,6,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,0,4,0,4,0,4,0,4,0,4,0, 
		0,4,0,4,0,4,0,4,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,0,4,0,4,0,4,0,4,0,4,0, 
		0,4,0,4,0,4,0,4,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,0,4,0,4,0,4,0,4,0,4,0, 
		0,4,0,4,0,4,0,4,0,4,0,4,0,4,0,4, 
		4,0,5,2,4,0,4,0,4,0,4,0,5,2,4,0, 
		0,4,1,6,0,4,0,4,0,4,0,4,1,6,0,4, 
		4,0,5,2,4,0,4,0,4,0,4,0,4,0,4,0, 
		0,4,1,6,0,4,0,4,0,4,0,4,0,4,0,4, 
		4,0,4,0,4,0,4,0,4,0,4,0,4,0,4,0, 
		}; 
 
	iShipBounds		= TRect(TPoint(0x00000800,0x00000800),TPoint(0x00001800,0x00001800)); 
	iShipWorldPos	= iShipBounds.Center(); 
	iShipVelocity	= TPoint(0x000e,0x0013); 
 
	iLeafFactory = CRetroLeafTileset::NewL(iImageFactory.TileImage()); 
	iMap = CTilemap::NewL(16,16,&mapData[0],*iLeafFactory); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::ConstructCompoundMapL() 
    { 
	TInt mapData[] =  
		{ 
		15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 
		15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 
		15,15, 7, 3,11,15, 7, 3, 3, 3, 3, 3, 3,11,15,15, 
		15,15, 5, 0, 2, 3, 1, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 8, 4, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 8, 4, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 2, 9, 4, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 0, 2, 1, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,10,15,15, 
		15,15,13,12,12,12,12,12,12,12,12,12,12,14,15,15, 
		15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 
		15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 
		}; 
 
	iShipBounds		= TRect(TPoint(0x00000800,0x00000800),TPoint(0x00007800,0x00007800)); 
	iShipWorldPos	= iShipBounds.Center(); 
 
	iLeafFactory = CRetroLeafTileset::NewL(iImageFactory.TileImage()); 
	iNodeFactory = CRetroNodeTileset::NewL(*iLeafFactory); 
	iMap = CTilemap::NewL(16,16,&mapData[0],*iNodeFactory); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::ConstructShipL() 
	{ 
	iShipVelocity	= -TPoint(0x000e,0x0013); 
 
	iShipFrame = 8; 
	iShipScreenPos = TPoint(88,104); 
	iShipScreenPosUp4 = TPoint(iShipScreenPos.iX << 4, iShipScreenPos.iY << 4); 
 
	iShipAnim = CShipAnim::NewL(iImageFactory.ShipAnim()); 
	iFireAnim = CFireAnim::NewL(iImageFactory.FireAnim()); 
 
	iEngineExhaust = CParticleSystem::NewL(16,*iFireAnim); 
 
	// Physics parameters for ship motion: 
	iDragDownshift = 8; 
	iDragRatio = 0xff; 
	iThrust = 6; 
	iGravity = 1; 
 
 
	// Allocate and initialise ship vectors 
	// (each one a vector lying along the central axis of the ship 
	// in the corresponding animation frame): 
	iShipVectors = new TVectorFP[64]; 
	User::LeaveIfNull(iShipVectors); 
 
	TReal degreesToRadians = 3.141592 / 180.0; 
 
	// Animation frame #0 is at 45 degrees, so: 
	TReal angle = 45.0 * degreesToRadians; 
	TReal angleStep = ( 360.0 / 64.0 ) * degreesToRadians; 
 
	for ( TInt frame = 0 ; frame < 64 ; frame++ ) 
		{ 
		TReal cos; 
		TReal sin; 
 
		Math::Cos(cos,angle); 
		Math::Sin(sin,angle); 
 
		TInt16 cosFP; 
		TInt16 sinFP; 
 
		Math::Int(cosFP,cos * 256.0); 
		Math::Int(sinFP,sin * 256.0); 
 
		iShipVectors[frame] = TVectorFP(TPoint(cosFP,sinFP)); 
 
		angle += angleStep; 
		} 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::Simulate() 
	{ 
	UpdatePosition(); 
	iEngineExhaust->Simulate(); 
 
	if( iKeyHandler.Direction() == TKeyHandler::ELeft ) 
		{ 
		iShipFrame--; 
		} 
	else if ( iKeyHandler.Direction() == TKeyHandler::ERight ) 
		{ 
		iShipFrame++; 
		} 
 
	if (iKeyHandler.FirePressed()) 
		{ 
		iEngineExhaust->Generate(iShipWorldPos,iShipVectors[iShipFrame],iShipVelocity,13 << 4,128); 
		} 
 
	iShipFrame &= 0x3f; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::UpdatePosition() 
	{ 
 
	if (iKeyHandler.FirePressed()) 
		{ 
			TPoint deltaV = iShipVectors[iShipFrame].ScaleToPoint(-iThrust); 
			iShipVelocity += deltaV; 
		} 
 
	TInt vSquared = ( iShipVelocity.iX * iShipVelocity.iX ) + ( iShipVelocity.iY * iShipVelocity.iY ); 
 
	TInt dragRatio = iDragRatio; 
 
	if ( vSquared < 1024 ) 
		{ 
		// Very slow - no drag needed: 
		dragRatio = 0x0100; 
		} 
	else if ( vSquared > 4096 ) 
		{ 
		// Fast - apply strong drag: 
		dragRatio = 0x00fc; 
		} 
	else if ( vSquared > 8192 ) 
		{ 
		// Very fast - apply stronger drag: 
		dragRatio = 0x00f0; 
		} 
 
	if ( vSquared > 1024 ) 
	{ 
		iShipVelocity.iX = ( iShipVelocity.iX * dragRatio ) >> iDragDownshift; 
		iShipVelocity.iY = ( iShipVelocity.iY * dragRatio ) >> iDragDownshift; 
	} 
 
	iShipVelocity.iY += iGravity; 
 
	TPoint newWorldPos = iShipWorldPos + iShipVelocity; 
 
	if ( iShipBounds.Contains(newWorldPos) ) 
		{ 
		iShipWorldPos = newWorldPos;	 
		} 
	else 
		{ 
		if ( ( newWorldPos.iX < iShipBounds.iTl.iX ) || ( newWorldPos.iX >= iShipBounds.iBr.iX ) ) 
			{ 
			iShipVelocity.iX = -iShipVelocity.iX; 
			} 
 
		if ( ( newWorldPos.iY < iShipBounds.iTl.iY ) || ( newWorldPos.iY >= iShipBounds.iBr.iY ) ) 
			{ 
			iShipVelocity.iY = -iShipVelocity.iY; 
			} 
		} 
 
	iMapWindowTopLeft = iShipWorldPos - iShipScreenPosUp4; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::Render(const TRect& aRect,CFbsBitGc* aCallerGc) const 
	{ 
	TPoint pixelTopLeft(iMapWindowTopLeft.iX >> 4,iMapWindowTopLeft.iY >> 4); 
	iMap->Render(pixelTopLeft,aRect,aCallerGc); 
 
 
	iEngineExhaust->Render(pixelTopLeft,aRect,aCallerGc); 
	iShipAnim->RenderFrameCentered(iShipFrame,iShipScreenPos,aRect,aCallerGc); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::SetupDirectScreenAccessL() 
	{ 
	// Initialise DSA 
	iDirectScreenAccess->StartL(); 
 
	// Get graphics context for it 
	iGc = iDirectScreenAccess->Gc(); 
 
	// Get region that DSA can draw in 
	iRegion = iDirectScreenAccess->DrawingRegion(); 
 
	// Set the display to clip to this region 
	iGc->SetClippingRegion(iRegion); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::StartFirstGameL() 
	{ 
	StartGameL(); 
	// We only want to play the game if we have the whole screen available so  
	// on first start we record the region available for comparision later (in restart) 
	iGameDawingArea = iRegion->BoundingRect(); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::StartGameL() 
	{ 
	iPaused = EFalse; 
	if(!iPlaying) 
		{ 
		SetupDirectScreenAccessL(); 
		iGameTimer->Restart(); 
		} 
	iPlaying = ETrue; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::StopGame() 
	{ 
	iPlaying = EFalse; 
	iPaused = ETrue; 
	iGameTimer->CancelTimer(); 
	iDirectScreenAccess->Cancel(); 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
TInt CRetroEngine::DoGameFrame() 
	{ 
	// Force screen update: 
	iDirectScreenAccess->ScreenDevice()->Update(); 
 
	Simulate(); 
 
	// Drop 1 render frame in every 128, to avoid ViewSrv 11 problems: 
	if (iDropRenderFrames & ((iFrameCounter & 0x007f) != 0x007f)) 
		{ 
		Render(iGameDawingArea, iOffscreenContext); 
		} 
 
	iFrameCounter++; 
 
	// Draw from offscreen bitmap 
	iGc->BitBlt(TPoint(0,0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap())); 
 
	iClient.Flush();	 
 
	if(iPaused) 
		{ 
		return CGameTimer::StopTicking; 
		} 
	else 
		{ 
		return CGameTimer::TickAgain; 
		} 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::Restart(RDirectScreenAccess::TTerminationReasons /*aReason*/) 
	{ 
	// Restart display 
	// Note that this will result in the clipping region being updated 
	// so that menus, overlaying dialogs, etc. will not be drawn over 
	SetupDirectScreenAccessL(); 
	if(iPaused) 
		{ 
		if(iGameDawingArea == iRegion->BoundingRect()) 
			{ 
			iPaused = EFalse;	 
			if(!iGameTimer->IsActive()) 
				{ 
				iGameTimer->Restart(); 
				} 
			} 
		else 
			{ 
			PauseFrame(); 
			} 
		} 
	else 
		{ 
		if(!iGameTimer->IsActive()) 
			{ 
			iGameTimer->Restart(); 
			} 
		} 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::AbortNow(RDirectScreenAccess::TTerminationReasons /*aReason*/) 
	{ 
	// Cancel timer and display 
	iDirectScreenAccess->Cancel(); 
	iPaused = ETrue; 
	} 
 
//////////////////////////////////////////////////////////////////////// 
 
void CRetroEngine::PauseFrame() 
	{ 
	// Force screen update: this is required for WINS, but may 
	// not be for all hardware: 
	iDirectScreenAccess->ScreenDevice()->Update(); 
 
	// and draw from unchanged offscreen bitmap 
	iGc->BitBlt(TPoint(0,0), &(iDoubleBufferedArea->GetDoubleBufferedAreaBitmap())); 
 
	iClient.Flush();		 
	} 
 
//////////////////////////////////////////////////////////////////////// 
////////////////////////////////////////////////////////////////////////