Switching sprite positions with each other - ios

I have 6 sprites that I want to switch positions with each other every time a function is called. I also don't want any two (or more) sprites to ever be in the same position. I tried using this function but it didn't do anything.
func newPositionPipe() {
let pipePosition1 = CGPoint(x: 63, y: 1275)
let pipePosition2 = CGPoint(x: 188, y: 1275)
let pipePosition3 = CGPoint(x: 315, y: 1275)
let pipePosition4 = CGPoint(x: 443, y: 1275)
let pipePosition5 = CGPoint(x: 565, y: 1275)
let pipePosition6 = CGPoint(x: 687, y: 1275)
var randomNumberBetween0And6 = Int(arc4random_uniform(6))
let pipePositions = [pipePosition1, pipePosition2, pipePosition3, pipePosition4, pipePosition5, pipePosition6]
greenPipe.position = pipePositions[randomNumberBetween0And6]
redPipe.position = pipePositions[randomNumberBetween0And6]
greenPipe.position = pipePositions[randomNumberBetween0And6]
yellowPipe.position = pipePositions[randomNumberBetween0And6]
greyPipe.position = pipePositions[randomNumberBetween0And6]
purplePipe.position = pipePositions[randomNumberBetween0And6]
}

The way you have it setup now will make every pipe position the same because it will be referencing the same random index number you've generated with randomNumberBetween0And6. Put this in a loop and generate a new random number each time. You could also use a Tuple to swap the values.
(greenPipe.position, redPipe.position) = (redPipe.position, greenPipe.position)

Related

Slice an SKShapeNode into two

Is there an easy method to slice an SKShapeNode into 2 seperate SKShapeNodes?
In this example I have created an SKShapeNode using a closed bezier path as well as a single line.
let squareShape = SKShapeNode()
squareShape.path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: 256, height: 256), cornerRadius: 10).cgPath
squareShape.position = CGPoint(x: frame.midX-128, y: frame.midY+200-128)
squareShape.fillColor = UIColor.green
squareShape.strokeColor = UIColor.blue
squareShape.lineWidth = 2
addChild(squareShape)
let lineShape1 = SKShapeNode()
let line1 = UIBezierPath()
line1.move(to: CGPoint(x: -200, y: 300))
line1.addLine(to: CGPoint(x: 200, y: 100))
lineShape1.path = line1.cgPath
lineShape1.strokeColor = UIColor.white
lineShape1.lineWidth = 2
addChild(lineShape1)
How can I transform the existing SKShapeNode into 2 seperate SKShapeNodes separated by the line?
I need to be able to do this with varying line positions and shapes types (or even with multiple shapes and a single line).
Thanks

Use PhysicsBody with SKShapenode line. Swift, iOS, SpriteKit

I need to add simple line using ShapeBody to interact with.
I'am trying code below, by Xcode gives me next response:
PhysicsBody: Could not create physics body.
let testPath = UIBezierPath()
testPath.move(to: CGPoint(x:-100, y: 200))
testPath.addLine(to: CGPoint(x:100, y: 200))
let testShape = SKShapeNode()
testShape.path = testPath.cgPath
testShape.position = CGPoint(x:0, y:250)
testShape.zPosition = 5
testShape.lineWidth = 5
testShape.strokeColor = .red
testShape.physicsBody = SKPhysicsBody(polygonFrom: testPath.cgPath)
Used edgeChainFrom instead of polygonFrom, and it works!
testShape.physicsBody = SKPhysicsBody(edgeChainFrom: testPath.cgPath)
A path cannot intersect any of its lines with a SKPhysicsBody, your line needs to be a thin rectangle
let testPath = UIBezierPath()
testPath.move(to: CGPoint(x:-100, y: 200))
testPath.addLine(to: CGPoint(x:100, y: 200))
testPath.addLine(to: CGPoint(x:100, y: 201))
testPath.addLine(to: CGPoint(x:-100, y: 201))
testPath.close()
let testShape = SKShapeNode()
testShape.path = testPath.cgPath
testShape.position = CGPoint(x:0, y:250)
testShape.zPosition = 5
testShape.lineWidth = 5
testShape.strokeColor = .red
testShape.physicsBody = SKPhysicsBody(polygonFrom: testPath.cgPath)

Weird Spritekit Collision Bug depending on SKSpriteNode position

I'm having a weird Spritekit issue where my moving SKSpriteNode is passing through a fixed SKSpriteNode depending on the position of the fixed SKSpriteNode.
UPDATE: Code works in simulator but not on real device.
Example:
Placing my bin SKSpriteNode at position x: -500, y: 100 works fine and my moving SKSpriteNode collides as expected.
Placing my bin SKSpriteNode at position x: -600, y: 100 DOES NOT work and my moving SKSpriteNode DOES NOT collide with the bin.
Using view.showsPhysics = true shows that there is physics bodies in both cases.
x values between -500 and -508 work as expected. All other values I have tried did not work.
Collisions with my other fixed SKSpriteNodes work as expected.
enum CollisionTypes: UInt32 {
case Plane = 1
case FloorAndRoof = 2
case OtherObject = 4
case FinishPoint = 8
}
Code to create levels
func createLevel(level: Int) {
switch level {
case 1:
createFloor()
createRoof()
createTable(position: CGPoint(x: 750, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -500, y: 100)) // THIS IS THE PROBLEM LOCATION
createFinishPoint(position: CGPoint(x: -500, y: 100))
break
case 2:
createFloor()
createRoof()
createTable(position: CGPoint(x: 250, y: 150))
createCeilingFan(position: CGPoint(x: 750, y: 560))
createCeilingFan(position: CGPoint(x: 2000, y: 560))
createWaterDispenser(position: CGPoint(x: 1500, y: 212))
createBin(position: CGPoint(x: -600, y: 100))
createFinishPoint(position: CGPoint(x: -300, y: 200))
break
default:
break
}
}
Moving SKSpriteNode
func createPlane() {
plane = SKSpriteNode(imageNamed: "plane1")
plane.name = "plane1"
//plane.position = CGPoint(x: -UIScreen.main.bounds.width + plane.size.width , y: 0)
plane.position = CGPoint(x: 0, y: 300)
plane.zPosition = 1
//plane.physicsBody = SKPhysicsBody(texture: plane.texture!, size: plane.texture!.size())
plane.physicsBody = SKPhysicsBody(texture: planeTexture, size: planeTexture.size())
plane.physicsBody?.allowsRotation = true
plane.physicsBody?.categoryBitMask = CollisionTypes.Plane.rawValue
plane.physicsBody?.collisionBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue // dont collide with finish point
plane.physicsBody?.contactTestBitMask = CollisionTypes.FloorAndRoof.rawValue | CollisionTypes.OtherObject.rawValue | CollisionTypes.FinishPoint.rawValue
plane.physicsBody?.usesPreciseCollisionDetection = true
plane.physicsBody?.isDynamic = true
plane.physicsBody?.friction = 1
plane.physicsBody?.restitution = 0
plane.physicsBody?.mass = 0.1 // customise for different planes
plane.physicsBody?.angularDamping = 1
plane.physicsBody?.linearDamping = 0.2 // customise for different planes
liftFactor = 0.1 // customise for different planes
addChild(plane)
flightMode = 4 // dead, should drop to floor and change to mode 0 when at rest
//print(flightMode)
}
Bin SKSpriteNode that moving Plane should collide with.
func createBin(position: CGPoint) {
binFront = SKSpriteNode(imageNamed: "binFront")
binFront.name = "binFront"
binFront.setScale(0.15)
binFront.position = position
binFront.zPosition = 2 // in front of plane
addChild(binFront)
binBack = SKSpriteNode(imageNamed: "binBack")
binBack.name = "binBack"
binBack.setScale(0.15)
binBack.position = position
binBack.zPosition = 0 // behind plane
addChild(binBack)
binPhysicsBody = SKSpriteNode(imageNamed: "binPhysicsBody")
binPhysicsBody.name = "binPhysicsBody"
binPhysicsBody.physicsBody = SKPhysicsBody(texture: binPhysicsBody.texture!, size: binPhysicsBody.texture!.size())
binPhysicsBody.setScale(0.15)
binPhysicsBody.physicsBody?.allowsRotation = false
binPhysicsBody.physicsBody?.categoryBitMask = CollisionTypes.OtherObject.rawValue
binPhysicsBody.physicsBody?.collisionBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.contactTestBitMask = CollisionTypes.Plane.rawValue
binPhysicsBody.physicsBody?.usesPreciseCollisionDetection = false
binPhysicsBody.physicsBody?.isDynamic = false
binPhysicsBody.physicsBody?.friction = 1
binPhysicsBody.physicsBody?.restitution = 0
binPhysicsBody.physicsBody?.mass = 50
binPhysicsBody.position = position
binPhysicsBody.zPosition = 0
addChild(binPhysicsBody)
}
I still don't know the cause of my issue but I got around it by changing the image used to create my physics body. I used a slightly thicker 'wall thickness' on the bin.

Create slanted cut on image view swift

I have been looking around the internet and I can't find a good solution for making a slanted cut on an image view that works for swift.
Here is what I want
As you can see I would like to slant an image view as seen in the background. If anyone had some thoughts or solutions, that would be much appreciated.
Properties:
fileprivate var headerView: PostHeaderView!
fileprivate var headerMaskLayer: CAShapeLayer!
In viewDidLoad():
headerMaskLayer = CAShapeLayer()
headerMaskLayer.fillColor = UIColor.black.cgColor
headerView.layer.mask = headerMaskLayer
updateHeaderView()
Then use this function:
func updateHeaderView() {
let effectiveHeight = Storyboard.tableHeaderHeight - Storyboard.tableHeaderCutAway / 2
var headerRect = CGRect(x: 0, y: -effectiveHeight, width: tableView.bounds.width, height: Storyboard.tableHeaderHeight)
headerView.logoImageView.alpha = 0
if tableView.contentOffset.y < -effectiveHeight {
headerRect.origin.y = tableView.contentOffset.y
headerRect.size.height = -tableView.contentOffset.y + Storyboard.tableHeaderCutAway/2
let final: CGFloat = -100
let alpha = min((tableView.contentOffset.y + effectiveHeight) / final, 1)
headerView.logoImageView.alpha = alpha
}
headerView.frame = headerRect
// cut away
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: headerRect.width, y: 0))
path.addLine(to: CGPoint(x: headerRect.width, y: headerRect.height))
path.addLine(to: CGPoint(x: 0, y: headerRect.height - Storyboard.tableHeaderCutAway))
headerMaskLayer?.path = path.cgPath
}

Create parallax clouds with random Y coordinate using SKSpriteNode and SKAction in Swift

I'm trying to create a parallax cloud effect with different speeds and sizes but i'm having a hard time when trying to add a different Y coordinate, not always in the same Y for all the clouds.
So I have 5 clouds, with its respective X and Y coordinate, and I use the SKAction.moveByX() function.
All the clouds starts from for example FRAME_WIDTH + 200 (out of bounds) and they end at -100. After that I reset the X to FRAME_WIDTH + 200 and do a "forever" sequence.
That was working perfectly, but I would like to add a random Y coordinate every time the animation finishes.
I was able to do it, but that would only change the Y coordinate once.
How can I achieve this?
Here's my current code:
func addClouds() {
let cloud1 = SKSpriteNode(imageNamed: "cloud1")
let cloud2 = SKSpriteNode(imageNamed: "cloud2")
let cloud3 = SKSpriteNode(imageNamed: "cloud3")
let cloud4 = SKSpriteNode(imageNamed: "cloud4")
let cloud5 = SKSpriteNode(imageNamed: "cloud5")
cloud1.zPosition = ZIndexPosition.CLOUD
cloud1.position = CGPoint(x: self.FRAME_WIDTH - 100, y: self.FRAME_HEIGHT / 2 - 150)
cloud1.size = CGSize(width: 44, height: 14)
cloud2.zPosition = ZIndexPosition.CLOUD
cloud2.position = CGPoint(x: self.FRAME_WIDTH + 150, y: self.FRAME_HEIGHT - 100)
cloud2.size = CGSize(width: 104, height: 16)
cloud3.zPosition = ZIndexPosition.CLOUD
cloud3.position = CGPoint(x: self.FRAME_WIDTH - 50, y: self.FRAME_HEIGHT - 200)
cloud3.size = CGSize(width: 8, height: 6)
cloud4.zPosition = ZIndexPosition.CLOUD
cloud4.position = CGPoint(x: self.FRAME_WIDTH + 200, y: self.FRAME_HEIGHT / 2 - 50)
cloud4.size = CGSize(width: 116, height: 32)
cloud5.zPosition = ZIndexPosition.CLOUD
cloud5.position = CGPoint(x: self.FRAME_WIDTH, y: self.FRAME_HEIGHT - 250)
cloud5.size = CGSize(width: 24, height: 6)
let resetCloud1YPos = SKAction.moveToY(self.randomCloud1, duration: 0)
let resetCloud2YPos = SKAction.moveToY(self.randomCloud2, duration: 0)
let resetCloud3YPos = SKAction.moveToY(self.randomCloud3, duration: 0)
let resetCloud4YPos = SKAction.moveToY(self.randomCloud4, duration: 0)
let resetCloud5YPos = SKAction.moveToY(self.randomCloud5, duration: 0)
let resetCloud1Pos = SKAction.moveToX((self.FRAME_WIDTH * 2) - 100, duration: 0)
let resetCloud2Pos = SKAction.moveToX((self.FRAME_WIDTH * 2) - 150, duration: 0)
let resetCloud3Pos = SKAction.moveToX((self.FRAME_WIDTH * 2) - 50, duration: 0)
let resetCloud4Pos = SKAction.moveToX((self.FRAME_WIDTH * 2) - 200, duration: 0)
let resetCloud5Pos = SKAction.moveToX((self.FRAME_WIDTH * 2) - 20, duration: 0)
let moveCloud1 = SKAction.moveToX(-100, duration: 28)
let cloud1Sequence = SKAction.sequence([moveCloud1, resetCloud1Pos, resetCloud1YPos])
let cloud1Forever = SKAction.repeatActionForever(cloud1Sequence)
let moveCloud2 = SKAction.moveToX(-100, duration: 24)
let cloud2Sequence = SKAction.sequence([moveCloud2, resetCloud2Pos, resetCloud2YPos])
let cloud2Forever = SKAction.repeatActionForever(cloud2Sequence)
let moveCloud3 = SKAction.moveToX(-100, duration: 35)
let cloud3Sequence = SKAction.sequence([moveCloud3, resetCloud3Pos, resetCloud3YPos])
let cloud3Forever = SKAction.repeatActionForever(cloud3Sequence)
let moveCloud4 = SKAction.moveToX(-100, duration: 13)
let cloud4Sequence = SKAction.sequence([moveCloud4, resetCloud4Pos, resetCloud4YPos])
let cloud4Forever = SKAction.repeatActionForever(cloud4Sequence)
let moveCloud5 = SKAction.moveToX(-100, duration: 18)
let cloud5Sequence = SKAction.sequence([moveCloud5, resetCloud5Pos, resetCloud5YPos])
let cloud5Forever = SKAction.repeatActionForever(cloud5Sequence)
cloud1.runAction(cloud1Forever)
cloud2.runAction(cloud2Forever)
cloud3.runAction(cloud3Forever)
cloud4.runAction(cloud4Forever)
cloud5.runAction(cloud5Forever)
self.addChild(cloud1)
self.addChild(cloud2)
self.addChild(cloud3)
self.addChild(cloud4)
self.addChild(cloud5)
}
randomCloud1,2,3,4 and 5 is just a random generation within the screen height bounds.
Thanks in advance.
If I understand what you're trying to accomplish, the following code should help you:
// ViewController.swift
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
//create and position a test SKSpriteNode
let cloud = SKSpriteNode()
cloud.color = SKColor.blueColor()
cloud.position = CGPoint(x: self.frame.size.width - 100, y: 400)
cloud.size = CGSize(width: 44, height: 14)
self.addChild(cloud)
//pass the SKSpriteNode into the moveNode function
self.moveNode(cloud)
}
//reposition the node
func repositionNode(node: SKSpriteNode) {
print("repositioning node")
node.position = CGPointMake(self.frame.size.width - 100, self.randomCloudPosition())
print(node.position.y)
self.moveNode(node)
}
//move the node again
func moveNode(node: SKSpriteNode) {
node.runAction(SKAction.moveToX(-100, duration: 28), completion: {
self.repositionNode(node)
})
}
//return a random number between 300 and 799 (change this for your specific case)
func randomCloudPosition() -> CGFloat {
return CGFloat(arc4random_uniform(500) + 300) //should be between 300 and 799
}
}
You should be able to create your five clouds (or however many) and then just pass each one into moveNode and the animation will continue indefinitely

Resources