Created
September 23, 2016 03:32
-
-
Save GuyCarver/465e95dfac21e1a101a3eeb3c81c662d to your computer and use it in GitHub Desktop.
F# version of pong.cs example for Continuous app. Only partially implemented due to some bugs in the app.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Pong Example | |
// | |
// Implements a basic version of the classic game for two players. | |
// Swipe up and down on the left to move the left paddle, and | |
// swipe on the right side for the right paddle. | |
// | |
// Tip: If the editor freezes while you type, | |
// turn off "Auto Run" in the settings. | |
// | |
// Exercises: | |
// 1. Change the color of the ball to green | |
// 2. Change the size of the paddles | |
// 3. Make the ball move faster | |
// 4. Add multiple balls | |
// 5. Add an AI to control the second paddle | |
// | |
open System | |
open CoreGraphics | |
open SceneKit | |
open UIKit | |
[<NoComparison>] | |
type PongDefaults = { | |
BallSize : float //= 5.0f; | |
BallColor : UIColor //= UIColor.Yellow; | |
BallRestitution : float //= 2.01f; | |
LeftPaddleHeight : nfloat //= 30.0f; | |
RightPaddleHeight : nfloat //= 30.0f; | |
} | |
let defaults = { BallSize = 5.0; BallColor = UIColor.Yellow; BallRestitution = 2.01; | |
LeftPaddleHeight = nfloat(30.0); RightPaddleHeight = nfloat(30.0) } | |
type Ball = | |
val mutable Node : SCNNode | |
new ( ) as self = | |
{ | |
Node = null | |
} | |
then | |
let geom = SCNSphere.Create(nfloat(defaults.BallSize)) | |
geom.FirstMaterial.Diffuse.ContentColor <- defaults.BallColor | |
self.Node <- SCNNode.FromGeometry(geom) | |
// Attach a light to the ball | |
let ln = SCNNode.Create() | |
ln.Light <- SCNLight.Create() | |
ln.Position <- SCNVector3(0.0f,0.0f,float32(defaults.BallSize) * 4.0f) | |
self.Node.Add ln | |
// Add physics to the ball | |
self.Node.PhysicsBody <- SCNPhysicsBody.CreateDynamicBody() | |
self.Node.PhysicsBody.Damping <- nfloat(0.0) | |
self.Node.PhysicsBody.Friction <- nfloat(0.0) | |
self.Node.PhysicsBody.Restitution <- nfloat(defaults.BallRestitution) | |
let options = SCNPhysicsShapeOptions() | |
self.Node.PhysicsBody.PhysicsShape <- SCNPhysicsShape.Create(geom, options) | |
self.Node.PhysicsBody.CategoryBitMask <- nuint(1u) | |
self.Node.PhysicsBody.CollisionBitMask <- nuint(1u) | |
self.Node.PhysicsBody.ContactTestBitMask <- nuint(1u) | |
type Paddle = | |
val mutable Node : SCNNode | |
new ((x : float32), (h : nfloat)) as self = | |
{ | |
Node = null | |
} | |
then | |
let geom = SCNBox.Create(nfloat(4.0), h, nfloat(20.0), nfloat(0.0)) | |
geom.FirstMaterial.Diffuse.ContentColor <- UIColor.LightGray | |
geom.FirstMaterial.Specular.ContentColor <- UIColor.Yellow | |
geom.FirstMaterial.Specular.Intensity <- nfloat(1.0) | |
self.Node <- SCNNode.FromGeometry(geom) | |
self.Node.Position <- SCNVector3(x,0.0f,0.0f) | |
self.Node.PhysicsBody <- SCNPhysicsBody.CreateStaticBody() | |
let options = SCNPhysicsShapeOptions() | |
self.Node.PhysicsBody.PhysicsShape <- SCNPhysicsShape.Create(geom, options) | |
self.Node.PhysicsBody.CategoryBitMask <- nuint(1u) | |
self.Node.PhysicsBody.CollisionBitMask <- nuint(1u) | |
self.Node.PhysicsBody.ContactTestBitMask <- nuint(1u) | |
type Wall = | |
val mutable Node : SCNNode | |
new (y : float32) as self = | |
{ | |
Node = null | |
} | |
then | |
let geom = SCNBox.Create(nfloat(320.0), nfloat(4.0), nfloat(15.0), nfloat(0.0)) | |
geom.FirstMaterial.Diffuse.ContentColor <- UIColor.DarkGray | |
geom.FirstMaterial.Specular.ContentColor <- UIColor.Yellow | |
geom.FirstMaterial.Specular.Intensity <- nfloat(1.0) | |
self.Node <- SCNNode.FromGeometry(geom) | |
self.Node.Position <- SCNVector3(0.0f,y,0.0f) | |
self.Node.PhysicsBody <- SCNPhysicsBody.CreateStaticBody() | |
let options = SCNPhysicsShapeOptions() | |
self.Node.PhysicsBody.PhysicsShape <- SCNPhysicsShape.Create(geom, options) | |
self.Node.PhysicsBody.CategoryBitMask <- nuint(1u) | |
self.Node.PhysicsBody.CollisionBitMask <- nuint(1u) | |
self.Node.PhysicsBody.ContactTestBitMask <- nuint(1u) | |
type Goal = | |
val mutable Node : SCNNode | |
new (x : float32) as self = | |
{ | |
Node = null | |
} | |
then | |
let geom = SCNBox.Create(nfloat(6.0), nfloat(400.0), nfloat(20.0), nfloat(0.0)) | |
geom.FirstMaterial.Diffuse.ContentColor <- UIColor.Black | |
self.Node <- SCNNode.FromGeometry(geom) | |
self.Node.Position <- SCNVector3(x,0.0f,0.0f) | |
self.Node.PhysicsBody <- SCNPhysicsBody.CreateKinematicBody() | |
let options = SCNPhysicsShapeOptions() | |
self.Node.PhysicsBody.PhysicsShape <- SCNPhysicsShape.Create(geom, options) | |
self.Node.PhysicsBody.CategoryBitMask <- nuint(1u) | |
self.Node.PhysicsBody.CollisionBitMask <- nuint(1u) | |
self.Node.PhysicsBody.ContactTestBitMask <- nuint(1u) | |
type Camera () = | |
let camera = SCNCamera.Create() | |
let _node = SCNNode.Create() | |
do | |
_node.Camera <- camera | |
_node.Position <- SCNVector3 (0.0f,0.0f,150.0f) | |
camera.ZNear <- 1.0 | |
camera.ZFar <- 150.0 | |
// Attach a light to the camera | |
let ln = SCNNode.Create() | |
ln.Light <- SCNLight.Create() | |
ln.Position <- SCNVector3(0.0f,0.0f,50.0f) | |
_node.Add ln | |
member x.Node with get() = _node | |
// | |
// Create the game | |
// | |
let mutable playerScore = 0 | |
let mutable aiScore = 0 | |
let cam = Camera() | |
let ball = Ball() | |
let playerPaddle = Paddle(-90.0f, defaults.LeftPaddleHeight) | |
let aiPaddle = Paddle(90.0f, defaults.RightPaddleHeight) | |
let topWall = Wall(70.0f) | |
let botWall = Wall(-70.0f) | |
let playerGoal = Goal(-130.0f) | |
let aiGoal = Goal(130.0f) | |
let scoreLabel : UILabel = new UILabel() | |
scoreLabel.Text <- "0 : 0" | |
scoreLabel.TextAlignment <- UITextAlignment.Center | |
scoreLabel.Font <- UIFont.SystemFontOfSize(nfloat(100.0)) | |
scoreLabel.TextColor <-UIColor.White.ColorWithAlpha(nfloat(0.25)) | |
scoreLabel.AutoresizingMask <- UIViewAutoresizing.FlexibleDimensions | |
scoreLabel.AdjustsFontSizeToFitWidth <- true | |
// | |
// Create the view | |
// | |
let scene = SCNScene.Create() | |
scene.PhysicsWorld.Gravity <- SCNVector3.Zero | |
let root = scene.RootNode | |
let UpdateScore () = | |
scoreLabel.BeginInvokeOnMainThread(fun () -> | |
scoreLabel.Text <- "{playerScore} : {aiScore}" | |
) | |
let sceneView = new SCNView(CGRect(nfloat(0.0),nfloat(0.0),nfloat(320.0),nfloat(320.0))) | |
sceneView.BackgroundColor <- UIColor.Black | |
sceneView.Scene <- scene | |
scoreLabel.Frame <- sceneView.Bounds | |
sceneView.AddSubview(scoreLabel) | |
root.Add(cam.Node) | |
root.Add(ball.Node) | |
root.Add(playerPaddle.Node) | |
root.Add(aiPaddle.Node) | |
root.Add(topWall.Node) | |
root.Add(botWall.Node) | |
root.Add(playerGoal.Node) | |
root.Add(aiGoal.Node) | |
sceneView.PointOfView <- cam.Node | |
let rand = Random() | |
let ResetBallPosition (x : float32) = | |
printfn "resetting" | |
let mutable vx = float32(rand.NextDouble()) * 75.0f + 75.0f | |
let mutable vy = float32(rand.NextDouble()) * 50.0f + 50.0f | |
if (x > 0.0f) then vx <- -vx | |
if (rand.Next(2) = 0) then vy <- -vy | |
ball.Node.Position <- SCNVector3(x, 0.0f, 0.0f) | |
match ball.Node.PhysicsBody with | |
| null -> printfn "null pb" | |
| x -> x.Velocity <- SCNVector3(vx, vy, 0.0f) | |
x.ResetTransform() | |
ResetBallPosition(0.0f) | |
(* causing exception. | |
scene.PhysicsWorld.DidBeginContact.Add( (e : SCNPhysicsContactEventArgs) -> | |
ResetBallPosition 0 | |
//let otherNode = match bal.node with | |
//| e.Contact.NodeA -> e.Contact.NodeB | |
//| e.Contact.NodeB -> e.Contact.NodeA | |
//| _ -> null | |
//ignore(match othernode with | |
//| playerGoal.Node -> | |
//Console.WriteLine("HIT PLAYER"); | |
// aiScore <- aiScore + 1 | |
// ResetBallPosition 50 | |
// UpdateScore() | |
//| aiGoal.Node -> | |
//Console.WriteLine("HIT AI"); | |
// playerScore <- playerScore + 1 | |
// ResetBallPosition -50 | |
// UpdateScore() | |
//| _ -> () | |
//) | |
//e.Contact.NodeA.Geometry.FirstMaterial.Diffuse.ContentColor=UIColor.Red; | |
) | |
*) | |
let panGesture = new UIPanGestureRecognizer (fun (g : UIPanGestureRecognizer) -> | |
match int(g.NumberOfTouches) with | |
| 0 -> () | |
| n -> | |
for i in 0 .. n do | |
let viewLoc = g.LocationOfTouch(nint(i), sceneView) | |
let a = viewLoc.X | |
let b = viewLoc.Y | |
let p = sceneView.UnprojectPoint SCNVector3(float32(a), float32(b), 1.0f) | |
//printfn "%d:%s" i p.ToString() | |
//this causes and exception cuz X isn't accessible for some reason. | |
if p.X < 0.0f then | |
playerPaddle.Node.Position <- SCNVector3(-90.0f, p.Y, 0.0f) | |
playerPaddle.Node.PhysicsBody.ResetTransform() | |
else | |
aiPaddle.Node.Position <- SCNVector3(90.0f, p.Y, 0.0f) | |
aiPaddle.Node.PhysicsBody.ResetTransform() | |
) | |
let tapGesture = new UITapGestureRecognizer (fun (g : UITapGestureRecognizer) -> ResetBallPosition float32(0.0) ) | |
tapGesture.NumberOfTapsRequired <- nuint(2u) | |
sceneView.AddGestureRecognizer(panGesture) | |
sceneView.AddGestureRecognizer(tapGesture) | |
let Main = sceneView | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment