3 people like it.

Missile Command playable in tsunami.io

Click on the tsunami.io button below to launch the online tsunami.io IDE with this snippet. Then select all the code (CTRL+A) and hit the Run button to start the game window, then just dock the window to the right of the code.. Click in the game window to launch missiles and save your cities.

  1: 
  2: 
  3: 
  4: 
  5: 
  6: 
  7: 
  8: 
  9: 
 10: 
 11: 
 12: 
 13: 
 14: 
 15: 
 16: 
 17: 
 18: 
 19: 
 20: 
 21: 
 22: 
 23: 
 24: 
 25: 
 26: 
 27: 
 28: 
 29: 
 30: 
 31: 
 32: 
 33: 
 34: 
 35: 
 36: 
 37: 
 38: 
 39: 
 40: 
 41: 
 42: 
 43: 
 44: 
 45: 
 46: 
 47: 
 48: 
 49: 
 50: 
 51: 
 52: 
 53: 
 54: 
 55: 
 56: 
 57: 
 58: 
 59: 
 60: 
 61: 
 62: 
 63: 
 64: 
 65: 
 66: 
 67: 
 68: 
 69: 
 70: 
 71: 
 72: 
 73: 
 74: 
 75: 
 76: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
207: 
208: 
209: 
210: 
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: 
228: 
229: 
230: 
231: 
232: 
233: 
234: 
235: 
236: 
237: 
238: 
239: 
240: 
241: 
242: 
243: 
244: 
245: 
246: 
247: 
248: 
249: 
250: 
251: 
252: 
253: 
254: 
255: 
256: 
257: 
258: 
259: 
260: 
261: 
262: 
263: 
264: 
265: 
266: 
267: 
268: 
269: 
270: 
271: 
272: 
273: 
#r "System.Windows.dll"

open System
open System.Collections.Generic
open System.Windows
open System.Windows.Controls
open System.Windows.Data
open System.Windows.Input
open System.Windows.Media
open System.Windows.Shapes
open System.Windows.Threading

[<AutoOpen>]
module Resources =
    let rand  = System.Random()
    let toPoints (xys) = 
        let coll = PointCollection()
        xys |> Seq.iter (fun (x,y) -> coll.Add(Point(x,y)))
        coll
    let toGradientStops stops =
        let collection = GradientStopCollection()
        stops
        |> List.map (fun (color,offset) -> GradientStop(Color=color,Offset=offset)) 
        |> List.iter collection.Add
        collection

type Missile (x,y,isBomb) =
    let canvas = Canvas ()
    let downBrush = LinearGradientBrush([Colors.Black,0.0;Colors.White,1.0] |> toGradientStops, 90.0)
    let upBrush = LinearGradientBrush([Colors.White,0.0;Colors.Black,1.0] |> toGradientStops, 90.0)
    let brush = if isBomb then downBrush else upBrush
    let line = Line(X1=x, Y1=y, X2=x, Y2=y, Stroke=brush)
    let endPoint = TranslateTransform()
    let missileBrush = SolidColorBrush(Colors.Red) :> Brush
    let circle = Ellipse(Width=3.0,Height=3.0,Fill=missileBrush,RenderTransform=endPoint)
    do  canvas.Children.Add line
        canvas.Children.Add circle
    member this.IsBomb = isBomb
    member this.Control = canvas
    member this.Update(x,y) =
        line.X2 <- x
        line.Y2 <- y
        endPoint.X <- x - 1.5
        endPoint.Y <- y - 1.5
    static member Path (x1,y1,x2,y2,velocity) = seq {
        let x, y = ref x1, ref y1
        let dx,dy = x2 - x1, y2 - y1
        let angle = atan2 dx dy
        let length = sqrt(dx * dx + dy * dy)
        let steps = length/velocity
        for i = 1 to int steps do
            y := !y + cos(angle)*velocity
            x := !x + sin(angle)*velocity
            yield !x , !y
        }

type Explosion (x,y) =
    let bombBrush = RadialGradientBrush(Colors.Yellow,Colors.White) :> Brush
    let explosion = Ellipse(Opacity=0.5, Fill=bombBrush)
    member this.Control = explosion
    member this.Update r =
        explosion.RenderTransform <- 
            TranslateTransform(X = x - r, Y = y - r)
        explosion.Width <- r * 2.0
        explosion.Height <- r * 2.0 
    static member Path radius = seq {
        for i in [50..2..100] do
            yield radius * ((float i / 100.0) ** 3.0)
        for i in [100..-1..0] do
            yield radius * ((float i / 100.0) ** 3.0)
        }

type City (x,y,width,height) =
    let canvas = Canvas ()
    let fill ws hs brush =
        let mutable i = 0
        do while i < width do
            let w = Seq.nth (Seq.length ws |> rand.Next) ws 
            let h = Seq.nth (Seq.length hs |> rand.Next) hs 
            Rectangle(Width=float w,Height=float h, Fill=brush,
                RenderTransform=TranslateTransform(X=x+float i,Y=y+float (height-h)))
            |> canvas.Children.Add
            i <- i + w
    do  SolidColorBrush Colors.Blue |> fill [2..4] [height/2..height] 
    do  SolidColorBrush Colors.Cyan |> fill [1..3] [height/4..height*2/3] 
    member this.Control = canvas
    member this.IsHit (x',y') =
        x' >= x && x' < x + float width &&
        y' >= y && y' < y + float height

type GameControl () as this =
    inherit UserControl ()

    let mutable disposables = []
    let remember disposable = disposables <- disposable :: disposables
    let dispose (d:IDisposable) = d.Dispose()
    let forget () = disposables |> List.iter dispose; disposables <- []

    let width, height = 500.0, 500.0
    do  this.Width <- width; this.Height <- height
    let skyBrush = 
        let darkBlue = Color.FromArgb(255uy,0uy,0uy,40uy)
        let stops = [Colors.Black,0.0; darkBlue,1.0] |> toGradientStops
        LinearGradientBrush(stops, 90.0)
    let canvas = Canvas(Background=skyBrush, Cursor=Cursors.Stylus)
    let add (x:#UIElement) = canvas.Children.Add x
    let remove (x:#UIElement) = canvas.Children.Remove x |> ignore

    let sandBrush = SolidColorBrush(Colors.Yellow)
    let planet = Rectangle(Width=width, Height=20.0, Fill=sandBrush)
    do  planet.RenderTransform <- TranslateTransform(X=0.0,Y=height-20.0)
    do  add planet
    let platform = System.Windows.Shapes.Polygon(Fill=sandBrush)
    do  platform.Points <- 
            let center = width/2.0
            [center,height-40.0;center-40.0,height;center+40.0,height]
            |> toPoints
    do  add platform

    let mutable score = 0
    let mutable cities = []
    let mutable missiles = []
    let mutable explosions = []
    let mutable wave = 5

    let scoreControl = TextBlock(Foreground=SolidColorBrush Colors.White)
    do  scoreControl.Text <- sprintf "SCORE %d" score
    do  add scoreControl

    do  cities <- [1..4] |> List.map (fun i -> City((width*(float i)/5.0)-25.0,height-33.3,40,15))
        cities |> List.iter (fun city -> add city.Control)

    let fireMissile (x1,y1,x2,y2,velocity,isBomb) =       
        let missile = Missile(x1,y1,isBomb)
        let path = Missile.Path(x1,y1,x2,y2,velocity)
        missiles <- ((x2,y2),missile,path.GetEnumerator()) :: missiles
        add missile.Control

    let startExplosion (x,y) = 
        let explosion = Explosion(x,y) 
        let path = Explosion.Path 50.0
        explosions <- ((x,y),explosion,path.GetEnumerator()) :: explosions
        explosion.Control |> add

    let dropBombs count =
        for i = 1 to count do 
        let x1, x2 = rand.NextDouble()*width, rand.NextDouble()*width
        fireMissile(x1,0.0,x2,height-20.0,1.0,true)

    let update () =
        let current, expired = 
            explosions |> List.partition (fun (_,_,path) -> path.MoveNext())
        explosions <- current
        expired |> List.iter (fun (_,explosion:Explosion,_) -> remove explosion.Control)
        current |> List.iter (fun (_,explosion,path) -> path.Current |> explosion.Update)

        let current, expired = missiles |> List.partition (fun (_,_,path) -> path.MoveNext())
        expired |> List.iter (fun (target,missile:Missile,path) -> 
            remove missile.Control
            startExplosion target
        )
        current |> List.iter (fun (_,missile:Missile,path) -> path.Current |> missile.Update)
        let hit,notHit,casualties = 
            current 
            |> List.fold  (fun (hit,notHit,casualties) missile ->
                let _,_, path = missile
                let x,y = path.Current
                let isHit = 
                    explosions |> List.exists (fun ((x',y'),_,path) ->
                        let r = path.Current
                        (x - x') ** 2.0 + (y - y') ** 2.0 < (r**2.0) 
                    )
                let casualty = cities |> List.tryFind (fun city -> city.IsHit(x,y))
            
                let casualties = 
                    match casualty with
                    | Some city -> city::casualties
                    | None -> casualties

                match isHit || Option.isSome casualty with
                | true -> (missile::hit,notHit,casualties)
                | false -> (hit,missile::notHit,casualties)          
            ) ([],[],[])
        hit |> List.iter (fun (_,missile,path) ->
            let x,y = path.Current
            startExplosion(x,y)
            remove missile.Control
        )
        missiles <- notHit
        score <- score + 10 * (hit |> List.filter (fun (_,missile,_) -> missile.IsBomb) |> List.length)
        casualties |> List.iter (fun city -> remove city.Control)
        cities <- cities |> List.filter (fun city -> casualties |> List.exists ((=) city) |> not)
        scoreControl.Text <- sprintf "SCORE %d" score

        if missiles.Length = 0 then
            wave <- wave + 1
            dropBombs wave

        cities.Length > 0

    let message s =
        let t = TextBlock(Text=s)
        t.HorizontalAlignment <- HorizontalAlignment.Center
        t.VerticalAlignment <- VerticalAlignment.Center
        t.Foreground <- SolidColorBrush Colors.White
        t

    let layout = Grid()

    let startGame () =
        dropBombs wave

        canvas.MouseLeftButtonDown
        |> Observable.subscribe (fun me ->
            let point = me.GetPosition(canvas)
            fireMissile(width/2.0,height-40.0,point.X,point.Y,2.0,false)
        )
        |> remember

        let timer = DispatcherTimer()
        timer.Interval <- TimeSpan.FromMilliseconds(20.0)
        timer.Tick
        |> Observable.subscribe (fun _ -> 
            let undecided = update ()
            if not undecided then
                message "The End" |> layout.Children.Add
                forget()
        )
        |> remember
        timer.Start()
        {new IDisposable with member this.Dispose() = timer.Stop()}
        |> remember
    
    do  layout.Children.Add canvas
        this.Content <- layout
    
    do  let t = message "Click to Start"
        layout.Children.Add t
        this.MouseLeftButtonUp
        |> Observable.subscribe (fun _ -> 
            forget ();
            layout.Children.Remove t |> ignore
            startGame() )
        |> remember

    interface System.IDisposable with
        member this.Dispose() = forget()

#r "Tsunami.IDESilverlight.dll"
#r "Telerik.Windows.Controls.dll"
#r "Telerik.Windows.Controls.Docking.dll"
#r "Telerik.Windows.Controls.Navigation.dll"
 
open Telerik.Windows.Controls
open Telerik.Windows.Controls.Docking
 
let dispatch f = Deployment.Current.Dispatcher.BeginInvoke(fun () -> f())
    
let pane content =
    // Find panes group
    let window = Application.Current.RootVisual :?> Tsunami.IDESilverlight.MainWindow
    let grid = window.Content :?> Grid
    let docking = grid.Children |> Seq.pick (function :? RadDocking as x -> Some x | _ -> None) 
    let container = docking.Items |> Seq.pick (function :? RadSplitContainer as x -> Some x | _ -> None)
    let group = container.Items |> Seq.pick (function :? RadPaneGroup as x -> Some x | _ -> None)
    // Add pane
    let pane = RadPane(Header="Game")
    pane.MakeFloatingDockable()
    group.Items.Add(pane)
    // Set content
    pane.Content <- content

dispatch <| fun () -> pane (new GameControl())
namespace System
namespace System.Collections
namespace System.Collections.Generic
namespace System.Windows
Multiple items
namespace System.Data

--------------------
namespace Microsoft.FSharp.Data
namespace System.Media
namespace System.Threading
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute
  new : path:string -> AutoOpenAttribute
  member Path : string

Full name: Microsoft.FSharp.Core.AutoOpenAttribute

--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
namespace System.Resources
val rand : Random

Full name: Script.Resources.rand
Multiple items
type Random =
  new : unit -> Random + 1 overload
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer:byte[] -> unit
  member NextDouble : unit -> float

Full name: System.Random

--------------------
Random() : unit
Random(Seed: int) : unit
val toPoints : xys:seq<'a * 'b> -> 'c

Full name: Script.Resources.toPoints
val xys : seq<'a * 'b>
val coll : 'c
module Seq

from Microsoft.FSharp.Collections
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
val x : 'a
val y : 'b
val toGradientStops : stops:('a * 'b) list -> 'c

Full name: Script.Resources.toGradientStops
val stops : ('a * 'b) list
val collection : 'c
Multiple items
type List<'T> =
  new : unit -> List<'T> + 2 overloads
  member Add : item:'T -> unit
  member AddRange : collection:IEnumerable<'T> -> unit
  member AsReadOnly : unit -> ReadOnlyCollection<'T>
  member BinarySearch : item:'T -> int + 2 overloads
  member Capacity : int with get, set
  member Clear : unit -> unit
  member Contains : item:'T -> bool
  member ConvertAll<'TOutput> : converter:Converter<'T, 'TOutput> -> List<'TOutput>
  member CopyTo : array:'T[] -> unit + 2 overloads
  ...
  nested type Enumerator

Full name: System.Collections.Generic.List<_>

--------------------
List() : unit
List(capacity: int) : unit
List(collection: IEnumerable<'T>) : unit
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val color : 'a
val offset : 'b
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
Multiple items
type Missile =
  new : x:obj * y:obj * isBomb:bool -> Missile
  member Update : x:'a * y:'b -> 'c
  member Control : obj
  member IsBomb : bool
  static member Path : x1:int * y1:int * x2:int * y2:int * velocity:int -> seq<int * int>

Full name: Script.Missile

--------------------
new : x:obj * y:obj * isBomb:bool -> Missile
val x : obj
val y : obj
val isBomb : bool
val canvas : obj
val downBrush : obj
val upBrush : obj
val brush : obj
val line : obj
val endPoint : obj
val missileBrush : obj
val circle : obj
val this : Missile
member Missile.IsBomb : bool

Full name: Script.Missile.IsBomb
Multiple items
member Missile.Control : obj

Full name: Script.Missile.Control

--------------------
namespace Microsoft.FSharp.Control
member Missile.Update : x:'a * y:'b -> 'c

Full name: Script.Missile.Update
static member Missile.Path : x1:int * y1:int * x2:int * y2:int * velocity:int -> seq<int * int>

Full name: Script.Missile.Path
val x1 : int
val y1 : int
val x2 : int
val y2 : int
val velocity : int
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val x : int ref
val y : int ref
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val dx : int
val dy : int
val angle : int
val atan2 : y:'T1 -> x:'T1 -> 'T2 (requires member Atan2)

Full name: Microsoft.FSharp.Core.Operators.atan2
val length : int
val sqrt : value:'T -> 'U (requires member Sqrt)

Full name: Microsoft.FSharp.Core.Operators.sqrt
val steps : int
val i : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val cos : value:'T -> 'T (requires member Cos)

Full name: Microsoft.FSharp.Core.Operators.cos
val sin : value:'T -> 'T (requires member Sin)

Full name: Microsoft.FSharp.Core.Operators.sin
Multiple items
type Explosion =
  new : x:obj * y:obj -> Explosion
  member Update : r:'a -> 'b
  member Control : obj
  static member Path : radius:float -> seq<float>

Full name: Script.Explosion

--------------------
new : x:obj * y:obj -> Explosion
val bombBrush : obj
val explosion : obj
val this : Explosion
Multiple items
member Explosion.Control : obj

Full name: Script.Explosion.Control

--------------------
namespace Microsoft.FSharp.Control
member Explosion.Update : r:'a -> 'b

Full name: Script.Explosion.Update
val r : 'a
static member Explosion.Path : radius:float -> seq<float>

Full name: Script.Explosion.Path
val radius : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
Multiple items
type City =
  new : x:float * y:float * width:int * height:int -> City
  member IsHit : x':float * y':float -> bool
  member Control : obj

Full name: Script.City

--------------------
new : x:float * y:float * width:int * height:int -> City
val x : float
val y : float
val width : int
val height : int
val fill : (seq<int> -> seq<'a> -> 'b -> unit)
val ws : seq<int>
val hs : seq<'a>
val brush : 'b
val mutable i : int
val w : int
val nth : index:int -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.nth
val length : source:seq<'T> -> int

Full name: Microsoft.FSharp.Collections.Seq.length
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val h : 'a
val this : City
Multiple items
member City.Control : obj

Full name: Script.City.Control

--------------------
namespace Microsoft.FSharp.Control
member City.IsHit : x':float * y':float -> bool

Full name: Script.City.IsHit
val x' : float
val y' : float
Multiple items
type GameControl =
  inherit obj
  interface IDisposable
  new : unit -> GameControl

Full name: Script.GameControl

--------------------
new : unit -> GameControl
val this : GameControl
type IDisposable =
  member Dispose : unit -> unit

Full name: System.IDisposable
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
namespace System.Text
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
namespace Microsoft.FSharp.Control
static member Missile.Path : x1:int * y1:int * x2:int * y2:int * velocity:int -> seq<int * int>
static member Explosion.Path : radius:float -> seq<float>
Random.NextDouble() : float
val partition : predicate:('T -> bool) -> list:'T list -> 'T list * 'T list

Full name: Microsoft.FSharp.Collections.List.partition
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State

Full name: Microsoft.FSharp.Collections.List.fold
val exists : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.exists
val tryFind : predicate:('T -> bool) -> list:'T list -> 'T option

Full name: Microsoft.FSharp.Collections.List.tryFind
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
module Option

from Microsoft.FSharp.Core
val isSome : option:'T option -> bool

Full name: Microsoft.FSharp.Core.Option.isSome
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val length : list:'T list -> int

Full name: Microsoft.FSharp.Collections.List.length
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
module Observable

from Microsoft.FSharp.Control
val subscribe : callback:('T -> unit) -> source:IObservable<'T> -> IDisposable

Full name: Microsoft.FSharp.Control.Observable.subscribe
Multiple items
type TimeSpan =
  struct
    new : ticks:int64 -> TimeSpan + 3 overloads
    member Add : ts:TimeSpan -> TimeSpan
    member CompareTo : value:obj -> int + 1 overload
    member Days : int
    member Duration : unit -> TimeSpan
    member Equals : value:obj -> bool + 1 overload
    member GetHashCode : unit -> int
    member Hours : int
    member Milliseconds : int
    member Minutes : int
    ...
  end

Full name: System.TimeSpan

--------------------
TimeSpan()
TimeSpan(ticks: int64) : unit
TimeSpan(hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : unit
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : unit
TimeSpan.FromMilliseconds(value: float) : TimeSpan
override GameControl.Dispose : unit -> unit

Full name: Script.GameControl.Dispose
val dispatch : f:'a -> 'b

Full name: Script.dispatch
val f : 'a
namespace System.Deployment
val pane : content:'a -> 'b

Full name: Script.pane
val content : 'a
val window : obj
val grid : obj
val docking : obj
val pick : chooser:('T -> 'U option) -> source:seq<'T> -> 'U

Full name: Microsoft.FSharp.Collections.Seq.pick
val container : obj
val group : obj
val pane : obj
Raw view Test code New version

More information

Link:http://fssnip.net/jQ
Posted:10 years ago
Author:Phillip Trelford
Tags: game