-
Notifications
You must be signed in to change notification settings - Fork 29
/
JigsawPuzzle.swift
277 lines (246 loc) · 9.17 KB
/
JigsawPuzzle.swift
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
274
275
276
277
//
// JigsawPuzzle.swift
// puzzleGame
//
// Created by Arturs Derkintis on 8/16/15.
// Copyright © 2015 Starfly. All rights reserved.
//
import SpriteKit
class JigsawPuzzle: SKScene {
var border : SKSpriteNode?
var points = [CGPoint]()
var pieces = [Piece]()
var piecesCount : Int?
var width : CGFloat = 0
var imageTiles = ([UIImage](), [CGPoint]())
var guidePhoto : SKSpriteNode?
var movingPiece : Piece?
var maxZPosition : CGFloat = Layer.Tiles
override func didMoveToView(view: SKView) {
super.didMoveToView(view)
backgroundColor = UIColor.lightGrayColor()
setBorder()
startNewPuzzleGameLevel()
}
func startNewPuzzleGameLevel(){
border?.removeAllChildren()
let tilesInLine = 9
piecesCount = tilesInLine * tilesInLine
let image = UIImage(named: "car")!
imageTiles = image.jigSawCuter(CGSize(width: 760, height: 698), piecesCount: piecesCount!)
for i in 0...80{
setPiece(CGSize(width: width, height: width), index : i)
}
guidePhoto = SKSpriteNode(imageNamed: "car")
guidePhoto?.size = CGSize(width: 760, height: 698)
guidePhoto?.zPosition = Layer.GuidePhoto
guidePhoto?.anchorPoint = CGPoint(x: 0, y: 0)
guidePhoto?.position = CGPoint(x: 0, y: 0)
guidePhoto?.alpha = 0.01
border!.addChild(guidePhoto!)
for piece in pieces{
setNeighboursInSafeDistance(piece)
}
delay(3) { () -> () in
self.smashAndCrashDown()
}
}
func smashAndCrashDown(){
let fallRect1 = CGRectMake(50, 50, frame.width - 100, 5) //down rect (unused)
let fallRect2 = CGRectMake(50, frame.height - 130, frame.width - 100, 5) //up rect (unused)
let fallRect3 = CGRectMake(55, 50, 5, frame.height - 110) //left rect
let fallRect4 = CGRectMake(frame.width - 65, 50, 5, frame.height - 110) //right rect
let rects = [fallRect3, fallRect4]
for piece in pieces{
let rect = rects[randomInRange(0, upper: rects.count - 1)]
let point = CGPoint.randomPointInRect(rect)
let position = convertPoint(point, toNode: border!)
let action = SKAction.moveTo(position, duration: 1.5)
piece.runAction(action)
piece.rotateRandomly()
}
let fadein = SKAction.fadeAlphaTo(0.3, duration: 1.5)
guidePhoto?.runAction(fadein)
}
func setPiece(size : CGSize, index : Int){
let piece = Piece()
piece.anchorPoint = CGPoint(x: 0.5, y: 0.5)
piece.size = size
piece.color = UIColor.blueColor()
piece.name = pieceName
pieces.append(piece)
piece.tag = index
let texture = SKTexture(image: imageTiles.0[index])
let point = imageTiles.1[index]
piece.zPosition = CGFloat(index + 10)
maxZPosition = CGFloat(index + 10)
piece.texture = texture
piece.size = texture.size()
let conP = convertUIPointToSprite(point, node: border!)
piece.position = conP
points.append(conP)
piece.correctPosition = conP
border?.addChild(piece)
}
func setBorder(){
let sprite = SKSpriteNode()
sprite.color = .clearColor()
sprite.size = CGSize(width: 760, height: 698)
sprite.position = CGPoint(x: (frame.width - 760) * 0.5, y: 30)
sprite.anchorPoint = CGPoint(x: 0, y: 0)
addChild(sprite)
border = sprite
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let loc = touch.locationInNode(border!)
let nodes = border!.nodesAtPoint(loc)
var piecess = [Piece]()
for node in nodes where node.name == pieceName{
if node.isKindOfClass(Piece) {
piecess.append((node as? Piece)!)
}
}
var minElem = CGFloat.min
var index : Int = 0
for piece in piecess{
if piece.zPosition > minElem{
minElem += piece.zPosition
index = piecess.indexOf(piece)!
}
}
if piecess.count > 0{
maxZPosition += 1
movingPiece = piecess[index] as Piece
movingPiece?.zPosition = maxZPosition
movingPiece?.touchStart()
}
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches{
let loc = touch.locationInNode(border!)
movingPiece?.touchMoves(loc)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
movingPiece?.touchEnd()
if let node = movingPiece{
radar(node)}
}
func radar(piece : Piece){
let position = piece.position
var distances = [CGFloat]()
for point in points{
let distance = distanceBetweenPoints(point, point2: position)
distances.append(distance)
}
var min = CGFloat.max
var index = 0
for distance in distances{
if distance < min{
min = distance
index = distances.indexOf(distance)!
}
}
let point = points[index]
if piece.correctPosition == point{
let action = SKAction.moveTo(point, duration: 0.2)
piece.runAction(action)
}
}
func setNeighboursInSafeDistance(piece : Piece){
///This method has no impact to anything, its there bcs I can!
let widthe = piece.size.width * 0.9
let centerNodePosition = piece.position
let upPoint = CGPoint(x: centerNodePosition.x, y: centerNodePosition.y + widthe)
let rightPoint = CGPoint(x: centerNodePosition.x + widthe, y: centerNodePosition.y)
let leftPoint = CGPoint(x: centerNodePosition.x - widthe, y: centerNodePosition.y)
let downPoint = CGPoint(x: centerNodePosition.x, y: centerNodePosition.y - widthe)
let upNodes = border?.nodesAtPoint(upPoint)
let rightNodes = border?.nodesAtPoint(rightPoint)
let leftNodes = border?.nodesAtPoint(leftPoint)
let downNodes = border?.nodesAtPoint(downPoint)
if let up = upNodes{
for pie in up where pie.name == pieceName{
piece.con!.top = (pie as! Piece).tag!
}
}
if let right = rightNodes{
for pie in right where pie.name == pieceName{
piece.con!.right = (pie as! Piece).tag!
}
}
if let left = leftNodes{
for pie in left where pie.name == pieceName{
piece.con!.left = (pie as! Piece).tag!
}
}
if let down = downNodes{
for pie in down where pie.name == pieceName{
let tag = (pie as! Piece).tag!
piece.con!.bottom = tag
}
}
}
}
class Piece: SKSpriteNode {
var correctPosition : CGPoint?
var con : ConectionTags?
var sprite : SKSpriteNode?
var tapTimeInterval : Int = 0
var taps = 0
let rotationTimeLimit = 3
var counterTimer : NSTimer?
var rotation = PieceRotation.zero
var tag : Int?
var hasMoved = false
override init(texture: SKTexture?, color: UIColor, size: CGSize) {
super.init(texture: texture, color: color, size: size)
userInteractionEnabled = false
con = ConectionTags()
}
func rotateRandomly(){
let array = [0, 90, 180, 270]
let index = randomInRange(0, upper: array.count - 1)
rotation = PieceRotation(rawValue: index)!
let randomRot = array[index].degreesToRadians
let action = SKAction.rotateByAngle(randomRot, duration: 1.5)
runAction(action)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
}
func touchStart(){
counterTimer = NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: "addMiliSec", userInfo: nil, repeats: true)
}
func touchMoves(point : CGPoint){
hasMoved = true
let action = SKAction.moveTo(point, duration: 0.001)
runAction(action)
}
func touchEnd(){
counterTimer?.invalidate()
counterTimer = nil
if hasMoved == false{
if tapTimeInterval <= 3{
let action = SKAction.rotateByAngle(90.degreesToRadians, duration: 0.2)
runAction(action)
tapTimeInterval = 0
if taps < 3{
taps += 1
rotation = PieceRotation(rawValue: taps)!
}else{
rotation = .zero
taps = 0
}
}}
tapTimeInterval = 0
hasMoved = false
}
func addMiliSec(){
tapTimeInterval += 1
}
}