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 + -
显示快捷键?