3 people like it.
Like the snippet!
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
More information