📄 retroengine.cpp
字号:
////////////////////////////////////////////////////////////////////////
//
// RetroEngine.cpp
//
// Copyright (c) 2003 Nokia Mobile Phones Ltd. All rights reserved.
//
////////////////////////////////////////////////////////////////////////
#include "RetroEngine.h"
//System includes
#include <e32math.h>
//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();
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -