Skip to content

Instantly share code, notes, and snippets.

@profh
Created November 18, 2025 15:29
Show Gist options
  • Select an option

  • Save profh/c504005e06e807314083308e0b6a1cd0 to your computer and use it in GitHub Desktop.

Select an option

Save profh/c504005e06e807314083308e0b6a1cd0 to your computer and use it in GitHub Desktop.
BalloonPop_Solutions
// TODO: TASK 1 - Handle user touches to detect balloon pops
/* Handle touch-down events during active gameplay
**Note**: This demonstrates several key concepts:
1. Converting touch coordinates between different coordinate systems
2. Hit-testing to find which nodes were touched
3. Filtering nodes by their 'name' property
4. Early exit patterns with guard statements
- Parameters:
- touches: Set of UITouch objects (usually just one for single tap)
- event: The event containing all touches (can be nil)
*/
func handleTouchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Exit early if game is not active (prevents touches during game over screen)
guard isGameActive else { return }
// Get the first touch from the set
// **Note**: iOS supports multi-touch, so touches is a Set.
// For this game, we only care about single touches, so we get .first
guard let touch = touches.first else { return }
// Convert touch location from view coordinates to scene coordinates
// **Note**: Critical concept! Touches come in UIView coordinates,
// but SpriteKit nodes use scene coordinates. Always convert with location(in:)
let location = touch.location(in: self)
// Get all nodes at the touch location
// **Note**: nodes(at:) returns an array of ALL nodes at that point,
// from top to bottom (highest zPosition first). This is called "hit testing"
let touchedNodes = nodes(at: location)
// Search through touched nodes to find a balloon
// **Note**: We iterate through nodes checking the 'name' property
// This is why we set balloon.name = "balloon" when creating balloons
for node in touchedNodes {
if node.name == "balloon" {
// Found a balloon! Pop it
popBalloon(node)
break // Only pop one balloon per touch (prevents scoring multiple times)
}
}
}
// TODO: TASK 2 - Create a pop animation and remove the balloon
/* Handle a balloon being successfully popped by the player
**Note**: This demonstrates:
- Combining multiple SKActions with group (simultaneous) and sequence (serial)
- Creating satisfying visual feedback for player actions
- The importance of "game feel" - animations make the game more enjoyable
- Parameter balloon: The balloon node that was tapped/popped
*/
func popBalloon(_ balloon: SKNode) {
// Update game state
score += 1
updateScoreLabel()
// Create visual feedback animations
// **Note**: Good games provide immediate, satisfying feedback for player actions
// A simple scale+fade makes popping feel impactful
// Scale up the balloon as it "pops"
let scaleUp = SKAction.scale(to: 1.5, duration: 0.1)
// Fade out simultaneously
let fadeOut = SKAction.fadeOut(withDuration: 0.1)
// Run both animations at the same time using group
// **Note**: group vs sequence:
// - group: all actions run simultaneously
// - sequence: actions run one after another
let popAnimation = SKAction.group([scaleUp, fadeOut])
// After the pop animation finishes, remove the balloon from the scene
let remove = SKAction.removeFromParent()
// Sequence: pop animation THEN removal
let sequence = SKAction.sequence([popAnimation, remove])
// Execute the animation sequence
balloon.run(sequence)
run(SKAction.playSoundFileNamed("pop_sound.mp3", waitForCompletion: false))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment