📄 world.cpp
字号:
/**
* File : World.cpp
* Author : Kevin Lynx
* Date : 2007/7/29
*/
#include "stdafx.h"
#include "World.h"
#include <stdio.h>
#include "MonsterManager.h"
#include "ResourceMgr.h"
#include "Player.h"
#include "App.h"
#include "ConfigReader.h"
const char *LEVEL_DIR = "data/levels/";
World::World( IrrlichtDevice *device )
{
mDevice = device;
mMapData = 0;
mGroundNode = 0;
mCurLevelIndex = 1;
}
World::~World()
{
release();
}
bool World::load( bool nextLevel )
{
char file[256];
if( nextLevel )
{
mCurLevelIndex = getNextLevelIndex( mCurLevelIndex );
}
sprintf( file, "%slevel%d.txt", LEVEL_DIR, mCurLevelIndex );
release();
if( !loadModels( file ) )
{
return false;
}
createGround();
return true;
}
int World::collision( const rect<float> &box2d, const vector3df &dir )
{
#define RETURN { if( cr > 0 && cr < STONE_COUNT ) return cr; }
int cr;
if( core::equals( dir.X, -1.0f ) )
{
// left
cr = collision( vector3df( box2d.UpperLeftCorner.X, 0, box2d.UpperLeftCorner.Y ) );
RETURN
cr = collision( vector3df( box2d.UpperLeftCorner.X, 0, box2d.LowerRightCorner.Y ) );
RETURN
}
else if( core::equals( dir.X, 1.0f ) )
{
// right
cr = collision( vector3df( box2d.LowerRightCorner.X, 0, box2d.LowerRightCorner.Y ) );
RETURN
cr = collision( vector3df( box2d.LowerRightCorner.X, 0, box2d.UpperLeftCorner.Y ) );
RETURN
}
else if( core::equals( dir.Z, -1.0f ) )
{
// down --left-handle coordinate , i mean , out of the screen
cr = collision( vector3df( box2d.UpperLeftCorner.X, 0, box2d.LowerRightCorner.Y ) );
RETURN
cr = collision( vector3df( box2d.LowerRightCorner.X, 0, box2d.LowerRightCorner.Y ) );
RETURN
}
else if( core::equals( dir.Z, 1.0f ) )
{
// ;up --left-handle coordinate
cr = collision( vector3df( box2d.UpperLeftCorner.X, 0, box2d.UpperLeftCorner.Y ) );
RETURN
cr = collision( vector3df( box2d.LowerRightCorner.X, 0, box2d.UpperLeftCorner.Y ) );
RETURN
}
//*/
return 0;
}
int World::collision( const vector3df &pos )
{
int ax = int( pos.X - mStartPos.Width ) / mStoneSize.Width ;
int az = int( mStartPos.Height - pos.Z ) / mStoneSize.Height ;
return mMapData[ ax + az * mMapSize.Width ];
}
void World::adjustPos( const rect<float> &box2d, const vector3df &dir, vector3df &outPos )
{
float w = box2d.LowerRightCorner.X - box2d.UpperLeftCorner.X;
float h = box2d.UpperLeftCorner.Y - box2d.LowerRightCorner.Y;
float centerX = box2d.LowerRightCorner.X - w / 2;
float centerZ = box2d.LowerRightCorner.Y + h / 2;
int ax, az;
float tx, tz;
if( equals( dir.Z, -1.0f ) )
{
// down
worldToMap( centerX, centerZ, ax, az );
mapToWorldCenter( ax, az, tx, tz );
az ++;
ax = centerX > tx ? ax + 1 : ax - 1;
mapToWorldCenter( ax, az, tx, tz );
tx = tx > centerX ? tx - mStoneSize.Width / 2 - w / 2 :
tx + mStoneSize.Width / 2 + w / 2;
outPos.X = tx;
}
else if( equals( dir.Z, 1.0f ) )
{
// up
worldToMap( centerX, centerZ, ax, az );
mapToWorldCenter( ax, az, tx, tz );
az --;
ax = centerX > tx ? ax + 1 : ax - 1;
mapToWorldCenter( ax, az, tx, tz );
tx = tx > centerX ? tx - mStoneSize.Width / 2 - w / 2 :
tx + mStoneSize.Width / 2 + w / 2;
outPos.X = tx;
}
if( equals( dir.X, -1.0f ) )
{
// left
worldToMap( centerX, centerZ, ax, az );
mapToWorldCenter( ax, az, tx, tz );
ax --;
az = centerZ > tz ? az - 1 : az + 1;
mapToWorldCenter( ax, az, tx, tz );
tz = tz > centerX ? tz - mStoneSize.Width / 2 - w / 2 :
tz + mStoneSize.Width / 2 + w / 2;
outPos.Z = tz;
}
else if( equals( dir.X, 1.0f ) )
{
// right
worldToMap( centerX, centerZ, ax, az );
mapToWorldCenter( ax, az, tx, tz );
ax ++;
az = centerZ > tz ? az - 1 : az + 1;
mapToWorldCenter( ax, az, tx, tz );
tz = tz > centerX ? tz - mStoneSize.Width / 2 - w / 2 :
tz + mStoneSize.Width / 2 + w / 2;
outPos.Z = tz;
}
}
void World::worldToMap( float x, float z, int &ax, int &az )
{
ax = int( x - mStartPos.Width ) / mStoneSize.Width ;
az = int( mStartPos.Height - z ) / mStoneSize.Height ;
}
void World::mapToWorld( int ax, int az, float &x, float &z )
{
x = ax * mStoneSize.Width + mStartPos.Width;
z = -az * mStoneSize.Height + mStartPos.Height;
}
void World::mapToWorldCenter( int ax, int az, float &cx, float &cz )
{
mapToWorld( ax, az, cx, cz );
cx += mStoneSize.Width / 2;
cz -= mStoneSize.Height / 2;
}
bool World::loadModels( const std::string &file )
{
FILE *fp = fopen( file.c_str(), "r" );
if( fp == NULL )
{
return false;
}
ISceneManager *smgr = mDevice->getSceneManager();
IVideoDriver *driver= mDevice->getVideoDriver();
int modelCount;
char resFile[256];
int type;
int i;
/// load stone model
fscanf( fp, "%d", &modelCount );
for( i = 0; i < modelCount; ++ i )
{
fscanf( fp, "%s%d", resFile, &type );
IAnimatedMesh *mesh = smgr->getMesh( resFile );
mStoneSet.insert( std::make_pair( type, mesh ) );
}
/// load monster model
fscanf( fp, "%d", &modelCount );
for( i = 0; i < modelCount; ++ i )
{
fscanf( fp, "%s%d", resFile, &type );
IAnimatedMesh *mesh = smgr->getMesh( resFile );
mMonsterSet.insert( std::make_pair( type, mesh ) );
/// texture
fscanf( fp, "%s", resFile );
ITexture *text = driver->getTexture( resFile );
mMonsterTextSet.insert( std::make_pair( type, text ) );
}
/// load bonus model
fscanf( fp, "%d", &modelCount );
for( i = 0; i < modelCount; ++ i )
{
fscanf( fp, "%s%d", resFile, &type );
IAnimatedMesh *mesh = smgr->getMesh( resFile );
mBonusSet.insert( std::make_pair( type, mesh ) );
}
/// background texture
fscanf( fp, "%s", resFile );
mBkTexture = driver->getTexture( resFile );
fscanf( fp, "%s", resFile );
fclose( fp );
return loadMap( resFile );
}
bool World::loadMap( const std::string &file )
{
FILE *fp = fopen( file.c_str(), "r" );
if( fp == NULL )
{
return false;
}
fscanf( fp, "%f%f", &mStartPos.Width, &mStartPos.Height );
fscanf( fp, "%d%d", &mStoneSize.Width, &mStoneSize.Height );
fscanf( fp, "%d%d", &mMapSize.Width, &mMapSize.Height );
mMapData = new int [ mMapSize.Width * mMapSize.Height ];
mBeanCount = 0;
for( int z = 0; z < mMapSize.Height; ++ z )
{
for( int x = 0; x < mMapSize.Width; ++ x )
{
int dummy;
fscanf( fp, "%d", &dummy );
mMapData[ z * mMapSize.Width + x ] = dummy;
createMapItem( dummy, x, z );
}
}
/// TODO : read monster information
MonsterManager::GetSingletonPtr()->init( fp );
/// TODO : read guns information
/// TODO : read player information
int player_x, player_z;
float w_p_x, w_p_z;
fscanf( fp, "%d%d", &player_x, &player_z );
mapToWorldCenter( player_x, player_z, w_p_x, w_p_z );
mPlayerWorldPos.X = w_p_x;
mPlayerWorldPos.Y = w_p_z;
/// delete the bean on the player's initial position
int id = player_x + player_z * mMapSize.Width ;
mMapData[id] = 0;
ISceneNode *beanNode = mDevice->getSceneManager()->getSceneNodeFromId( id );
if( beanNode )
{
beanNode->remove();
mBeanCount --;
}
/// read level time
u32 time;
fscanf( fp, "%d", &time );
App::GetSingletonPtr()->setLevelTime( time * 1000 );
fclose( fp );
return true;
}
void World::createGround()
{
const std::string meshname = "GroundMesh";
ISceneManager *smgr = mDevice->getSceneManager();
dimension2d<float> tileSize( (f32)mStoneSize.Width, (f32)mStoneSize.Height );
IAnimatedMesh *planeMesh = smgr->getMesh( meshname.c_str() );
if( planeMesh != 0 )
{
IMeshCache *meshCache = smgr->getMeshCache();
meshCache->removeMesh( planeMesh );
}
if( mGroundNode != 0 )
{
mGroundNode->remove();
mGroundNode = 0;
}
planeMesh = smgr->addHillPlaneMesh( meshname.c_str(), tileSize, mMapSize );
ISceneNode *node = smgr->addAnimatedMeshSceneNode( planeMesh );
node->setMaterialFlag( EMF_LIGHTING, false );
node->setMaterialTexture( 0, mBkTexture );
mGroundNode = node;
}
void World::release()
{
/// delete beans and stones scene node in the world
for( int z = 0; z < mMapSize.Height; ++ z )
{
for( int x = 0; x < mMapSize.Width; ++ x )
{
int id = z * mMapSize.Width + x;
ISceneNode *node = mDevice->getSceneManager()->getSceneNodeFromId( id );
if( node != 0 )
{
node->remove();
}
}
}
mStoneSet.clear();
mMonsterSet.clear();
mBonusSet.clear();
mMonsterTextSet.clear();
SAFE_DELETE_ARR( mMapData );
if( mGroundNode != 0 )
{
mGroundNode->remove();
mGroundNode = 0;
}
}
void World::createMapItem( int value, int x, int z )
{
if( value == 0 )
{
IAnimatedMesh *mesh = ResourceMgr::GetSingletonPtr()->mBeanMesh ;
/// should put beans or bonues
float rx = x * mStoneSize.Width + mStartPos.Width + mStoneSize.Width / 2 ;
float rz = -z * mStoneSize.Height + mStartPos.Height - mStoneSize.Height / 2;
float ry = 20; ///need adjust
int id = z * mMapSize.Width + x; //it's important
ISceneNode *node = mDevice->getSceneManager()->addAnimatedMeshSceneNode(
mesh, 0, id, vector3df( rx, ry, rz ) );
node->setMaterialFlag( EMF_LIGHTING, false );
ISceneNodeAnimator *anim = mDevice->getSceneManager()->createFlyCircleAnimator(
vector3df( rx, ry, rz ), 5, 0.005f, vector3df( 1, 0, 0 ) );
node->addAnimator( anim );
anim->drop();
mMapData[ x + z * mMapSize.Width ] = STONE_COUNT + B_BEAN;
/// add bean count
mBeanCount ++;
}
else
{
/// should put stones
tModelSet::iterator it = mStoneSet.find( value );
if( it != mStoneSet.end() )
{
float rx = x * mStoneSize.Width + mStartPos.Width + mStoneSize.Width / 2 ;
float rz = -z * mStoneSize.Height + mStartPos.Height - mStoneSize.Height / 2;
float ry = 40; ///need adjust
int id = z * mMapSize.Width + x; //it's important
ISceneNode *node = mDevice->getSceneManager()->addAnimatedMeshSceneNode(
it->second, 0, id, vector3df( rx, ry, rz ) );
node->setScale( vector3df( 2.0f, 2.0f, 2.0f ) );
node->setMaterialFlag( EMF_LIGHTING, ConfigReader::GetSingletonPtr()->mEnableLight );
}
/// the map array 's value is ok.
}
}
bool World::isGotBean( const aabbox3df &box )
{
vector3df p[4];
p[0].set( box.MinEdge );
p[1].set( box.MinEdge.X, 0, box.MaxEdge.Z );
p[2].set( box.MaxEdge.X, 0, box.MaxEdge.Z );
p[3].set( box.MaxEdge.X, 0, box.MinEdge.Z );
int ax, az;
ISceneManager *smgr = mDevice->getSceneManager();
for( int i = 0; i < 4; ++ i )
{
worldToMap( p[i].X, p[i].Z, ax, az );
if( mMapData[ ax + az * mMapSize.Width ] != B_BEAN + STONE_COUNT )
continue;
ISceneNode *node = smgr->getSceneNodeFromId( getNodeId( ax, az ) );
if( node != NULL )
{
if( node->getTransformedBoundingBox().intersectsWithBox( box ) )
{
// eaten
mMapData[ ax + az * mMapSize.Width ] = 0;
node->remove();
// decress bean count
mBeanCount --;
return true;
}
}
}
return false;
}
inline int World::getNodeId( int ax, int az )
{
return az * mMapSize.Width + ax;
}
bool World::getMonsterRes( int type, IAnimatedMesh *&mesh, ITexture *&texture )
{
tModelSet::iterator it = mMonsterSet.find( type );
if( it == mMonsterSet.end() )
{
return false;
}
mesh = it->second;
tMonsterTexture::iterator it2 = mMonsterTextSet.find( type );
if( it2 != mMonsterTextSet.end() )
{
texture = it2->second;
}
return true;
}
bool World::getBonusRes( int type, IAnimatedMesh *&mesh )
{
tModelSet::iterator it = mBonusSet.find( type );
if( it == mBonusSet.end() )
{
return false;
}
mesh = it->second;
return true;
}
int World::getMapValue( int ax, int az )
{
if( ax + az * mMapSize.Width >= mMapSize.Width * mMapSize.Height )
{
/// error
return 1;
}
else
{
return mMapData[ ax + az * mMapSize.Width ];
}
}
bool World::canReach( int ax, int az )
{
int v = getMapValue( ax, az );
return v == 0 || v >= STONE_COUNT;
}
bool World::isCenterPos( const vector3df &worldPos )
{
int ax, az;
float x, z;
worldToMap( worldPos.X, worldPos.Z, ax, az );
mapToWorld( ax, az, x, z );
x += mStoneSize.Width / 2;
z -= mStoneSize.Height / 2;
/// as you can see, the center position is a range :D
if( fabs( worldPos.X - x ) < 5 &&
fabs( worldPos.Z - z ) < 5 )
{
return true;
}
return false;
}
void World::getValidPos( float &x, float &z )
{
int ax, az;
do
{
ax = rand() % ( mMapSize.Width - 2 ) + 1;
az = rand() % ( mMapSize.Height - 2 ) + 1;
}while( canReach( ax, az ) );
mapToWorldCenter( ax, az, x, z );
}
bool World::isLevelClear()
{
return mBeanCount <= 0;
}
int World::getNextLevelIndex( int curIndex )
{
curIndex ++;
char file[256];
sprintf( file, "%slevel%d.txt", LEVEL_DIR, curIndex );
FILE *fp = fopen( file, "r" );
if( fp == 0 )
{
curIndex = 1;
return curIndex;
}
fclose( fp );
return curIndex;
}
void World::setLevelIndex( int index )
{
mCurLevelIndex = index;
}
bool World::isOutOfWorld( const rect<f32> &rect )
{
dimension2d<f32> endPos( mStartPos.Width + mMapSize.Width * mStoneSize.Width,
mStartPos.Height - mMapSize.Height * mStoneSize.Height );
return rect.LowerRightCorner.X < mStartPos.Width ||
rect.LowerRightCorner.Y > mStartPos.Height ||
rect.UpperLeftCorner.X > endPos.Width ||
rect.UpperLeftCorner.Y < endPos.Height ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -