0 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
namespace System.Windows.Input
Multiple items
type AutoOpenAttribute =
  inherit Attribute
  new : unit -> AutoOpenAttribute + 1 overload
  member Path : string

--------------------
new : unit -> AutoOpenAttribute
new : path:string -> AutoOpenAttribute
namespace System.Resources
val rand : Random
Multiple items
type Random =
  new : unit -> unit + 1 overload
  member GetSampleForLargeRange : unit -> float
  member InternalSample : unit -> int
  member Next : unit -> int + 2 overloads
  member NextBytes : buffer: byte [] -> unit + 1 overload
  member NextDouble : unit -> float
  member Sample : unit -> float
  static member GenerateGlobalSeed : unit -> int
  static member GenerateSeed : unit -> int
  static val s_globalRandom : Random
  ...

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

from Microsoft.FSharp.Collections
val iter : action:('T -> unit) -> source:seq<'T> -> unit
val x : 'a
val y : 'b
val toGradientStops : stops:('a * 'b) list -> 'c
val stops : ('a * 'b) list
val collection : 'c
Multiple items
type List<'T> =
  interface IList<'T>
  interface ICollection<'T>
  interface IEnumerable<'T>
  interface IEnumerable
  interface IList
  interface ICollection
  interface IReadOnlyList<'T>
  interface IReadOnlyCollection<'T>
  new : unit -> unit + 2 overloads
  member Add : item: 'T -> unit
  ...

--------------------
List() : List<'T>
List(capacity: int) : List<'T>
List(collection: IEnumerable<'T>) : List<'T>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list
val color : 'a
val offset : 'b
val iter : action:('T -> unit) -> list:'T list -> unit
Multiple items
type Missile =
  new : x:obj * y:obj * isBomb:bool -> Missile
  member Update : x:'a * y:'b -> 'c
  static member Path : x1:int * y1:int * x2:int * y2:int * velocity:int -> seq<int * int>
  member Control : obj
  member IsBomb : bool

--------------------
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
val x1 : int
val y1 : int
val x2 : int
val y2 : int
val velocity : int
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

--------------------
type seq<'T> = IEnumerable<'T>
val x : int ref
val y : int ref
Multiple items
val ref : value:'T -> 'T ref

--------------------
type 'T ref = Ref<'T>
val dx : int
val dy : int
val angle : int
val atan2 : y:'T1 -> x:'T1 -> 'T2 (requires member Atan2)
val length : int
val sqrt : value:'T -> 'U (requires member Sqrt)
val steps : int
val i : int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

--------------------
[<Struct>]
type int = int32

--------------------
type int<'Measure> =
  int
val cos : value:'T -> 'T (requires member Cos)
val sin : value:'T -> 'T (requires member Sin)
Multiple items
type Explosion =
  new : x:obj * y:obj -> Explosion
  member Update : r:'a -> 'b
  static member Path : radius:float -> seq<float>
  member Control : obj

--------------------
new : x:obj * y:obj -> Explosion
val bombBrush : obj
val explosion : obj
val this : Explosion
val r : 'a
val radius : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

--------------------
[<Struct>]
type float = Double

--------------------
type float<'Measure> =
  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

--------------------
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 length : source:seq<'T> -> int
Random.Next() : int
Random.Next(maxValue: int) : int
Random.Next(minValue: int, maxValue: int) : int
val h : 'a
val this : City
val x' : float
val y' : float
Multiple items
type GameControl =
  interface IDisposable
  new : unit -> GameControl

--------------------
new : unit -> GameControl
val this : GameControl
type IDisposable =
  member Dispose : unit -> unit
val ignore : value:'T -> unit
val sprintf : format:Printf.StringFormat<'T> -> 'T
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
val fold : folder:('State -> 'T -> 'State) -> state:'State -> list:'T list -> 'State
val exists : predicate:('T -> bool) -> list:'T list -> bool
val tryFind : predicate:('T -> bool) -> list:'T list -> 'T option
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
val filter : predicate:('T -> bool) -> list:'T list -> 'T list
val length : list:'T list -> int
val not : value:bool -> bool
namespace System.Text
module Observable

from Microsoft.FSharp.Control
val subscribe : callback:('T -> unit) -> source:IObservable<'T> -> IDisposable
Multiple items
[<Struct>]
type TimeSpan =
  new : ticks: int64 -> unit + 3 overloads
  member Add : ts: TimeSpan -> TimeSpan
  member CompareTo : value: obj -> int + 1 overload
  member Divide : divisor: float -> TimeSpan + 1 overload
  member Duration : unit -> TimeSpan
  member Equals : value: obj -> bool + 2 overloads
  member GetHashCode : unit -> int
  member Multiply : factor: float -> TimeSpan
  member Negate : unit -> TimeSpan
  member Subtract : ts: TimeSpan -> TimeSpan
  ...

--------------------
TimeSpan ()
TimeSpan(ticks: int64) : TimeSpan
TimeSpan(hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : TimeSpan
TimeSpan.FromMilliseconds(value: float) : TimeSpan
val dispatch : f:'a -> 'b
val f : 'a
val pane : content:'a -> 'b
val content : 'a
val window : obj
val grid : obj
val docking : obj
val pick : chooser:('T -> 'U option) -> source:seq<'T> -> 'U
val container : obj
val group : obj
val pane : obj

More information

Link:http://fssnip.net/jQ
Posted:9 days ago
Author:Phillip Trelford
Tags: game