📄 cgame.cpp
字号:
/*
*
============================================================================
* Name : CGame.cpp
* Part of : Example3D
* Created : 12/14/2003 by Forum Nokia
* Description:
* This is the project specification file for Example3D.
* Initial content was generated by Series 60 AppWizard.
*
* Version : 1.0.0
* Copyright: Forum Nokia
*
============================================================================
*/
// INCLUDES
#include "CGame.h"
#include "CPictureLoader.h"
#include "C3DBase.h"
#include "C3DRenderer.h"
#include "CPolygonObject.h"
#include <e32math.h>
#include <eikenv.h>
#include "3DObjects.h"
#include <e32svr.h>
#include <eikenv.h>
#include <eikappui.h>
#include <eikapp.h>
// CONSTANTS
const TInt KFrontWheelRadius = 100;
const TInt KRearWheelRadius = 150;
const TInt KRideHeight = 100; // car ride height
const TInt KTileSize = 3000; // tile size in 3D-space
// MEMBER FUNCTIONS
CGame* CGame::NewL( TDisplayMode aDisplayMode, const TBitmap& aScreen )
{
CGame* self = new( ELeave )CGame( aDisplayMode );
CleanupStack::PushL( self );
self->ConstructL( aScreen );
CleanupStack::Pop( self );
return self;
}
CGame::~CGame()
{
delete iTexture.iData;
delete iTexture2.iData;
delete i3DBase;
delete iRender;
delete i3dHouse;
delete i3dCar;
delete i3dRoad;
delete i3dGrass;
delete i3dFrontWheel;
delete i3dRearWheel;
}
void CGame::ConstructL( const TBitmap& aScreen )
{
//
// load texture
//
CPictureLoader* loader = CPictureLoader::NewL();
CleanupStack::PushL( loader );
iTexture = loader->LoadL( _L("picture.jpg"), iDisplayMode );
iTexture2 = loader->LoadL( _L("picture2.jpg"), iDisplayMode );
CleanupStack::PopAndDestroy( loader );
//
// construct 3D base classes
//
i3DBase = C3DBase::NewL( aScreen.iSize );
iRender = C3DRenderer::NewL( i3DBase, 1000 );
//
// create 3D-objects
//
// house
i3dHouse = CreateObject( KHouseVertexData, KHouseFaceData, KNumHouseVertices, KNumHouseFaces,
TPoint( 0,0 ), 1 );
i3dHouse->SetTexture( (TUint16*)iTexture2.iData );
// road
i3dRoad = CreateObject( KRoadVertexData, KRoadFaceData, KNumRoadVertices, KNumRoadFaces,
TPoint( 0,0 ), 1 );
i3dRoad->SetTexture( (TUint16*)iTexture.iData );
// grass tile
i3dGrass = CreateObject( KGrassVertexData, KGrassFaceData, KNumGrassVertices, KNumGrassFaces,
TPoint( 0,0 ), 1 );
i3dGrass->SetTexture( (TUint16*)iTexture2.iData );
// wheels
i3dFrontWheel = CreateWheel( KFrontWheelRadius, 50, 6 );
i3dFrontWheel->SetTexture( (TUint16*)iTexture.iData );
i3dRearWheel = CreateWheel( KRearWheelRadius, 150, 6 );
i3dRearWheel->SetTexture( (TUint16*)iTexture.iData );
// car
i3dCar = CreateObject( KCarVertexData, KCarFaceData, KNumCarVertices, KNumCarFaces,
TPoint( 0,128 ), 10 );
i3dCar->SetTexture( (TUint16*)iTexture.iData );
//
// add objects to renderer
//
TInt n;
n = iRender->AddObject( i3dRearWheel );
n = iRender->AddObject( i3dFrontWheel );
n = iRender->AddObject( i3dRearWheel );
n = iRender->AddObject( i3dFrontWheel );
n = iRender->AddObject( i3dCar );
iRender->SetObjectPosition( n, TVertex( 0, -300,4250 ) );
iRender->SetObjectAngle( n, TVertex( 0, 0, 0 ) );
TInt y;
TInt x;
//
// Tilemapped city
//
for( y=0; y<KMapHeight; y++ )
{
TUint8* p = (TUint8*)KMap[ y ];
for( x=0; x<KMapWidth; x++ )
{
switch( *p++ )
{
case '0':
{
n = iRender->AddObject( i3dRoad );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 0, 0 ) );
iRender->SetObjectPriority( n, 0x7000000 );
break;
}
case '1':
{
n = iRender->AddObject( i3dRoad );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 1024, 0 ) );
iRender->SetObjectPriority( n, 0x7000000 );
break;
}
case '2':
{
n = iRender->AddObject( i3dRoad );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 2048, 0 ) );
iRender->SetObjectPriority( n, 0x7000000 );
break;
}
case '3':
{
n = iRender->AddObject( i3dRoad );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 3072, 0 ) );
iRender->SetObjectPriority( n, 0x7000000 );
break;
}
case 'a':
{
n = iRender->AddObject( i3dHouse );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 0, 0 ) );
iRender->SetObjectPriority( n, 0 );
break;
}
case 'x':
{
n = iRender->AddObject( i3dGrass );
iRender->SetObjectPosition( n,
TVertex( x * KTileSize, 200, y * KTileSize ) );
iRender->SetObjectAngle( n, TVertex( 0, 0, 0 ) );
iRender->SetObjectPriority( n, 0x7000000 );
break;
}
}
}
}
// some initializations
// start from tile 2,2 ( x,y on map )
iCarPosition = TVertex( KTileSize * 2, 0, KTileSize * 2 );
iCarPositionAdd = TVertex( 0,0,0 );
iCarSpeed = 0;
iCameraMode = ECameraSouth;
i3dHouse->Init();
i3dCar->Init();
i3dRoad->Init();
i3dGrass->Init();
i3dFrontWheel->Init();
i3dRearWheel->Init();
}
CGame::CGame( TDisplayMode aDisplayMode )
: iDisplayMode( aDisplayMode )
{
}
void CGame::Draw( const TBitmap& aScreen )
{
// this would clear the screen
// not needed; 3D is drawn to whole screen
Mem::FillZ( aScreen.iData, aScreen.iSize.iWidth * aScreen.iSize.iHeight * 2 );
TInt ang = iCarAngleSpeed*5;
TInt carAngle = ang + iCarAngle;
// calculate wheel positions in space
TVertex v;
v = TVertex( -500, -KRearWheelRadius, 350 );
v = i3DBase->RotateY( v, carAngle );
v += iCarPosition;
iRender->SetObjectPosition( 0, v );
v = TVertex( 500, -KFrontWheelRadius, 300 );
v = i3DBase->RotateY( v, carAngle );
v += iCarPosition;
iRender->SetObjectPosition( 1, v );
v = TVertex( -500, -KRearWheelRadius, -350 );
v = i3DBase->RotateY( v, carAngle );
v += iCarPosition;
iRender->SetObjectPosition( 2, v );
v = TVertex( 500, -KFrontWheelRadius, -300 );
v = i3DBase->RotateY( v, carAngle );
v += iCarPosition;
iRender->SetObjectPosition( 3, v );
// turn wheels to right direction ( car's direction )
// add steering angle to front wheels
// also turn wheels by iCarPos
iRender->SetObjectAngle( 0, TVertex( 0, carAngle + ( KSinTableSize/2 ), -iCarPos*2 ) );
iRender->SetObjectAngle( 1, TVertex( 0, -iSteerAngle*4 + carAngle + ( KSinTableSize/2 ), -iCarPos*3 ) );
iRender->SetObjectAngle( 2, TVertex( 0, carAngle, iCarPos*2 ) );
iRender->SetObjectAngle( 3, TVertex( 0, -iSteerAngle*4 + carAngle, iCarPos*3 ) );
if( iCarSpeed < 0 ) ang = -ang;
// tilt car
iRender->SetObjectAngle( 4, TVertex( ang, carAngle, -iThrottle * 50 ) );
// and set car position in space
iRender->SetObjectPosition( 4, iCarPosition + TVertex( 0,-KRideHeight, 0 ) );
// calculate camera position
TInt speed = iCarSpeed;
if( speed < 0 ) speed = -speed;
switch( iCameraMode )
{
case ECameraBehind:
{
TVertex camPos( 5000 + speed * 25, -( 3000 + speed * 15 ), 00 );
camPos = i3DBase->RotateY( camPos, ( iCarAngle + KSinTableSize/2 ) );
iRender->SetCameraPosition( iCarPosition + camPos );
iRender->SetCameraAngle( TVertex( 300, -( iCarAngle - KSinTableSize/4 ), 0 ) );
break;
}
case ECameraSouth:
{
TVertex camPos( 0, -( 3000 + speed * 15 ), -( 5000 + speed * 25 ) );
iRender->SetCameraPosition( iCarPosition + camPos );
iRender->SetCameraAngle( TVertex( 300, 0, 0 ) );
break;
}
case ECameraLookAt:
{
TVertex camPos( 0, -200, 5000 );
iRender->SetCameraPosition( camPos );
camPos -= iCarPosition;
if( camPos.iZ == 0 ) camPos.iZ = 1;
TReal r;
Math::ATan( r, camPos.iX, camPos.iZ );
r = r * KSinTableSize/2 / KPi;
TInt32 a1;
Math::Int( a1, r );
a1 += KSinTableSize/2;
if( camPos.iY == 0 ) camPos.iY = 1;
Math::ATan( r, camPos.iZ, camPos.iY );
r = r * KSinTableSize/2 / KPi;
TInt32 a2;
Math::Int( a2, r );
a2 += KSinTableSize/2 + KSinTableSize/4;
iRender->SetCameraAngle( TVertex( a2, a1, 0 ) );
break;
}
}
// and draw everything
iRender->Draw( aScreen );
}
void CGame::Move( TUint8* aKey )
{
// check keys and update physics
iCarPositionAdd = TVertex( iCarSpeed,0,0 );
iCarPositionAdd = i3DBase->RotateY( iCarPositionAdd, iCarAngle & (KSinTableSize-1) );
iCarPosition += iCarPositionAdd;
// VERY simple collision detection from tilemap
TBool collision = EFalse;
TInt tileX = ( iCarPosition.iX + KTileSize/2 ) / KTileSize;
TInt tileY = ( iCarPosition.iZ + KTileSize/2 ) / KTileSize;
// first check we stay on map:
if( ( tileX < 1 ) || ( tileX >= KMapWidth-1 ) ||
( tileY < 1 ) || ( tileY >= KMapHeight-1 ) )
{
collision = ETrue;
}
else
{
// then check collisions against buildings
TInt tile = KMap[ tileX ][ tileY ];
if( tile == 'a' ) // if tile is a building
{
collision = ETrue;
}
}
if( collision )
{
// move back
iCarPosition -= iCarPositionAdd;
// and stop
iCarSpeed = 0;
}
iCarPos += iCarSpeed;
if( aKey[ EStdKeyUpArrow ] )
{
iThrottle = 1;
}
else if( aKey[ EStdKeyDownArrow ] )
{
iThrottle = -1;
}
else
{
iThrottle = 0;
}
iCarAngleSpeed = ( -iSteerAngle * iCarSpeed ) >> 8;
iCarAngle += iCarAngleSpeed;
if( aKey[ EStdKeyLeftArrow ] || aKey[ '5' ] )
{
iSteerAngle -= 4;
}
else if( aKey[ EStdKeyRightArrow ] || aKey[ '6' ] )
{
iSteerAngle += 4;
}
else
{
if( iSteerAngle > 0 ) iSteerAngle -= 4;
if( iSteerAngle < 0 ) iSteerAngle += 4;
}
iCarSpeed += iThrottle;
if( iThrottle == 0 )
{
if( iCarSpeed > 0 ) iCarSpeed -= 1;
if( iCarSpeed < 0 ) iCarSpeed += 1;
}
if( iCarSpeed > 100 ) iCarSpeed = 100;
if( iCarSpeed < -100 ) iCarSpeed = -100;
TInt steerLimit = 100;
if( iSteerAngle > steerLimit ) iSteerAngle = steerLimit;
if( iSteerAngle < -steerLimit ) iSteerAngle = -steerLimit;
//
// choose camera mode with keys 1 and 2
//
if( aKey[ '1' ] )
{
iCameraMode = ECameraBehind;
}
if( aKey[ '2' ] )
{
iCameraMode = ECameraSouth;
}
}
//
// These functions demonstrate how to create 3D objects
// It should be easy to convert objects from your
// favourite 3D object file format to use in here
CPolygonObject* CGame::CreateWheel( TInt aRadius, TInt aWidth, TInt aNumPoints )
{
CPolygonObject* o = CPolygonObject::NewL( i3DBase, 100,100 );
TInt16* cos = i3DBase->CosTable();
TInt16* sin = i3DBase->SinTable();
TInt i;
TInt z1 = -aWidth/2;
TInt z2 = aWidth/2;
o->AddVertex( TVertex( 0,0,0 ) );
for( i=0; i<aNumPoints; i++ )
{
TInt a1 = 4096 * i / aNumPoints;
TInt a2 = ( a1 + 4096 / aNumPoints ) & 4095;
TInt x1 = ( aRadius * cos[ a1 ] ) >> KShift;
TInt y1 = ( aRadius * sin[ a1 ] ) >> KShift;
TInt x2 = ( aRadius * cos[ a2 ] ) >> KShift;
TInt y2 = ( aRadius * sin[ a2 ] ) >> KShift;
o->AddVertex( TVertex( x1,y1,z1 ) );
o->AddVertex( TVertex( x1,y1,z2 ) );
TInt n1 = i*2;
TInt n2 = n1 + 1;
TInt n3 = n1 + 2;
TInt n4 = n1 + 3;
if( n3 >= aNumPoints*2 ) n3 -= aNumPoints*2;
if( n4 >= aNumPoints*2 ) n4 -= aNumPoints*2;
n1 += 1;
n2 += 1;
n3 += 1;
n4 += 1;
o->AddFace( TFace( n1,n2,n3, 128,0, 255,0, 128,128 ) );
o->AddFace( TFace( n3,n2,n4, 128,128, 255,0, 255,128 ) );
TInt tx1 = 64 + x1 * 63 / aRadius;
TInt ty1 = 64 + y1 * 63 / aRadius;
TInt tx2 = 64 + x2 * 63 / aRadius;
TInt ty2 = 64 + y2 * 63 / aRadius;
o->AddFace( TFace( n1,n3,0, tx1,ty1, tx2,ty2, 64,64 ) );
}
return o;
}
CPolygonObject* CGame::CreateObject( const TInt* aVertexData, const TInt* aFaceData,
TInt aNumVertices, TInt aNumFaces,
const TPoint& aTexOffset, TInt aTexMul )
{
// leave some extra room for vertices and polygons
// otherwise renderer might not have enough space
// after clipping
CPolygonObject* o = CPolygonObject::NewL( i3DBase, aNumVertices*2+10, aNumFaces*2+10 );
TInt n=0;
TInt i;
for( i=0; i<aNumVertices; i++ )
{
o->AddVertex( TVertex( aVertexData[ n + 0 ],
aVertexData[ n + 1 ],
aVertexData[ n + 2 ]
) );
n += 3;
}
n=0;
for( i=0; i<aNumFaces; i++ )
{
o->AddFace( TFace( aFaceData[ n + 0 ],
aFaceData[ n + 1 ],
aFaceData[ n + 2 ],
aFaceData[ n + 3 ]*aTexMul+aTexOffset.iX,
aFaceData[ n + 4 ]*aTexMul+aTexOffset.iY,
aFaceData[ n + 5 ]*aTexMul+aTexOffset.iX,
aFaceData[ n + 6 ]*aTexMul+aTexOffset.iY,
aFaceData[ n + 7 ]*aTexMul+aTexOffset.iX,
aFaceData[ n + 8 ]*aTexMul+aTexOffset.iY
) );
n += 9;
}
return o;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -