Skip to content

Instantly share code, notes, and snippets.

@sketchytech
Created November 19, 2014 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sketchytech/b707c17707085a767923 to your computer and use it in GitHub Desktop.
Save sketchytech/b707c17707085a767923 to your computer and use it in GitHub Desktop.
Swift: 3D drawing, digging a hole (with and without water)
import UIKit
import QuartzCore
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// select cube rotation
let adjustment:CGFloat = 90
let radius:CGFloat = 50
let cubePoint = CGPoint(x: 100, y: 250)
// draw cube
let cube = drawCube(cubePoint.x, cubePoint.y, radius, adjustment, UIColor(hue: 60/360, saturation: 80/100, brightness: 100/100, alpha: 1.0))
for c in cube {
self.view.layer.addSublayer(c)
}
// draw pyramid
let pyramid = drawPyramid(cubePoint.x, cubePoint.y-radius, radius, adjustment, UIColor(hue: 197/360, saturation: 65/100, brightness: 100/100, alpha: 1.0))
for p in pyramid {
self.view.layer.addSublayer(p)
}
// tiles
var tilePos = positionNextCube(x: cubePoint.x, y: cubePoint.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightBehind)
for a in 1...2 {
let tile = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 86/100, alpha: 1.0))
tile.zPosition = -1
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightBehind)
self.view.layer.addSublayer(tile)
}
// second cube
let secondCubePosition = positionNextCube(x: cubePoint.x, y: cubePoint.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 3, position:.RightBehind)
let secondCube = drawCube(secondCubePosition.x, secondCubePosition.y, radius, adjustment, UIColor(hue: 60/360, saturation: 80/100, brightness: 100/100, alpha: 1.0))
for c in secondCube {
self.view.layer.addSublayer(c)
}
// second pyramid
let secondPyramid = drawPyramid(secondCubePosition.x, secondCubePosition.y-radius, radius, adjustment, UIColor(hue: 197/360, saturation: 65/100, brightness: 100/100, alpha: 1.0))
for p in secondPyramid {
self.view.layer.addSublayer(p)
}
// second tiles
tilePos = positionNextCube(x: secondCubePosition.x, y: secondCubePosition.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightFront)
for a in 1...2 {
let tile = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 86/100, alpha: 1.0))
tile.zPosition = -1
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightFront)
self.view.layer.addSublayer(tile)
}
// third cube
let thirdCubePosition = positionNextCube(x: secondCubePosition.x, y: secondCubePosition.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 3, position:.RightFront)
let thirdCube = drawCube(thirdCubePosition.x, thirdCubePosition.y, radius, adjustment, UIColor(hue: 60/360, saturation: 80/100, brightness: 100/100, alpha: 1.0))
for c in thirdCube {
self.view.layer.addSublayer(c)
}
// third pyramid
let thirdPyramid = drawPyramid(thirdCubePosition.x, thirdCubePosition.y-radius, radius, adjustment, UIColor(hue: 197/360, saturation: 65/100, brightness: 100/100, alpha: 1.0))
for p in thirdPyramid {
self.view.layer.addSublayer(p)
}
// third tiles
tilePos = positionNextCube(x: thirdCubePosition.x, y: thirdCubePosition.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.LeftFront)
for a in 1...3 {
let tile = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 86/100, alpha: 1.0))
tile.zPosition = -1
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.LeftFront)
self.view.layer.addSublayer(tile)
}
// fourth cube
let fourthCubePosition = positionNextCube(x: thirdCubePosition.x, y: thirdCubePosition.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 3, position:.LeftFront)
let fourthCube = drawCube(fourthCubePosition.x, fourthCubePosition.y, radius, adjustment, UIColor(hue: 60/360, saturation: 80/100, brightness: 100/100, alpha: 1.0))
for c in fourthCube {
// self.view.layer.addSublayer(c)
}
// fourth pyramid
let fourthPyramid = drawPyramid(fourthCubePosition.x, fourthCubePosition.y-radius, radius, adjustment, UIColor(hue: 197/360, saturation: 65/100, brightness: 100/100, alpha: 1.0))
for p in fourthPyramid {
// self.view.layer.addSublayer(p)
}
// fourth tiles
tilePos = positionNextCube(x: fourthCubePosition.x, y: fourthCubePosition.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.LeftBehind)
for a in 1...2 {
let tile = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 86/100, alpha: 1.0))
tile.zPosition = -1
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.LeftBehind)
self.view.layer.addSublayer(tile)
}
// light hole tiles
tilePos = positionNextCube(x: cubePoint.x, y: cubePoint.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightFront)
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightBehind)
let tile = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 65/100, alpha: 1.0))
tile.zPosition = -1
self.view.layer.addSublayer(tile)
// corner hole tiles
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightBehind)
var tileCorner = cornerHoleTile(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: 65/100, alpha: 1.0))
tileCorner.zPosition = -1
self.view.layer.addSublayer(tileCorner)
// dark hole tile
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.RightFront)
let tileDark = drawCubeBase(tilePos.x, tilePos.y, radius, adjustment, UIColor(hue: 117/360, saturation: 29/100, brightness: (65/100)*0.8, alpha: 1.0))
tileDark.zPosition = -1
self.view.layer.addSublayer(tileDark)
// corner hole tiles
tilePos = positionNextCube(x: tilePos.x, y: tilePos.y, radius: radius, sides: 6, adjustment:adjustment, spaces: 1, position:.LeftFront)
let holeColor = UIColor(hue: 117/360, saturation: 29/100, brightness: 65/100, alpha: 1.0)
let waterColor = UIColor(hue: 192/360, saturation: 67/100, brightness: 79/100, alpha: 1.0)
tileCorner = cornerHoleTile(tilePos.x, tilePos.y, radius, adjustment, holeColor)
tileCorner.zPosition = -1
self.view.layer.addSublayer(tileCorner)
}
}
func degree2radian(a:CGFloat)->CGFloat {
let b = CGFloat(M_PI) * a/180
return b
}
func polygonPointArray(sides:Int,x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat=0)->[CGPoint] {
let angle = degree2radian(360/CGFloat(sides))
let cx = x // x origin
let cy = y // y origin
let r = radius // radius of circle
var i = sides
var points = [CGPoint]()
while points.count <= sides {
let xpo = cx - r * cos(angle * CGFloat(i)+degree2radian(adjustment))
let ypo = cy - r * sin(angle * CGFloat(i)+degree2radian(adjustment))
points.append(CGPoint(x: xpo, y: ypo))
i--;
}
return points
}
func drawCube (x:CGFloat,y:CGFloat,radius:CGFloat, adjustment:CGFloat, color:UIColor)->[CAShapeLayer] {
// --- Color is shaded with light coming from above and to the right --- //
var h:CGFloat = 0
var s:CGFloat = 0
var b:CGFloat = 0
color.getHue(&h, saturation: &s, brightness: &b, alpha: nil)
// --- Left side of cube (visible) --- //
let leftSide = CAShapeLayer()
let leftSidePath = cubeLeft(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
leftSide.path = leftSidePath
leftSide.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.7, alpha: 1.0).CGColor
// --- Front side of cube (visible) --- //
let frontSide = CAShapeLayer()
let frontSidePath = cubeFront(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
frontSide.path = frontSidePath
frontSide.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.85, alpha: 1.0).CGColor
let topSide = CAShapeLayer()
let topSidePath = cubeTop(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
topSide.path = topSidePath
topSide.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.95, alpha: 1.0).CGColor
return [leftSide,frontSide,topSide]
}
func cubeTop(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[0]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[1].x, points[1].y)
CGPathAddLineToPoint(path, nil, x, y)
CGPathAddLineToPoint(path, nil, points[5].x, points[5].y)
CGPathCloseSubpath(path)
return path
}
func cubeFront(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[5]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[4].x, points[4].y)
CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathAddLineToPoint(path, nil, x, y)
CGPathCloseSubpath(path)
return path
}
func cubeLeft(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[5]
CGPathMoveToPoint(path, nil, x, y)
CGPathAddLineToPoint(path, nil, points[1].x, points[1].y)
CGPathAddLineToPoint(path, nil, points[2].x, points[2].y)
CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathCloseSubpath(path)
return path
}
func cubeBase(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[2]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathAddLineToPoint(path, nil, points[4].x, points[4].y)
CGPathAddLineToPoint(path, nil, x, y)
CGPathCloseSubpath(path)
return path
}
func cornerHoleTileLeft(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[2]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathAddLineToPoint(path, nil, x, y)
CGPathCloseSubpath(path)
return path
}
func cornerHoleTileRight(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[3]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[4].x, points[4].y)
CGPathAddLineToPoint(path, nil, x, y)
CGPathCloseSubpath(path)
return path
}
func drawCubeBase (x:CGFloat,y:CGFloat,radius:CGFloat, adjustment:CGFloat, color:UIColor)->CAShapeLayer {
// --- Left side of cube (visible) --- //
let cubeBaseObject = CAShapeLayer()
let cubeBasePath = cubeBase(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
cubeBaseObject.path = cubeBasePath
cubeBaseObject.fillColor = color.CGColor
return cubeBaseObject
}
func cornerHoleTile (x:CGFloat,y:CGFloat,radius:CGFloat, adjustment:CGFloat, color:UIColor)->CAShapeLayer {
// --- Color is shaded with light coming from above and to the right --- //
var h:CGFloat = 0
var s:CGFloat = 0
var b:CGFloat = 0
color.getHue(&h, saturation: &s, brightness: &b, alpha: nil)
let corner = CAShapeLayer()
let left = CAShapeLayer()
let leftPath = cornerHoleTileLeft(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
left.path = leftPath
left.fillColor = color.CGColor
let right = CAShapeLayer()
let rightPath = cornerHoleTileRight(x: x, y: y, radius: radius, sides: 6, adjustment:adjustment)
right.path = rightPath
right.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.8, alpha: 1.0).CGColor
corner.addSublayer(left)
corner.addSublayer(right)
return corner
}
func pyramidFront(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> CGPathRef {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[4]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[5].x/2+points[1].x/2, points[5].y/2+points[1].y/2)
CGPathAddLineToPoint(path, nil, points[3].x, points[3].y)
CGPathCloseSubpath(path)
return path
}
func pyramidLeft(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat) -> (path:CGPathRef,point:CGPoint) {
let path = CGPathCreateMutable()
let points = polygonPointArray(sides,x,y,radius,adjustment: adjustment)
var cpg = points[3]
CGPathMoveToPoint(path, nil, cpg.x, cpg.y)
CGPathAddLineToPoint(path, nil, points[5].x/2+points[1].x/2, points[5].y/2+points[1].y/2)
CGPathAddLineToPoint(path, nil, points[2].x, points[2].y)
CGPathCloseSubpath(path)
let topOfPyramid = CGPoint(x:points[5].x/2+points[1].x/2, y:points[5].y/2+points[1].y/2)
return (path,topOfPyramid)
}
func drawPyramid(x:CGFloat,y:CGFloat,radius:CGFloat,adjustment:CGFloat, color:UIColor)->[CAShapeLayer] {
// --- Color is shaded with light coming from above and to the right --- //
var h:CGFloat = 0
var s:CGFloat = 0
var b:CGFloat = 0
color.getHue(&h, saturation: &s, brightness: &b, alpha: nil)
let pyramidFrontLayer = CAShapeLayer()
let pyramidFrontPath = pyramidFront(x: x, y: y, radius: radius, sides: 6, adjustment: adjustment)
pyramidFrontLayer.path = pyramidFrontPath
pyramidFrontLayer.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.85, alpha: 1.0).CGColor
let pyramidLeftLayer = CAShapeLayer()
let pyramidLeftPath = pyramidLeft(x: x, y: y, radius: radius, sides: 6, adjustment: adjustment)
pyramidLeftLayer.path = pyramidLeftPath.path
pyramidLeftLayer.fillColor = UIColor(hue: h, saturation: s, brightness: b*0.7, alpha: 1.0).CGColor
return [pyramidFrontLayer,pyramidLeftLayer]
}
func positionNextCube(#x:CGFloat, #y:CGFloat, #radius:CGFloat, #sides:Int, #adjustment:CGFloat, #spaces:Int, #position:CubeRelativePosition) -> CGPoint {
// to get the origin of a hexagon so many spaces away, we simply multiply the radius by the number of spaces since each origin is space exactly the length of the radius
var points = polygonPointArray(sides,x,y,radius*CGFloat(spaces),adjustment: adjustment)
return points[position.rawValue]
}
enum CubeRelativePosition:Int {
case Above = 0, LeftBehind, LeftFront, Underneath, RightFront, RightBehind
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment