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(); } //////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////