Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Add-Type -AssemblyName System.Windows.Forms
- Add-Type -AssemblyName System.Drawing
- # Enhanced form with simple gradient background
- $form = New-Object Windows.Forms.Form
- $form.Text = 'PowerShell FlappyBird'
- $form.Size = New-Object Drawing.Size(1200, 800)
- $form.StartPosition = 'CenterScreen'
- $form.FormBorderStyle = 'Sizable'
- $form.MaximizeBox = $true
- $form.MinimizeBox = $true
- $form.BackColor = [System.Drawing.Color]::FromArgb(135, 206, 235) # Sky Blue
- # Game variables
- $script:birdY = 300
- $script:gravity = 0.8
- $script:jumpStrength = -15
- $script:velocity = 0
- $script:score = 0
- $script:highScore = 0
- $script:pipeGap = 200 # Increased from 180 for easier gameplay
- $script:minPipeGap = 120
- $script:pipeSpeed = 4
- $script:maxPipeSpeed = 12
- $script:pipes = @()
- $script:gameRunning = $false
- $script:paused = $false
- $script:frameCount = 0
- $script:lastPipeFrame = 0
- # Sound functions (with error handling)
- function Play-JumpSound {
- try {
- [System.Console]::Beep(800, 100)
- }
- catch {
- # Silent fallback
- }
- }
- function Play-ScoreSound {
- try {
- [System.Console]::Beep(1000, 200)
- }
- catch {
- # Silent fallback
- }
- }
- function Play-GameOverSound {
- try {
- [System.Console]::Beep(300, 500)
- }
- catch {
- # Silent fallback
- }
- }
- # Function to download bird image
- function Get-BirdImage {
- try {
- Write-Host "Attempting to download bird image..."
- # Try multiple reliable image URLs
- $imageUrls = @(
- "https://raw.githubusercontent.com/sourabhv/FlapPyBird/master/assets/sprites/yellowbird-midflap.png",
- "https://flappybird.io/img/bird.png",
- "https://github.com/samuelcust/flappy-bird-assets/raw/master/sprites/yellowbird-midflap.png"
- )
- $tempPath = [System.IO.Path]::GetTempPath() + "flappy_bird.png"
- foreach ($imageUrl in $imageUrls) {
- try {
- Write-Host "Trying URL: $imageUrl"
- # Use .NET WebClient with timeout
- $webClient = New-Object System.Net.WebClient
- $webClient.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
- $webClient.DownloadFile($imageUrl, $tempPath)
- $webClient.Dispose()
- # Verify file was downloaded and has content
- if ((Test-Path $tempPath) -and ((Get-Item $tempPath).Length -gt 0)) {
- Write-Host "Successfully downloaded bird image!"
- # Load and return the image
- $image = [System.Drawing.Image]::FromFile($tempPath)
- return $image
- }
- }
- catch {
- Write-Host "Failed to download from: $imageUrl - $($_.Exception.Message)"
- continue
- }
- }
- Write-Host "All image URLs failed, using fallback"
- return $null
- }
- catch {
- Write-Host "Error in Get-BirdImage: $($_.Exception.Message)"
- return $null
- }
- }
- # Create enhanced bird with downloaded image
- Write-Host "Initializing bird sprite..."
- $birdImage = Get-BirdImage
- $bird = New-Object Windows.Forms.PictureBox
- $bird.Size = New-Object Drawing.Size(40, 30)
- $bird.Location = New-Object Drawing.Point(200, $script:birdY)
- $bird.SizeMode = 'StretchImage'
- $bird.BackColor = [System.Drawing.Color]::Transparent
- if ($birdImage) {
- Write-Host "Using downloaded bird image!"
- $bird.Image = $birdImage
- } else {
- Write-Host "Using fallback bird design"
- # Fallback if image download fails
- $bird.BackColor = [System.Drawing.Color]::Gold
- $bird.BorderStyle = 'None'
- # Create a simple bird shape using a label overlay
- $birdLabel = New-Object Windows.Forms.Label
- $birdLabel.Size = New-Object Drawing.Size(40, 30)
- $birdLabel.Location = New-Object Drawing.Point(0, 0)
- $birdLabel.BackColor = [System.Drawing.Color]::Transparent
- $birdLabel.ForeColor = [System.Drawing.Color]::DarkOrange
- $birdLabel.Text = '🐤'
- $birdLabel.Font = New-Object Drawing.Font('Segoe UI Emoji', 16, [Drawing.FontStyle]::Bold)
- $birdLabel.TextAlign = 'MiddleCenter'
- # If emoji doesn't work, use arrow
- if (-not $birdLabel.Text -or $birdLabel.Text -eq '🐤') {
- $birdLabel.Text = '▶'
- $birdLabel.Font = New-Object Drawing.Font('Arial', 16, [Drawing.FontStyle]::Bold)
- }
- $bird.Controls.Add($birdLabel)
- }
- $form.Controls.Add($bird)
- # Score display
- $scoreLabel = New-Object Windows.Forms.Label
- $scoreLabel.Font = New-Object Drawing.Font('Arial', 18, [Drawing.FontStyle]::Bold)
- $scoreLabel.ForeColor = [Drawing.Color]::White
- $scoreLabel.BackColor = [Drawing.Color]::FromArgb(120, 0, 0, 0) # Semi-transparent black
- $scoreLabel.AutoSize = $false
- $scoreLabel.Size = New-Object Drawing.Size(350, 60)
- $scoreLabel.Location = New-Object Drawing.Point(20, 20)
- $scoreLabel.TextAlign = 'MiddleLeft'
- $form.Controls.Add($scoreLabel)
- # Instructions label (just text, no box at all)
- $instructionsLabel = New-Object Windows.Forms.Label
- $instructionsLabel.Font = New-Object Drawing.Font('Arial', 10, [Drawing.FontStyle]::Bold)
- $instructionsLabel.ForeColor = [Drawing.Color]::White
- $instructionsLabel.BackColor = [Drawing.Color]::Transparent
- $instructionsLabel.AutoSize = $true # Let it size itself to the text
- $instructionsLabel.Location = New-Object Drawing.Point(($form.Width - 200), ($form.Height - 120))
- $instructionsLabel.Text = "CONTROLS:`nSPACE - Jump`nESC - Pause/Resume`nR - Restart Game`nQ - Quit Game"
- $instructionsLabel.TextAlign = 'TopLeft'
- $form.Controls.Add($instructionsLabel)
- # Countdown display
- $countdownLabel = New-Object Windows.Forms.Label
- $countdownLabel.Font = New-Object Drawing.Font('Arial', 72, [Drawing.FontStyle]::Bold)
- $countdownLabel.ForeColor = [Drawing.Color]::Red
- $countdownLabel.BackColor = [Drawing.Color]::Transparent
- $countdownLabel.AutoSize = $true
- $countdownLabel.TextAlign = 'MiddleCenter'
- $form.Controls.Add($countdownLabel)
- # Pause label
- $pauseLabel = New-Object Windows.Forms.Label
- $pauseLabel.Font = New-Object Drawing.Font('Arial', 36, [Drawing.FontStyle]::Bold)
- $pauseLabel.ForeColor = [Drawing.Color]::Red
- $pauseLabel.BackColor = [Drawing.Color]::FromArgb(200, 255, 255, 255)
- $pauseLabel.AutoSize = $false
- $pauseLabel.Size = New-Object Drawing.Size(600, 80)
- $pauseLabel.Text = 'PAUSED - Press ESC to Resume'
- $pauseLabel.Visible = $false
- $pauseLabel.TextAlign = 'MiddleCenter'
- $form.Controls.Add($pauseLabel)
- # Enhanced pipe creation with better colors and styling
- function New-Pipe {
- $gapStart = 200 # Increased from 180 for easier gameplay
- $gapMin = $script:minPipeGap
- $script:pipeGap = [math]::Max($gapMin, $gapStart - [math]::Floor($script:score / 5))
- $maxTop = $form.Height - $script:pipeGap - 150
- $pipeTopHeight = Get-Random -Minimum 80 -Maximum $maxTop
- # Top pipe with enhanced styling
- $topPipe = New-Object Windows.Forms.Panel
- $topPipe.Width = 70
- $topPipe.Height = $pipeTopHeight
- $topPipe.Left = $form.Width
- $topPipe.Top = 0
- $topPipe.BackColor = [System.Drawing.Color]::ForestGreen
- $topPipe.BorderStyle = 'None'
- # Add pipe cap as a separate control for 3D effect
- $topCap = New-Object Windows.Forms.Panel
- $topCap.Width = 86
- $topCap.Height = 25
- $topCap.Left = $form.Width - 8
- $topCap.Top = $pipeTopHeight - 25
- $topCap.BackColor = [System.Drawing.Color]::DarkGreen
- $topCap.BorderStyle = 'FixedSingle'
- # Bottom pipe with enhanced styling
- $bottomPipe = New-Object Windows.Forms.Panel
- $bottomPipe.Width = 70
- $bottomPipe.Height = $form.Height - $pipeTopHeight - $script:pipeGap
- $bottomPipe.Left = $form.Width
- $bottomPipe.Top = $pipeTopHeight + $script:pipeGap
- $bottomPipe.BackColor = [System.Drawing.Color]::ForestGreen
- $bottomPipe.BorderStyle = 'None'
- # Add pipe cap as a separate control for 3D effect
- $bottomCap = New-Object Windows.Forms.Panel
- $bottomCap.Width = 86
- $bottomCap.Height = 25
- $bottomCap.Left = $form.Width - 8
- $bottomCap.Top = $pipeTopHeight + $script:pipeGap
- $bottomCap.BackColor = [System.Drawing.Color]::DarkGreen
- $bottomCap.BorderStyle = 'FixedSingle'
- $form.Controls.Add($topPipe)
- $form.Controls.Add($topCap)
- $form.Controls.Add($bottomPipe)
- $form.Controls.Add($bottomCap)
- return @($topPipe, $bottomPipe, $topCap, $bottomCap)
- }
- function Check-Collision {
- foreach ($pipeSet in $script:pipes) {
- # Only check collision with main pipes (first two elements)
- for ($i = 0; $i -lt 2; $i++) {
- $pipe = $pipeSet[$i]
- # Simple bounds checking - more reliable in PowerShell
- if ($bird.Left -lt ($pipe.Left + $pipe.Width) -and
- ($bird.Left + $bird.Width) -gt $pipe.Left -and
- $bird.Top -lt ($pipe.Top + $pipe.Height) -and
- ($bird.Top + $bird.Height) -gt $pipe.Top) {
- return $true
- }
- }
- }
- # Check boundaries
- if ($bird.Top -le 0 -or ($bird.Top + $bird.Height) -ge $form.Height) {
- return $true
- }
- return $false
- }
- function Update-LabelPositions {
- $countdownLabel.Location = New-Object Drawing.Point((($form.Width / 2) - 60), ($form.Height / 2) - 50)
- $pauseLabel.Location = New-Object Drawing.Point((($form.Width / 2) - 300), ($form.Height / 2) - 40)
- # Update instructions position on resize (just text, no box)
- $instructionsLabel.Location = New-Object Drawing.Point(($form.Width - 200), ($form.Height - 120))
- }
- function Restart-Game {
- $script:velocity = 0
- $script:birdY = 300
- $script:score = 0
- $script:frameCount = 0
- $script:lastPipeFrame = 0
- $script:pipeSpeed = 4
- $script:paused = $false
- $pauseLabel.Visible = $false
- # Clean up pipes (updated for new pipe structure)
- foreach ($pipeSet in $script:pipes) {
- foreach ($pipe in $pipeSet) {
- $form.Controls.Remove($pipe)
- $pipe.Dispose()
- }
- }
- $script:pipes = @()
- $bird.Location = New-Object Drawing.Point(200, $script:birdY)
- Update-LabelPositions
- Start-Countdown
- }
- function Start-Countdown {
- $count = 3
- $startTime = Get-Date
- $form.Controls.Add($countdownLabel)
- $countdownLabel.Visible = $true
- # Hide score panel during countdown so it doesn't overlay
- $scoreLabel.Visible = $false
- while ($form.Visible) {
- $elapsed = (Get-Date) - $startTime
- $seconds = [math]::Floor($elapsed.TotalSeconds)
- if ($seconds -le $count) {
- $remaining = $count - $seconds
- if ($remaining -gt 0) {
- $countdownLabel.Text = "$remaining"
- try { [System.Console]::Beep(600, 150) } catch { }
- }
- }
- elseif ($seconds -eq ($count + 1)) {
- $countdownLabel.Text = 'GO!'
- try { [System.Console]::Beep(800, 200) } catch { }
- }
- elseif ($seconds -gt ($count + 1.5)) {
- $countdownLabel.Visible = $false
- $scoreLabel.Visible = $true # Show score panel when game starts
- $script:gameRunning = $true
- break
- }
- Start-Sleep -Milliseconds 200
- [System.Windows.Forms.Application]::DoEvents()
- }
- }
- # Event handlers
- $form.Add_KeyDown({
- switch ($_.KeyCode) {
- 'Space' {
- if ($script:gameRunning -and -not $script:paused) {
- $script:velocity = $script:jumpStrength
- Play-JumpSound
- }
- }
- 'Escape' {
- if ($script:gameRunning) {
- $script:paused = -not $script:paused
- $pauseLabel.Visible = $script:paused
- Update-LabelPositions
- }
- }
- 'R' {
- if (-not $script:gameRunning -or $script:paused) {
- Restart-Game
- }
- }
- 'Q' {
- $form.Close()
- }
- }
- })
- $form.Add_Resize({
- Update-LabelPositions
- })
- # Add close button functionality (updated for new pipe structure and image cleanup)
- $form.Add_FormClosing({
- # Clean up resources
- foreach ($pipeSet in $script:pipes) {
- foreach ($pipe in $pipeSet) {
- $pipe.Dispose()
- }
- }
- # Clean up bird image if it exists
- if ($bird.Image) {
- $bird.Image.Dispose()
- }
- # Clean up temp image file
- $tempPath = [System.IO.Path]::GetTempPath() + "flappy_bird.png"
- if (Test-Path $tempPath) {
- Remove-Item $tempPath -Force -ErrorAction SilentlyContinue
- }
- })
- # Show form and start game
- $form.Show()
- $form.Focus()
- $form.KeyPreview = $true # Important for key events to work
- Update-LabelPositions
- Start-Countdown
- # Main game loop
- while ($form.Visible) {
- if ($script:gameRunning -and -not $script:paused) {
- # Bird physics
- $script:velocity += $script:gravity
- $script:birdY += $script:velocity
- $bird.Top = [math]::Max(0, [math]::Min($form.Height - $bird.Height, [math]::Round($script:birdY)))
- # Move pipes (updated for new pipe structure)
- foreach ($pipeSet in $script:pipes) {
- foreach ($pipe in $pipeSet) {
- $pipe.Left -= $script:pipeSpeed
- }
- }
- # Remove off-screen pipes (updated for new pipe structure)
- $newPipes = @()
- foreach ($pipeSet in $script:pipes) {
- if (($pipeSet[0].Left + $pipeSet[0].Width) -gt -50) {
- $newPipes += ,$pipeSet
- } else {
- # Remove all parts of the pipe set from form and dispose
- foreach ($pipe in $pipeSet) {
- $form.Controls.Remove($pipe)
- $pipe.Dispose()
- }
- }
- }
- $script:pipes = $newPipes
- # Generate new pipes
- if ($script:frameCount - $script:lastPipeFrame -ge 100) {
- $script:pipes += , (New-Pipe)
- $script:lastPipeFrame = $script:frameCount
- }
- # Score detection (updated for new pipe structure)
- foreach ($pipeSet in $script:pipes) {
- $pipeRight = $pipeSet[0].Left + $pipeSet[0].Width
- $birdLeft = $bird.Left
- # Check if bird just passed the pipe
- if ($pipeRight -lt $birdLeft -and $pipeRight -gt ($birdLeft - $script:pipeSpeed - 5)) {
- $script:score++
- Play-ScoreSound
- if ($script:score -gt $script:highScore) {
- $script:highScore = $script:score
- }
- # Increase difficulty gradually
- $script:pipeSpeed = [math]::Min($script:maxPipeSpeed, 4 + [math]::Floor($script:score / 10))
- break
- }
- }
- # Update score display
- $scoreLabel.Text = "Score: $script:score | High Score: $script:highScore"
- # Win condition
- if ($script:score -ge 50) {
- $script:gameRunning = $false
- [System.Windows.Forms.MessageBox]::Show("🎉 Congratulations! You're a Flappy Bird Master!`nFinal Score: $script:score", 'Victory!', 'OK', 'Information')
- $form.Close()
- }
- # Collision detection
- if (Check-Collision) {
- $script:gameRunning = $false
- Play-GameOverSound
- $result = [System.Windows.Forms.MessageBox]::Show("Game Over!`nScore: $script:score`nHigh Score: $script:highScore`n`nWould you like to play again?", 'Game Over', 'YesNo', 'Question')
- if ($result -eq 'Yes') {
- Restart-Game
- }
- else {
- $form.Close()
- }
- }
- $script:frameCount++
- }
- Start-Sleep -Milliseconds 30
- [System.Windows.Forms.Application]::DoEvents()
- }
Advertisement
Add Comment
Please, Sign In to add comment