Brick Breaker Clone Made Entirely on my iPhone!

I made a pretty simple Brick Breaker clone using an IDE called Continuous Development Environment for iOS. 

I made the game almost entirely on the bus, lunch breaks, 10 minute breaks, and various other times I had a few free minutes to kill. 

I learned a little bit about SceneKit and some of the other Xamarian libraries proprietary to iOS. 

I have a short little video demonstrating gameplay and going over a little bit of the script in the IDE that I made the game. 

This was primarily done as a proof of concept that I could make a game for my phone on my phone. I have made one other game that is a Helicopter Game clone with the Continuous IDE.

The code is included below (It is still in development, so there are unused functions)

 

using System;

using CoreGraphics; using SceneKit; using UIKit;

public int lives = 3; int score = 0; public int brickCount = 8; public int speed = 60; public bool flash;

static class GameDefaults { public static float size = 1.5f; public static float brickSize = 2f; public static UIColor color = UIColor.Yellow; public static UIColor redColor = UIColor.Red; public static UIColor blackColor = UIColor.Black; public static UIColor brickColor = UIColor.Blue; public static float restitution = 2.01f; public static float height = 30.0f; }

class Ball { public readonly SCNNode Node; public Ball() { var geom = SCNSphere.Create(GameDefaults.size); geom.FirstMaterial.Diffuse.ContentColor = GameDefaults.color; Node = SCNNode.FromGeometry(geom);

// Attach a light to the ball
    var ln = SCNNode.Create();
    ln.Light = SCNLight.Create();
    ln.Position = new SCNVector3(0,0,GameDefaults.size*4);
    Node.Add(ln);

    Node.Position = new SCNVector3(0,10,0);

    // Add physics to the ball
    Node.PhysicsBody = SCNPhysicsBody.CreateDynamicBody();
    Node.PhysicsBody.Damping = 0;
    Node.PhysicsBody.Friction = 0;
    Node.PhysicsBody.Restitution = GameDefaults.restitution;
    Node.PhysicsBody.AffectedByGravity = false;
    var options = new SCNPhysicsShapeOptions();
    Node.PhysicsBody.PhysicsShape = SCNPhysicsShape.Create(geom, options);
    Node.PhysicsBody.CategoryBitMask = 1u;
    Node.PhysicsBody.CollisionBitMask = 1u;
    Node.PhysicsBody.ContactTestBitMask = 1u;
}

}

class Paddle { public readonly SCNNode Node; public Paddle(float w, float h, float y) { var geom = SCNBox.Create(w, h, 20, 0); geom.FirstMaterial.Diffuse.ContentColor = UIColor.LightGray; geom.FirstMaterial.Specular.ContentColor = UIColor.Yellow; geom.FirstMaterial.Specular.Intensity = 1; Node = SCNNode.FromGeometry(geom); Node.Position = new SCNVector3(0,y,0); Node.PhysicsBody = SCNPhysicsBody.CreateStaticBody(); var options = new SCNPhysicsShapeOptions(); Node.PhysicsBody.PhysicsShape = SCNPhysicsShape.Create(geom, options); Node.PhysicsBody.CategoryBitMask = 1u; Node.PhysicsBody.CollisionBitMask = 1u; Node.PhysicsBody.ContactTestBitMask = 1u; } }

class Brick { public readonly SCNNode Node; public Brick(float x, float y) { var geom = SCNBox.Create(5f, 5, 10,0); geom.FirstMaterial.Diffuse.ContentColor = UIColor.FromRGB(135, 206, 250); geom.FirstMaterial.Specular.ContentColor = UIColor.Yellow; geom.FirstMaterial.Specular.Intensity = 1; Node = SCNNode.FromGeometry(geom); Node.Position = new SCNVector3(x,y,0); Node.PhysicsBody = SCNPhysicsBody.CreateStaticBody(); var options = new SCNPhysicsShapeOptions(); Node.PhysicsBody.PhysicsShape = SCNPhysicsShape.Create(geom, options); Node.PhysicsBody.CategoryBitMask = 1u; Node.PhysicsBody.CollisionBitMask = 1u; Node.PhysicsBody.ContactTestBitMask = 1u; } }

class Wall { public readonly SCNNode Node; public Wall(float w, float h, float x, float y) { var geom = SCNBox.Create(w, h, 1, 0); geom.FirstMaterial.Diffuse.ContentColor = UIColor.DarkGray; geom.FirstMaterial.Specular.ContentColor = UIColor.Yellow; geom.FirstMaterial.Specular.Intensity = 0f; Node = SCNNode.FromGeometry(geom); var ln = SCNNode.Create(); ln.Light = SCNLight.Create(); ln.Position = new SCNVector3(0,0,GameDefaults.size*4); Node.Add(ln); Node.Position = new SCNVector3(x,y,0); Node.PhysicsBody = SCNPhysicsBody.CreateStaticBody(); var options = new SCNPhysicsShapeOptions(); Node.PhysicsBody.PhysicsShape = SCNPhysicsShape.Create(geom, options); Node.PhysicsBody.CategoryBitMask = 1u; Node.PhysicsBody.CollisionBitMask = 1u; Node.PhysicsBody.ContactTestBitMask = 1u;

}

}

class Camera { public readonly SCNNode Node = SCNNode.Create(); readonly SCNCamera camera = SCNCamera.Create(); public Camera() { Node.Camera = camera; Node.Position = new SCNVector3 (0,0,150); camera.ZNear = 1; camera.ZFar = 150; // Attach a light to the camera var ln = SCNNode.Create(); ln.Light = SCNLight.Create(); ln.Position = new SCNVector3(0,0,50); Node.Add(ln); } }

var scoreLabel = new UILabel() { Text = "0",

TextAlignment = UITextAlignment.Center,
Font = UIFont.SystemFontOfSize(25),
TextColor = UIColor.White.ColorWithAlpha(0.25f),
AutoresizingMask = UIViewAutoresizing.FlexibleDimensions,
AdjustsFontSizeToFitWidth = true,

};

void ResetPauseBall() { ball.Node.Position = new SCNVector3(0, 10, 0); ball.Node.PhysicsBody.Velocity = new SCNVector3(0, 0, 0); ball.Node.PhysicsBody.ResetTransform();

}

void ResetBallPosition() { if(ball.Node.Hidden == true) { ball.Node.Hidden = false; } if(lives<=0) data-preserve-html-node="true" { ball.Node.Hidden = true; } if(lives>0) { var rand = new Random(); ball.Node.Position = new SCNVector3(0, 10, 0); ball.Node.PhysicsBody.Velocity = new SCNVector3(rand.Next(-30,30), speed, 0); ball.Node.PhysicsBody.ResetTransform(); } }

void ChangeBrickColor() { //brick_1.Node.Geometry.FirstMaterial.Diffuse.ContentColor = UIColor.Yellow;

}

void DecreaseScore() { lives--;

if(lives<=0)
{
    scoreLabel.BeginInvokeOnMainThread(() => {
scoreLabel.Text = $"Game Over";
});
}
if(lives>0)
{

scoreLabel.BeginInvokeOnMainThread(() => {
scoreLabel.Text =$"Level " + brickCount/8 + "   " + lives+$"UP";
});
}

}

void StartGame() { //PlaceBricks();

PlaceBricksLoop(brickCount);
lives=3;
scoreLabel.BeginInvokeOnMainThread(() => {
scoreLabel.Text =$"Level " + brickCount/8 + "   " + lives+$"UP";
});

scene.Background.ContentColor = GameDefaults.blackColor;

}

void CheckForRestart() { if(lives<=0) data-preserve-html-node="true" { score = 0; brickCount = 8; ResetBricks();

StartGame();
}

}

void PlaceBricksLoop(int brickCounter) { int xPos = -20; int yPos = 70;

for (int i = 0; i < brickCount; i++)
   {
    bricks[i] = new Brick(xPos +(int)2.5,yPos);
    root.Add(bricks[i].Node);
    xPos +=5;
       if(xPos > 0 && xPos % 20 == 0)
       {
           xPos = -20;
           yPos -= 5;
       }
    }

}

void ResetBricks() { foreach(Brick element in bricks) { if(element.Node.Hidden == false) { element.Node.Hidden = true; } } }

void CheckForBricks() { score++; if(score>=brickCount) { brickCount +=8; score = 0; bricks = new Brick[brickCount]; //ResetBricks(); PlaceBricksLoop(brickCount); ResetBallPosition(); scoreLabel.BeginInvokeOnMainThread(() => { scoreLabel.Text =$"Level " + brickCount/8 + " " + lives+$"UP"; }); } }

void BackroundFlash() { if(scene.Background.ContentColor == UIColor.Black) { scene.Background.ContentColor = GameDefaults.redColor; } else { scene.Background.ContentColor = GameDefaults.blackColor; }

}

var cam = new Camera(); var paddle = new Paddle(10f,2f,5); var ceiling = new Wall(100, 3, 0, 80); var floor = new Wall(100, 3, 0, -20); var leftWall = new Wall(3,100,-30,30); var rightWall = new Wall(3,100,30,30); var ball = new Ball(); var bricks = new Brick[brickCount];

var scene = SCNScene.Create(); //scene.PhysicsWorld.Gravity = SCNVector3.One; scene.PhysicsWorld.Gravity = SCNVector3.Zero;

var root = scene.RootNode;

var sceneView = new SCNView(new CGRect(0,0,320,320)); sceneView.BackgroundColor = UIColor.Black; sceneView.Scene = scene;

scoreLabel.Frame = sceneView.Bounds; sceneView.AddSubview(scoreLabel);

scene.PhysicsWorld.DidBeginContact += (s,e) => {

var otherNode = e.Contact.NodeA == ball.Node ? e.Contact.NodeB :
    (e.Contact.NodeB == ball.Node ? e.Contact.NodeA : null);
if (otherNode == floor.Node) {
    Console.WriteLine("HIT FLOOR");
    //BackroundFlash();
    DecreaseScore();
    ResetBallPosition();


}
if (otherNode == paddle.Node) {
    Console.WriteLine("HIT PADDLE");

}
if (otherNode == ceiling.Node) {
    Console.WriteLine("HIT CEILING");

}
foreach(Brick element in bricks)
{
    if (otherNode == element.Node) {
    Console.WriteLine("HIT element");
    element.Node.Hidden = true;
    //element.Node.RemoveFromParentNode();
    CheckForBricks();

}
}

// e.Contact.NodeA.Geometry.FirstMaterial.Diffuse.ContentColor=UIColor.Red; };

var panGesture = new UIPanGestureRecognizer (g => { for (var i = 0; i < g.NumberOfTouches; i++) { var viewLoc = g.LocationOfTouch(i, sceneView); var pos = sceneView.UnprojectPoint(new SCNVector3((float)viewLoc.X, (float)viewLoc.Y, 1.0f));

paddle.Node.Position = new SCNVector3(pos.X/8, 5, 0.0f);
        paddle.Node.PhysicsBody.ResetTransform();


}

});

var tapGesture = new UITapGestureRecognizer (g => { CheckForRestart(); ResetBallPosition(); }); tapGesture.NumberOfTapsRequired = 2;

root.Add(paddle.Node); root.Add(floor.Node); root.Add(ceiling.Node); root.Add(leftWall.Node); root.Add(rightWall.Node); root.Add(ball.Node);

//ball.Node.PhysicsBody.ApplyForce(new SCNVector3(10,50,0), true); sceneView.AddGestureRecognizer(panGesture); sceneView.AddGestureRecognizer(tapGesture);

//ChangeBrickColor();

StartGame();

var Main = sceneView;

Mobile GameTyler Jones