ROLL OUT!
Libra is a top-down tank game where players traverse tile-based maps and battle various types of enemies.


void Player::UpdateTurret( float deltaSeconds ) { m_turretTargetVec = Vec2::ZERO; m_isFiring = false; m_isFlaming = false; UpdateTurretFromController( deltaSeconds ); UpdateTurretFromKeyboard( deltaSeconds ); if( m_turretTargetVec.GetLength() >= 0.01f ) { m_turretTargetRelativeOrientation = GetShortestAngularDispDegrees( m_stats.m_orientationDegrees, m_turretTargetVec.GetOrientationDegrees() ); m_turretRelativeOrientation = GetTurnedTowardDegrees( m_turretRelativeOrientation, m_turretTargetRelativeOrientation, ( m_turretAngularVelocity * deltaSeconds ) ); } if( m_isFiring ) { m_fireTime += deltaSeconds; if( m_fireTime >= m_stats.m_fireRate ) { if( !g_isMuted ) { SoundID shootID = g_theAudio->CreateOrGetSound( g_gameConfigBlackboard.GetValue( "shootSFX", "" ) ); g_theAudio->StartSound( shootID ); } float turretOrientationDeg = m_stats.m_orientationDegrees + m_turretRelativeOrientation; Vec2 bulletPos = m_position + Vec2::MakeFromPolarDegrees( turretOrientationDeg, g_gameConfigBlackboard.GetValue( "playerBulletSpawnOffset", 0.f ) ); m_map->SpawnNewEntityOfType( EntityType::GOOD_BULLET, bulletPos, turretOrientationDeg ); m_fireTime = 0.f; } } else { m_fireTime = m_stats.m_fireRate; } if( !m_isFiring && m_isFlaming ) { m_flameTime += deltaSeconds; if( m_flameTime >= m_flameRate ) { if( !g_isMuted ) { SoundID flameID = g_theAudio->CreateOrGetSound( g_gameConfigBlackboard.GetValue( "flameSFX", "" ) ); g_theAudio->StartSound( flameID, false, 0.1f ); } float turretOrientationDeg = m_stats.m_orientationDegrees + m_turretRelativeOrientation; Vec2 bulletPos = m_position + Vec2::MakeFromPolarDegrees( turretOrientationDeg, g_gameConfigBlackboard.GetValue( "playerBulletSpawnOffset", 0.f ) ); m_map->SpawnNewEntityOfType( EntityType::GOOD_FLAME, bulletPos, turretOrientationDeg + g_rng.GetRandomFloatInRange( -m_flameSpread, m_flameSpread ) ); m_flameTime = 0.f; } } else { m_flameTime = m_flameRate; } }
void Map::PopulateDistanceField( TileHeatMap& out_distanceField, IntVec2 referenceCoords, float maxCost, bool treatWaterAsSolid ) { out_distanceField.SetAll( maxCost ); out_distanceField.SetHeatAt( referenceCoords, 0.f ); std::queue<IntVec2> coordsToCheck; coordsToCheck.push( referenceCoords ); while( !coordsToCheck.empty() ) { IntVec2 coord = coordsToCheck.front(); IntVec2 northCoord = IntVec2( coord.x, coord.y + 1 ); if( !IsTileOutOfBounds( northCoord ) && !IsTileSolid( northCoord ) && !( treatWaterAsSolid && IsTileWater( northCoord ) ) ) { if( out_distanceField.GetHeatAt( northCoord ) > out_distanceField.GetHeatAt( coord ) + 1 ) { out_distanceField.SetHeatAt( northCoord, out_distanceField.GetHeatAt( coord ) + 1 ); coordsToCheck.push( northCoord ); } } // ... } }
Post-Mortem
When working on Libra, I think the most valuable asset was organizing tasks by priority. Many of the engine additions were necessary for future projects but provided little in terms of immediate returns, so prioritizing those incentivized doing those. However, the priorities resulted in working less on the "fun-ness" of the Libra game, as well as cleaning up and refactoring code (the latter also being an issue in Starship). In the future, I need to allow more time for the "extra" components of the project, since working on more unique problems will provide valuable experience.