map.cpp

来自「一个symbian 冒险游戏代码」· C++ 代码 · 共 1,225 行 · 第 1/3 页

CPP
1,225
字号
#include "Map.h"
#include "App.h"
#include "Surface.h"
#include "FixUtil.h"
#include "Enemy.h"
#include "Player.h"
#include "MapObject.h"
#include "GameApp.h"
#include <io/IOException.h>
#include <io/FileInputStream.h>
#include <io/FileOutputStream.h>
#include <lang/Profile.h>
#include <lang/algorithm/unique.h>
#include <lang/algorithm/quicksort.h>
#include <stdlib.h>
#include <string.h>
#include <config.h>


const int MAX_PILLAR_HEIGHT = 208;


// for optimization since Map::render is performance critical
#ifdef __SYMBIAN32__
#undef assert
#define assert(A)
#endif

#ifdef WIN32_CONVERT
using namespace lua;
#endif

using namespace io;
using namespace lang;


#ifndef WIN32_CONVERT
Map::Map( void* ) :
	startBlock( Fix(0), Fix(0) ),
	m_objs( 0 ),
	m_loadingPhase( LOAD_NONE ),
	m_playerStartPosition( Fix(0), Fix(0) ),
	m_player( 0 ),
	m_loadingDone( false )
{
	clear();
}
#else
//Conversion constructor
Map::Map( LuaState* luastate ) :
	LuaObject( luastate ),
	startBlock( Fix(0), Fix(0) ),
	m_objs( 0 ),
	m_loadingPhase( LOAD_NONE ),
	m_playerStartPosition( Fix(0), Fix(0) ),
	m_player( 0 )
{
	clear();
}
#endif

Map::~Map()
{
	dprintf( "~Map(%s)\n", m_name );
	removeObjects();
}

void Map::checkId( InputStream* in, int okid )
{
	int id;
	in->read( &id, sizeof(id) );
	if ( id != okid )
		throwError( IOException( Format("Corrupted level file, id was {0,x} but should have been {1}", id, okid) ) );
}

void Map::clear()
{
	m_name[0] = 0;
	m_ambientSound[0] = 0;
	removeObjects();

	startBlock = FixVec2( Fix(0), Fix(0) );
	m_loadingPhase = LOAD_NONE;
	m_playerStartPosition = FixVec2( Fix(0), Fix(0) );
	m_player = 0;
	m_loadingDone = false;
}

void Map::removeObjects()
{
	for ( int i = 0 ; i < m_objs ; ++i )
	{
		if ( m_objlist[i] )
		{
			m_objlist[i]->m_map = 0;
			m_objlist[i] = 0;
		}
	}
	m_objs = 0;
	memset( m_objlist, 0, sizeof(m_objlist) );
}

void Map::load( String filename )
{
	dprintf( "Map::load\n" );
	String::cpy( m_debugPrint, sizeof(m_debugPrint), "Map Load Launched" );

	m_loadingPhase = LOAD_START;
	m_loadingDone = false;
	removeObjects();
	startBlock = FixVec2( Fix(0), Fix(0) );
	String::cpy( m_name, sizeof(m_name), filename );
	dprintf( "Loading map %s\n", m_name );
	String::cpy( m_fileName, sizeof(m_fileName), App::get()->expandPath( ("data/maps/" + filename + ".bin").c_str() ) );
}

bool Map::load()
{
	TRACE();
	if ( m_loadingDone || ( m_loadingPhase == LOAD_NONE ) ) return true;

	m_loadingDone = false;
	int nextPhase = -1;
	m_debugPrint[0] = 0;
	TRACE();

	switch ( m_loadingPhase )
	{
		// start
		case LOAD_START:
			nextPhase = LOAD_START_REFRESH;
			break;

		// refresh
		case LOAD_START_REFRESH:
			nextPhase = LOAD_PROPERTIES;
			break;

		// properties
		case LOAD_PROPERTIES:
		{
			TRACE();
			String::cpy( m_debugPrint, sizeof(m_debugPrint), "Map Load/Start Ok" );

			FileInputStream in( m_fileName );
			int okid = 0x1234ABC0;

			// core data
			checkId( &in, okid++ );
			in.read( &m_props, sizeof(m_props) );

			m_blocks.resize( m_props.numBlockStr );
			checkId( &in, okid++ );
			in.read( m_blocks.begin(), m_blocks.size()*sizeof(m_blocks[0]) );

			m_map.resize( m_props.mapWidth*m_props.mapHeight );
			checkId( &in, okid++ );
			in.read( m_map.begin(), m_map.size()*sizeof(m_map[0]) );

			// start point
			checkId( &in, okid++ );
			in.read( &startBlock, sizeof(startBlock) );

			// ambient sound
			checkId( &in, okid++ );
			in.read( m_ambientSound, sizeof(m_ambientSound) );

			// level triggers
			checkId( &in, okid++ );
			int size;
			in.read( &size, sizeof(size) );
			m_levelTriggers.resize( size );
			in.read( m_levelTriggers.begin(), sizeof(LevelTrigger)*size );

			// text triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_textTriggers.resize( size );
			in.read( m_textTriggers.begin(), sizeof(TextTrigger)*size );

			// enable triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_enableTriggers.resize( size );
			in.read( m_enableTriggers.begin(), sizeof(EnableTrigger)*size );

			// sprite triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_spriteTriggers.resize( size );
			in.read( m_spriteTriggers.begin(), sizeof(SpriteTrigger)*size );

			// screen triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_screenTriggers.resize( size );
			in.read( m_screenTriggers.begin(), sizeof(ScreenTrigger)*size );

			// item triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_itemTriggers.resize( size );
			in.read( m_itemTriggers.begin(), sizeof(ItemTrigger)*size );

			// character state triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_charStateTriggers.resize( size );
			in.read( m_charStateTriggers.begin(), sizeof(CharStateTrigger)*size );

			// special triggers
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_specialTriggers.resize( size );
			in.read( m_specialTriggers.begin(), sizeof(SpecialTrigger)*size );

			// enemies
			checkId( &in, okid++ );
			in.read( &size, sizeof(size) );
			m_enemies.resize( size );
			for ( int i = 0 ; i < m_enemies.size() ; ++i )
			{
				m_enemies[i].read( &in );
				addObject( &m_enemies[i] );
			}

			nextPhase = LOAD_BITMAP;
			TRACE();
			break;
		}

		// bitmap
		case LOAD_BITMAP:
		{
			TRACE();
			String::cpy( m_debugPrint, sizeof(m_debugPrint), "Map Load/Bitmap Ok" );

			GameApp::get()->blockSet().load( m_props.bitmapFilename, m_props.blockWidth, m_props.blockHeight );

			nextPhase = LOAD_FINISH;
			break;
		}

		// finish
		case LOAD_FINISH:
		{
			TRACE();
			assert( m_props.blockStaggerX > 0 );
			assert( m_props.blockStaggerY > 0 );
			m_blockDimensionsRatio = Fixf( m_props.blockStaggerY ) / Fixf( m_props.blockStaggerX );
			computeIntermediates();
			
			// no next phase (loading done)
			TRACE();
			break;
		}

		default:
			TRACE();
			break;
	}

	if ( nextPhase >= LOAD_START )
	{
		m_loadingPhase = nextPhase;
	}
	else
	{
		m_loadingPhase = LOAD_NONE;
		m_debugPrint[0] = 0;
		m_loadingDone = true;
	}

	TRACE();
	return m_loadingDone;
}

void Map::save( String filename )
{
	int size = 0;
	FileOutputStream out( filename );
	int id = 0x1234ABC0;

	// core data
	out.write( &id, sizeof(id) ); ++id;
	out.write( &m_props, sizeof(m_props) );

	out.write( &id, sizeof(id) ); ++id;
	out.write( m_blocks.begin(), m_blocks.size()*sizeof(m_blocks[0]) );

	out.write( &id, sizeof(id) ); ++id;
	out.write( m_map.begin(), m_map.size()*sizeof(m_map[0]) );

	// start point
	out.write( &id, sizeof(id) ); ++id;
	out.write( &startBlock, sizeof(startBlock) );

	// ambient sound
	out.write( &id, sizeof(id) ); ++id;
	out.write( m_ambientSound, sizeof(m_ambientSound) );

	// level triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_levelTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_levelTriggers.begin(), sizeof(LevelTrigger)*m_levelTriggers.size() );

	// text triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_textTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_textTriggers.begin(), sizeof(TextTrigger)*m_textTriggers.size() );

	// enable triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_enableTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_enableTriggers.begin(), sizeof(EnableTrigger)*m_enableTriggers.size() );

	// sprite triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_spriteTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_spriteTriggers.begin(), sizeof(SpriteTrigger)*m_spriteTriggers.size() );

	// screen triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_screenTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_screenTriggers.begin(), sizeof(ScreenTrigger)*m_screenTriggers.size() );

	// item triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_itemTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_itemTriggers.begin(), sizeof(ItemTrigger)*m_itemTriggers.size() );

	// char state triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_charStateTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_charStateTriggers.begin(), sizeof(CharStateTrigger)*m_charStateTriggers.size() );

	// special triggers
	out.write( &id, sizeof(id) ); ++id;
	size = m_specialTriggers.size();
	out.write( &size, sizeof(size) );
	out.write( m_specialTriggers.begin(), sizeof(SpecialTrigger)*m_specialTriggers.size() );

	// enemies
	out.write( &id, sizeof(id) ); ++id;
	size = m_enemies.size();
	out.write( &size, sizeof(size) );
	for ( int i = 0 ; i < m_enemies.size() ; ++i )
		m_enemies[i].write( &out );
}

void Map::render( Surface& dst )
{
	PROFILE(Map_render);

	GameApp* app = GameApp::get();

	MapBlockSet& blockset = app->blockSet();
	const bool halfRes = app->isHalfResolution();

	int x0 = dst.viewportX();
	int y0 = dst.viewportY();
	int x1 = x0 + dst.width();
	int y1 = y0 + dst.height();
	if ( halfRes )
	{
		x0 <<= 1;
		y0 <<= 1;
		x1 <<= 1;
		y1 <<= 1;
	}

	blockset.load( m_props.bitmapFilename, m_props.blockWidth, m_props.blockHeight );

	for ( int i = 0 ; i < m_objs ; ++i )
	{
		FixVec2 p = m_objlist[i]->blockRenderPositionReference();
		m_objBlockPosX0[i] = p.x.toInt();
		m_objBlockPosY0[i] = p.y.toInt();
		p = m_objlist[i]->blockRenderPositionExtreme();
		m_objBlockPosX1[i] = p.x.toInt();
		m_objBlockPosY1[i] = p.y.toInt();
		m_objlist[i]->resetDrawn();
	}

	Surface* sprites = app->sprites;

	assert( m_props.blockWidth > 0 );
	assert( m_props.blockStaggerY > 0 );
	assert( m_props.blockWidth > 0 );
	assert( m_props.blockStaggerY > 0 );
	const int startx = ( x0 - m_props.blockWidth ) / m_props.blockWidth;
	const int starty = ( y0 - m_props.blockStaggerY ) / m_props.blockStaggerY;
	const int endx = ( x1 + m_props.blockWidth ) / m_props.blockWidth;
	const int endy = ( y1 + m_props.blockHeight + MAX_PILLAR_HEIGHT ) / m_props.blockStaggerY;

	// cache some variables to avoid re-calculating them in inner loop
	int mappos0 = startx + starty*m_props.mapWidth;
	int bx0 = startx * m_props.blockWidth;
	int by0 = starty * m_props.blockStaggerY;
	SpriteTrigger* spritetriggerbuffer[256];

	int dstx, dsty;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?