player.cpp

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

CPP
1,095
字号

		case BODY_WALK:
			break;

		case BODY_DEATH:
			GameApp::get()->playSound( "hero_die", SoundContext::CHANNEL_OTHER );
			break;

		case BODY_ATTACK:
			switch ( m_currentWeapon )
			{
				case WEAPON_SWORD:		GameApp::get()->playSound( "hero_attack", SoundContext::CHANNEL_OTHER ); break;
				case WEAPON_SPEAR:		GameApp::get()->playSound( "hero_attack", SoundContext::CHANNEL_OTHER ); break;
				case WEAPON_SHOTGUN:	GameApp::get()->playSound( "hero_shotgun", SoundContext::CHANNEL_OTHER ); break;
				default:				GameApp::get()->playSound( "hero_attack", SoundContext::CHANNEL_OTHER ); break;
			}
			break;

		case BODY_TAKE_WEAPON:
			break;

		default:
			break;
		}

		m_state = state;
		setVirtualState( (BodyState) virtualState );

		if ( !endTime )
		{
			m_time = Fix(0);
		}
		else
		{
			Surface& s = bodyAnim( NULL, NULL );
			m_time = s.endTime();
		}
	}
}

void Player::setVirtualState( BodyState virtualState )
{
	if ( virtualState != m_virtualState )
	{
		m_virtualState = virtualState;
		m_time = Fixf(0);
	}
}

void Player::clearVirtualState()
{
	m_virtualState = BODY_NONE;
	m_time = Fixf(0);
}

void Player::walk( Dir dir )
{
	if ( m_hitpoints <= Fixf(0) ) return;
	setDirection( dir );
	if ( m_hitpoints > maxHitPoints()*Fixf(0.25) )
		setState( BODY_WALK );
	else
		setState( BODY_WALK_WOUNDED );
}

void Player::stand()
{
	setState( BODY_IDLE );
}

void Player::hit()
{
}

void Player::die( MapObject* killer )
{
	m_killer = killer;
	m_hitpoints = Fixf(0);
	setState( BODY_DEATH );
}

void Player::attack()
{
	setState( (BodyState) BODY_ATTACK );
}

void Player::cheat()
{
	m_hitpoints = m_maxHitPoints;
}

void Player::drink()
{
	setState( BODY_DRINK );
}

void Player::changeWeapon()
{
	int newWeapon;
	for ( int i = 1; i < WEAPON_COUNT; i++ )
	{
		newWeapon = ( m_currentWeapon + i ) % WEAPON_COUNT;
		assert( newWeapon < WEAPON_COUNT );
		if ( hasItem( (char*) WEAPON_NAMES[ newWeapon ] ) )
		{
			m_nextWeapon = newWeapon;
			setState( BODY_TAKE_WEAPON );
			break;
		}
	}
}

void Player::updateWalk( Fix dt, bool wounded )
{
	if ( m_time < Fixf(0.2) ) return;

	Fix speed = getModifiedSpeed();
	if ( wounded )
	{
		// wounded => loss of speed
		speed *= Fixf(0.75);
	}
	speed *= ( Fixf(1) - getWeaponSlowdownFactor() );
	if ( speed < Fixf(10) ) speed = Fixf(10);

	FixVec2 dir = directionVector();
	FixVec2 delta = dir * ( dt* speed );
	delta.y *= m_map->blockDimensionsRatio();

	Surface& s = bodyAnim( NULL, NULL );
	s.setReversed( false );
	s.setFrameRateModifier( Fix( speed.v >> 7 ) ); // speed 128 => frame rate modifier 1.0 => 100% frame rate

	if ( !m_map->testPointCollision( m_pos, delta, dir ) )
	{
		setPosition( position() + delta );
	}
	else
	{
		restorePosition();
	}
}

void Player::updateAttack( Fix dt, Fix skill, Fix damage, Fix range, Fix anglecos )
{
	const Surface& s = bodyAnim( NULL, NULL );
	Fix damagetime = s.endTime()*Fixf(0.5);
	if ( m_time > damagetime && m_time <= damagetime+dt )
	{
		tryAttack( skill, damage, range, anglecos );
	}

	if ( m_time > ( s.endTime() + getWeaponDelay() ) )
	{
		stand();
	}
}

void Player::updateDeath( Fix /*dt*/ )
{
	if ( animEnded() )
	{
		setState( BODY_DEAD, true );
	}
}

void Player::updateDrink( Fix /*dt*/ )
{
	if ( animEnded() )
		stand();
}

void Player::tryAttack( Fix skill, Fix damage, Fix range, Fix anglecos )
{
	MapObject* objlist[4];
	FixVec2 pos = position();
	int objs = getObjects( pos, range, anglecos, objlist, sizeof(objlist) / sizeof(objlist[0]) );
    
	for ( int i = 0 ; i < objs ; ++i )
		if ( isSkillSuccess(skill) )
		{
			objlist[i]->damage( damage, this );
		}
		else
		{
			objlist[i]->disturb( this );
		}
}

Fix Player::getModifiedSpeed()
{
	if ( m_speedModifyTime > Fixf(0) )
	{
		Fix speed = m_speed;
		speed += m_speedModifier * speed;
		if ( speed < Fixf(0) ) speed = Fixf(0);
		return speed;
	}
	else
	{
		m_speedModifyTime = Fixf(0);
		return m_speed;
	}
}

bool Player::animEnded() const
{
	const Surface& s = bodyAnim( NULL, NULL );
	return m_time > s.endTime();
}

bool Player::isInterruptable()
{
	return	m_state != BODY_ATTACK &&
			m_state != BODY_DRINK &&
			m_state != BODY_DEATH &&
			m_state != BODY_DEAD &&
			m_state != BODY_TAKE_WEAPON &&
			m_state != BODY_PUT_WEAPON &&
			m_virtualState != BODY_TAKE_WEAPON &&
			m_virtualState != BODY_PUT_WEAPON;
}

bool Player::isInState( const char* statename )
{
	int state = -1;
	for ( int i = 0; i < 2; i++ )
	{
		// first pass: check virtual state
		// second pass: check state
		state = ( i == 0 ) ? m_virtualState : m_state;
		
		if ( state == BODY_IDLE )
		{
			if ( strcmp( statename, "IDLE" ) == 0 ) return true;
		}
		else if ( state == BODY_WALK )
		{
			if ( strcmp( statename, "WALK" ) == 0 ) return true;
		}
		else if ( state == BODY_WALK_WOUNDED )
		{
			if ( strcmp( statename, "WALK_WOUNDED" ) == 0 ) return true;
		}
		else if ( state == BODY_ATTACK )
		{
			if ( strcmp( statename, "ATTACK" ) == 0 ) return true;
		}
		else if ( state == BODY_DRINK )
		{
			if ( strcmp( statename, "DRINK" ) == 0 ) return true;
		}
		else if ( state == BODY_DEATH )
		{
			if ( strcmp( statename, "DEATH" ) == 0 ) return true;
		}
		else if ( state == BODY_DEAD )
		{
			if ( strcmp( statename, "DEAD" ) == 0 ) return true;
		}
		else if ( state == BODY_TAKE_WEAPON )
		{
			if ( strcmp( statename, "TAKE_WEAPON" ) == 0 ) return true;
		}
		else if ( state == BODY_PUT_WEAPON )
		{
			if ( strcmp( statename, "PUT_WEAPON" ) == 0 ) return true;
		}
		else if ( state == BODY_STILL )
		{
			if ( strcmp( statename, "STILL" ) == 0 ) return true;
		}

		if ( ( state == BODY_TAKE_WEAPON ) || ( state == BODY_PUT_WEAPON ) )
		{
			if ( strcmp( statename, "CHANGE_WEAPON" ) == 0 ) return true;
		}

		if ( m_weaponInHand )
		{
			if ( strcmp( statename, "WEAPON_IN_HAND" ) == 0 ) return true;
		}
	}

	return false;
}

void Player::setState( const char* statename )
{
	if ( strcmp( statename, "DRINK" ) == 0 )
	{
		drink();
	}
	else if ( strcmp( statename, "IDLE" ) == 0 )
	{
		stand();
	}
	else
	{
		throwError( Exception( Format("Invalid character state: {0}", statename) ) );
	}
}

FixVec2 Player::blockRenderPositionReference() const
{
	return m_map->pixelToBlock( FixVec2( m_pos.x, m_pos.y ) );
}

FixVec2 Player::blockRenderPositionExtreme() const
{
	bool lowerHalf, oddBlock;
	FixVec2 lowRightPoint = renderPositionLow( SIDE_RIGHT );
	FixVec2 block = m_map->pixelToBlock( lowRightPoint, 0, &lowerHalf, &oddBlock );
	if ( lowerHalf )
	{
		// point located on the lower half of the block: need to check left
		FixVec2 left = m_map->pixelToBlock( renderPositionLow( SIDE_LEFT ) );
		if ( ( left.x != block.x ) || ( left.y != block.y ) )
		{
			// exceeding the boundary of the block located below and on the left, which is a latter block:
			// need to change the rendering position there to maintain correct drawing order
			block.y += Fix::fromInt( 1 );
			if ( !oddBlock ) block.x -= Fix::fromInt( 1 );
		}
	}

	return block;
}

FixVec2 Player::renderPositionLow( int side ) const
{
	const bool halfResolution = GameApp::get()->isHalfResolution();
	const int xSign = ( side < 0 ) ? -1 : ( side > 0 ) ? 1 : 0;
	int refX, refY;
	const Surface& anim = bodyAnim( &refX, &refY );
	if ( anim.mirror() ) refX = -refX;
	const int frameHalfWidth = anim.frameWidth() >> 1;
	const int frameHeight = anim.frameHeight();
	
	int x0 = position().x.toInt() - refX;
	int y0 = position().y.toInt() - refY;
	int shiftX = anim.mirror() ? ( -anim.offsetX() - anim.frameWidth() ) : anim.offsetX();
	int shiftY = anim.offsetY();
	shiftX += frameHalfWidth;
	x0 += shiftX;
	y0 += shiftY;
	if ( halfResolution )
	{
		x0 += shiftX;
		y0 += shiftY;
	}

	int x1 = x0 + frameHalfWidth * xSign;
	int y1 = y0 + frameHeight;
	if ( halfResolution )
	{
		x1 += frameHalfWidth * xSign;
		y1 += frameHeight;
	}
	
	return FixVec2( Fix::fromInt(x1), Fix::fromInt(y1) );
}

// End of File

⌨️ 快捷键说明

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