map.cpp

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

CPP
1,225
字号

	Surface& s = app->sprites[o.spriteIndex];
	o.position[0] += m_props.blockStaggerX;
	o.position[1] += m_props.blockStaggerY;
	o.position[0] += s.offsetX();
	o.position[1] += s.offsetY();
	if ( GameApp::get()->isHalfResolution() )
	{
		o.position[0] += s.offsetX();
		o.position[1] += s.offsetY();
	}

	m_spriteTriggers.add( o );
}

void Map::addScreenTrigger( String name, float x, float y, String screen )
{
	ScreenTrigger o;
	String::cpy( o.name, sizeof(o.name), name );
	o.block[0] = Fixf(x);
	o.block[1] = Fixf(y);

	o.active = true;
	GameApp* app = GameApp::get();
	o.screenIndex = app->findItem( app->screenNames, app->screenCount, screen.c_str() );
	if ( -1 == o.screenIndex )
		throwError( Exception( Format( "screen {0} not found from list", screen ) ) );

	m_screenTriggers.add( o );
}

void Map::addItemTrigger( String name, float x, float y, String item )
{
	ItemTrigger o;
	String::cpy( o.name, sizeof(o.name), name );
	o.block[0] = Fixf(x);
	o.block[1] = Fixf(y);
	o.type = ItemTrigger::Add;
	String::cpy( o.itemName, sizeof(o.itemName), item );
	GameApp* app = GameApp::get();
	o.itemIndex = app->findItem( app->spriteNames, app->spriteCount, item.c_str() );
	m_itemTriggers.add( o );
}

void Map::removeItemTrigger( String name, float x, float y, String item )
{
	ItemTrigger o;
	String::cpy( o.name, sizeof(o.name), name );
	o.block[0] = Fixf(x);
	o.block[1] = Fixf(y);
	o.type = ItemTrigger::Remove;
	String::cpy( o.itemName, sizeof(o.itemName), item );
	GameApp* app = GameApp::get();
	o.itemIndex = app->findItem( app->spriteNames, app->spriteCount, item.c_str() );
	m_itemTriggers.add( o );
}

float Map::addEnemy(	lang::String name, float x, float y, float angle, lang::String type, float hitpoints, 
						float speed, float attackdamage, float attackskill, float aggression )
{
	ASSERT( angle >= 0 && angle <= 360 );
	ASSERT( aggression <= 256.f );

	Enemy o;
	o.m_map = this;
	String::cpy( o.m_name, sizeof(o.m_name), name );
	o.setBlockPosition( FixVec2(Fixf(x),Fixf(y)) );
	o.setDirection( Enemy::getAngleAsDir(Fixf(angle)) );
	o.setType( Enemy::toEnemyType(type.c_str()) );
	o.setHitPoints( Fixf(hitpoints) );
	o.m_speed = Fixf(speed);
	o.m_attackDamage = Fixf(attackdamage);
	o.m_attackSkill = Fixf(attackskill/100.f);
	o.m_aggression = Fixf(aggression);
	m_enemies.add( o );
	return (float)( m_enemies.size()-1 );
}

void Map::disableTrigger( String name )
{
	Trigger* triggerlist[128]; // note the limit
	int triggers = getTriggers( name.c_str(), triggerlist, 128 );
	for ( int i = 0 ; i < triggers ; ++i )
		triggerlist[i]->flags &= ~Trigger::FLAG_ENABLED;
}

//-------
#endif

int Map::getTriggers( const char* name, Trigger** triggerlist, int size )
{
	int triggers = 0;

	for ( int i = 0 ; i < m_levelTriggers.size() ; ++i )
		if ( !strcmp(name,m_levelTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_levelTriggers[i];
		}

	for ( int i = 0 ; i < m_textTriggers.size() ; ++i )
		if ( !strcmp(name,m_textTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_textTriggers[i];
		}

	for ( int i = 0 ; i < m_enableTriggers.size() ; ++i )
		if ( !strcmp(name,m_enableTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_enableTriggers[i];
		}

	for ( int i = 0 ; i < m_spriteTriggers.size() ; ++i )
		if ( !strcmp(name,m_spriteTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_spriteTriggers[i];
		}

	for ( int i = 0 ; i < m_screenTriggers.size() ; ++i )
		if ( !strcmp(name,m_screenTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_screenTriggers[i];
		}

	for ( int i = 0 ; i < m_itemTriggers.size() ; ++i )
		if ( !strcmp(name,m_itemTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_itemTriggers[i];
		}

	for ( int i = 0 ; i < m_charStateTriggers.size() ; ++i )
		if ( !strcmp(name,m_charStateTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_charStateTriggers[i];
		}

	for ( int i = 0 ; i < m_specialTriggers.size() ; ++i )
		if ( !strcmp(name,m_specialTriggers[i].name) )
		{
			assert( triggers < size );
			triggerlist[triggers++] = &m_specialTriggers[i];
		}

	return triggers;
}

void Map::addPlayer( MapObject* obj )
{
	addObject( obj );
	obj->setBlockPosition( m_playerStartPosition );
	obj->setDirection( MapObject::DIR_0 );
	m_player = obj;
}

void Map::removePlayer()
{
	removeObject( m_player );
	m_player = 0;
}

void Map::addObject( MapObject* obj )
{
	assert( m_objs < MAX_OBJECTS );

	#ifdef WIN32_EXTRA_CHECKS
		for ( int i = 0 ; i < m_objs ; ++i )
		{
			assert( m_objlist[i] != obj );
		}
	#endif
		
	obj->m_map = this;
	m_objlist[m_objs++] = obj;
}

void Map::removeObject( MapObject* obj )
{
	for ( int i = 0 ; i < m_objs ; ++i )
	{
		if ( m_objlist[i] == obj )
		{
			m_objlist[i] = m_objlist[m_objs-1];
			--m_objs;
			break;
		}
	}
}

void Map::computeIntermediates()
{
	// bound visible area
	int x1=0, y1=0;
	int x0=mapWidth(), y0=mapHeight();
	for ( int y = 0 ; y < mapHeight() ; ++y )
	{
		for ( int x = 0 ; x < mapWidth() ; ++x )
		{
			if ( getMapBlock(x,y) != 0 )
			{
				if ( x > x1 )
					x1 = x;
				if ( x < x0 )
					x0 = x;
				if ( y > y1 )
					y1 = y;
				if ( y < y0 )
					y0 = y;
			}
		}
	}
	dprintf( "visible area: (%d,%d)-(%d,%d)\n", x0,y0,x1,y1 );
	m_boundX0 = x0;
	m_boundX1 = x1;
	m_boundY0 = y0;
	m_boundY1 = y1;
}

int Map::getCollisionLines( int x, int y, FixVec2* linelist ) const
{
	int coll = -1;
	if ( isMapBlock(x,y) )
	{
		const BlockInfo& bi = getBlockInfo( getMapBlock(x,y) );
		if ( bi.bg[0] != 0 )
			coll = bi.coll;
	}

	const Fix sx = Fix::fromInt( blockStaggerX() );
	const Fix sy = Fix::fromInt( blockStaggerY() );
	const Fix bw = Fix::fromInt( blockWidth() );
	const Fix bh = Fix::fromInt( blockHeight() );
	const FixVec2 origin( blockToPixel( FixVec2(Fix::fromInt(x),Fix::fromInt(y)) ) );

	int c = 0;
	if ( coll & BlockInfo::COLL_TOPLEFT )
	{
		linelist[c++] = FixVec2(Fixf(0),sy) + origin;
		linelist[c++] = FixVec2(sx,Fixf(0)) + origin;
	}
	if ( coll & BlockInfo::COLL_TOPRIGHT )
	{
		FixVec2 s(sx,Fixf(0));
		FixVec2 e(bw,sy);
		linelist[c++] = s + origin;
		linelist[c++] = e + origin;
	}
	if ( coll & BlockInfo::COLL_BOTTOMRIGHT )
	{
		linelist[c++] = FixVec2(bw,sy) + origin;
		linelist[c++] = FixVec2(sx,bh) + origin;
	}
	if ( coll & BlockInfo::COLL_BOTTOMLEFT )
	{
		linelist[c++] = FixVec2(sx,bh) + origin;
		linelist[c++] = FixVec2(Fixf(0),sy) + origin;
	}

	return c>>1;
}

bool Map::testPointCollision( const FixVec2& pos, const FixVec2& delta, const FixVec2& dir ) const
{
	FixVec2 left( -dir.y, dir.x );
	FixVec2 pos1 = pos + delta + dir*Fixf(5.f);

	FixVec2 pointlist[] = 
	{ 
		pos-dir*Fixf(5.f), pos, pos1, pos1+dir*Fixf(5.f), 
		pos-dir*Fixf(5.f)-left, pos-left, pos1-left, pos1+dir*Fixf(5.f)-left,
		pos-dir*Fixf(5.f)+left, pos+left, pos1+left, pos1+dir*Fixf(5.f)+left
	};

	const int POINTS = sizeof(pointlist) / sizeof(pointlist[0]);

	int blocklist[100];
	int blocks = 0;
	for ( int i = 0 ; i < POINTS ; ++i )
	{
		FixVec2 b = pixelToBlock( pointlist[i] );
		assert( blocks < int(sizeof(blocklist) / sizeof(blocklist[0])) );
		blocklist[blocks++] = b.x.toInt() + (b.y.toInt()<<16);
	}
	LANG_SORT( blocklist, blocklist+blocks );
	blocks = unique( blocklist, blocklist+blocks ) - blocklist;

	const int MAX_LINES = 64;
	FixVec2 linelist[MAX_LINES*2];
	int lines = 0;
	for ( int i = 0 ; i < blocks ; ++i )
	{
		assert( lines+4 <= MAX_LINES );
		lines += getCollisionLines( blocklist[i]&0xFFFF, (blocklist[i]>>16)&0xFFFF, linelist + lines+lines );
	}

	for ( int i = 0 ; i < lines ; ++i )
	{
		const FixVec2& p0 = linelist[i+i];
		const FixVec2& p1 = linelist[i+i+1];
		
		#ifdef DEBUG_INFO
			viewportLines.add( p0, p1, 0xF );
		#endif

		if ( FixUtil::testLineLineIntersection(pos,pos1,p0,p1) ||
			FixUtil::testLineLineIntersection(pos-left,pos+left,p0,p1) ||
			FixUtil::testLineLineIntersection(pos1-left,pos1+left,p0,p1) ||
			FixUtil::testLineLineIntersection(pos-left,pos1-left,p0,p1) ||
			FixUtil::testLineLineIntersection(pos+left,pos1+left,p0,p1) )
			return true;
	}
	return false;
}

lang::Array<Enemy> Map::enemies() const
{
	return m_enemies;
}

FixVec2 Map::blockToPixel( const FixVec2& pos ) const
{
	FixVec2 p( pos.x * Fix::fromInt(blockWidth()),
		pos.y * Fix::fromInt(blockStaggerY()) );

	if ( pos.y.toInt() & 1 )
		p.x += Fix::fromInt( blockStaggerX() );

	return p;
}

FixVec2	Map::pixelToBlock( const FixVec2& pos, bool* out_rightHalf, bool* out_lowerHalf, bool* out_oddBlock ) const
{
	div_t x = div( pos.x.toInt(), blockWidth() );
	div_t y = div( pos.y.toInt(), blockHeight() );

	bool rightHalf = false;
	bool lowerHalf = false;
	bool oddBlock = false;

	Fix px = Fix::fromInt( x.rem );
	Fix py = Fix::fromInt( y.rem );
	const Fix sx = Fix::fromInt( blockStaggerX() );
	const Fix sy = Fix::fromInt( blockStaggerY() );
	const Fix bw = Fix::fromInt( blockWidth() );
	const Fix bh = Fix::fromInt( blockHeight() );
	
	FixVec2 line[] =
	{
		FixVec2(Fixf(0),sy),
		FixVec2(sx,Fixf(0)),
		FixVec2(bw,sy),
		FixVec2(sx,bh)
	};

	int bx = x.quot;
	int by = y.quot << 1;
	if ( !FixUtil::getPointLineSide(px,py,line[0],line[1]) )
	{
		--bx;
		--by;
		rightHalf = true;
		lowerHalf = true;
		oddBlock = true;
	}
	else if ( !FixUtil::getPointLineSide(px,py,line[1],line[2]) )
	{
		--by;
		rightHalf = false;
		lowerHalf = true;
		oddBlock = true;
	}
	else if ( !FixUtil::getPointLineSide(px,py,line[2],line[3]) )
	{
		++by;
		rightHalf = true;
		lowerHalf = false;
		oddBlock = true;
	}
	else if ( !FixUtil::getPointLineSide(px,py,line[3],line[0]) )
	{
		--bx;
		++by;
		rightHalf = false;
		lowerHalf = false;
		oddBlock = true;
	}
	else
	{
		rightHalf = ( x.rem > blockStaggerX() );
		lowerHalf = ( y.rem > blockStaggerY() );
		oddBlock = false;
	}

	if ( out_rightHalf ) *out_rightHalf = rightHalf;
	if ( out_lowerHalf ) *out_lowerHalf = lowerHalf;
	if ( out_oddBlock ) *out_oddBlock = oddBlock;
	
	return FixVec2( Fix::fromInt(bx), Fix::fromInt(by) );
}

// End of file

⌨️ 快捷键说明

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