functions/utility/New-MiniGameRunUtility.ps1
|
function New-MiniGameRunUtility { <# .SYNOPSIS This return a utility class for running a game loop. .DESCRIPTION This return a utility class for running a game loop. It combines several other utility classes: - MiniGameObjectUtility - MiniGameDrawUtility - MiniGameSoundUtility Itself can handle: - reading keyboard input - easy aliases for keypresses (LeftArrow => A) - starting a gameloop with vars, functions and all utility classes .OUTPUTS .EXAMPLE PS> $gameUtility = New-MiniGameRunUtility -InvertY -Mute # Variables for the gameloop can be defined here. # These are availabe as the '$var'-Parameter. $gameUtility.set( @{ LifePoints = 5 Damage = 2 } ) # Custom sound from files can be registered here. # These are availabe in the 'once' and 'loop'-function via sound.once("damage") or sound.loop("music"). $gameUtility.sound.add("music", "./path/to/music.wav") $gameUtility.sound.add("damage", "./path/to/hit.wav") # Define a player as an object. $player = $gameUtility.object.Add("player 1") $player.setPos(40,0) $player.AddCanvas('Right', @( " O_", " Ä " ) ) $player.AddCanvas('Left', @( "_O ", " Ä " ) ) # For Key Pressed any number of aliases can be registered $gameUtility.alias([System.ConsoleKey]::A, [System.ConsoleKey]::LeftArrow) $gameUtility.alias([System.ConsoleKey]::D, [System.ConsoleKey]::RightArrow) # Move the player on key presses $gameUtility.onKey([System.ConsoleKey]::A, { param($key, $var, $func, $canvas, $sound, $object, $stop) $object.Get("Player 1").SetCanvas('Left') $object.Get("Player 1").Move(-1, 0) $object.Get("Player 1").Redraw() } ) $gameUtility.onKey([System.ConsoleKey]::D, { param($key, $var, $func, $canvas, $sound, $object, $stop) $object.Get("Player 1").SetCanvas('Right') $object.Get("Player 1").Move(1, 0) $object.Get("Player 1").Redraw() } ) $gameUtility.once( { # This is similar to the gameloop but only executed once. # This is useful for setting up variables, a looping music and other setups that only need to be executed once. param($var, $func, $canvas, $sound, $object, $stop) $sound.loop("music") $object.draw() } ) $gameUtility.loop( { # The first script-block gets executed in a gameloop param($var, $func, $canvas, $sound, $object, $stop) # Access and modify the defined Variables if($wasHit) { $var.LifePoints -= 1 } # Look at New-MiniGameDrawUtility # $canvas can be used to draw text in certain colors on the screen $canvas.ForeGround.onceColor("Red") $canvas.draw(0, 10, "Hello World") # Look at New-MiniGameSoundUtility # $sound can be used to play custom sounds from files $sound.once("My Sound") # Stops the gameloop when a condition is met if($var.LifePoints -LE 0){ $stop.Invoke() } }, { # The second (optional) script-block always gets executed # - when the game ended # - was exited unexpectedly param($var, $func, $canvas, $sound, $object, $static) } ) .LINK #> <# TODO: - Mouse input handling with [System.Windows.Forms.Curosr]::Position #> [CmdletBinding()] param ( [Parameter( Position = 0, Mandatory = $false )] [System.Int32] [ValidateRange(1, 1000)] $TickSpanMilliseconds = 100, <# Explicitly mutes the sound, even when the sound.play() function is called. Sound is by default only played when called via $sound.play() in the game.loop or game.once function. #> [Parameter( Position = 1, Mandatory = $false )] [switch] $Mute, <# Setting custom boundaries for drawing objects. Defaults to full console window size. #> [Parameter( Mandatory = $false )] [System.Int32] $MaximumX = -1, [Parameter( Mandatory = $false )] [System.Int32] $MaximumY = -1, [Parameter( Mandatory = $false )] [System.Int32] $MinimumX = 0, [Parameter( Mandatory = $false )] [System.Int32] $MinimumY = 0, # Inverts drawing on the Y-Axis. Normally Y=0 points to the top of the screen. # This is usefull for having elements fly from the bottom upwards. [Parameter()] [switch] $InvertY, # Inverts drawing on the X-Axis. Normally X=0 points to the left side of the screen. # Might not be useful but complement to InvertY $InvertX, # This automatically trims empty spaces from inputet strings. [Parameter( Mandatory = $false )] [System.Boolean] $TrimSpaces = $true ) $drawSettings = @{ MinimumX = $MinimumX MinimumY = $MinimumY MaximumX = $MaximumX MaximumY = $MaximumY TrimSpaces = $TrimSpaces InvertY = $InvertY.IsPresent InvertX = $InvertX.IsPresent } $objectUtility = New-MiniGameObjectUtility @drawSettings $soundUtility = New-MiniGameSoundUtility -Mute:$Mute class MiniGameRunUtility { [System.Collections.Hashtable] $Functions = @{} [System.Collections.Hashtable] $Variables = @{ ticks = 0 } [System.Collections.Hashtable] $Settings = @{ TickSpanMilliseconds = $TickSpanMilliseconds GameRunning = $true CursorVisibility = $false OnceScriptRun = $false } [System.Collections.Hashtable] $EventHandler = @{ keyEvent = @{} } $Sound = $soundUtility $Object = $objectUtility $Canvas = $objectUtility.canvas MiniGameRunUtility() {} [Void] Stop() { $this.Settings.GameRunning = $false } [Void] Clear() { $this.Canvas.Clear() } [Void] Set([System.String] $name, [System.Object] $value) { $this.Variables.Remove($name) $this.Variables.Add($name, $value) } [Void] Func([System.String] $name, [scriptblock] $action) { $this.Functions.Remove($name) $this.Functions.Add($name, $action) } [Void] Set([System.Collections.Hashtable] $variables) { $variables.GetEnumerator() | ForEach-Object { $this.set($_.Key, $_.Value) } } [Void] Once([scriptblock] $action) { $this.Clear() $this.Settings.OnceScriptRun = $true $action.Invoke( $this.Variables, $this.Functions, $this.Canvas, $this.Sound, $this.Object, $this.Stop ) } [Void] Loop([scriptblock] $action) { $this.loop($action, {}) } [Void] Loop([scriptblock] $action, [scriptblock] $final) { if (-NOT $this.Settings.OnceScriptRun) { $this.Clear() } try { :GameLoop while ($this.Settings.GameRunning) { [System.Console]::CursorVisible = $this.CursorVisibility $this.processKeys() $action.Invoke( $this.Variables, $this.Functions, $this.Canvas, $this.Sound, $this.Object, $this.Stop ) $this.Variables.ticks += 1 Start-Sleep -Milliseconds $this.Settings.TickSpanMilliseconds } } finally { $this.Sound.Stop() $final.Invoke( $this.Variables, $this.Functions, $this.Canvas, $this.Sound, $this.Object ) } } <# This processes key inputs and execute the action associated with the key. #> [void] ProcessKeys() { $this.processKeys($false, 1) } [Void] ProcessKeys([System.Boolean] $blocking) { $this.processKeys($blocking, 1) } [Void] ProcessKeys([System.Boolean] $blocking, [System.Byte] $expectedKeys) { while ([System.Console]::KeyAvailable -OR $blocking ) { $keyEvent = [System.Console]::ReadKey($true) $handlers = $this.EventHandler.keyEvent $script = $handlers[$keyEvent.Key] # If the script is a key alias, get the actual script while ($script -IS [System.ConsoleKey]) { $script = $handlers[$script] } if ($null -NE $script) { $script.Invoke( $keyEvent, $this.Variables, $this.Functions, $this.Canvas, $this.Sound, $this.Object, $this.Stop ) } # When blocking execute only for expected key amounts if ($blocking -AND --$expectedKeys -LE 0) { return } } } <# This defines actions in key pressens: key: The name of the pressed key action: A script block #> [Void] OnKey([System.ConsoleKey] $key, [ScriptBlock] $action) { $this.EventHandler.keyEvent.Remove($key) $this.EventHandler.keyEvent.Add($key, $action) } <# This processes key inputs and execute the action associated with the key. Source: The name of the pressed key Alias: The Alias to set for the key #> [void] Alias([System.ConsoleKey] $Source, [System.ConsoleKey] $Alias) { $this.EventHandler.keyEvent.Remove($Alias) $this.EventHandler.keyEvent.Add($Alias, $Source) } [void] RemoveKey([System.ConsoleKey] $key) { $this.EventHandler.keyEvent.Remove($key) } [void] RemoveAlias([System.ConsoleKey] $key) { $this.EventHandler.keyEvent.Remove($key) } } return [MiniGameRunUtility]@{} } |