⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 world.cpp

📁 吃豆子游戏源码
💻 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 + -