This is how I made my nodes to move when you tap on the left and the right side of the screen but how can I make them separate when one finger in on the left side and the other on the right side ?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let location = (touches.first)?.location(in: self.view)
if (location?.x)! < (self.view?.bounds.size.width)!/2 {
player1.run(SKAction.moveTo(x: 0 + player1.size.width / 2, duration: 0.1))
player2.run(SKAction.moveTo(x: 0 + player1.size.width + player2.size.width / 2, duration: 0.1))
} else {
player1.run(SKAction.moveTo(x: self.frame.width - player1.size.width - player2.size.width / 2, duration: 0.1))
player2.run(SKAction.moveTo(x: self.frame.width - player1.size.width / 2, duration: 0.1))
}
}
To enable the multiple touch on your game , you should use : view.isMultipleTouchEnabled = true. Here you can find the API references
Then, if you present your scene from a SKS file, usually the anchorPoint setted is (0.5,0.5) so to work with my example below be sure to add this line in your GameViewController:
scene.anchorPoint = CGPoint.zero
before the line view.presentScene(scene) to have your anchorPoint setted to 0 for your current scene.
You should also think to "protect" your action from multiple calls especially when you launch these actions from the touch event delegate methods. This can be possible with action(forKey: where you check if an action is running or not.
I have made a more detailed example to show you how it can be possible to obtain the multitouch for your actions in Sprite-kit:
import SpriteKit
class GameScene: SKScene {
private var player1 : SKSpriteNode!
private var player2 : SKSpriteNode!
override func didMove(to view: SKView) {
self.player1 = SKSpriteNode.init(color: .red, size: CGSize(width:50,height:50))
self.player2 = SKSpriteNode.init(color: .yellow, size: CGSize(width:50,height:50))
addChild(player1)
addChild(player2)
self.player1.position=CGPoint(x:self.frame.width/2,y:(self.frame.height/2)+100)
self.player2.position=CGPoint(x:self.frame.width/2,y:(self.frame.height/2)-100)
if let view = self.view {
view.isMultipleTouchEnabled = true
}
}
func rightActions() {
if (player1.action(forKey: "right") == nil) {
player1.run(SKAction.moveTo(x: 0 + player1.size.width / 2, duration: 0.1),withKey:"right")
}
if (player2.action(forKey: "right") == nil) {
player2.run(SKAction.moveTo(x: 0 + player1.size.width + player2.size.width / 2, duration: 0.1),withKey:"right")
}
}
func leftActions() {
if (player1.action(forKey: "left") == nil) {
player1.run(SKAction.moveTo(x: self.frame.width - player1.size.width - player2.size.width / 2, duration:0.1) ,withKey:"left")
}
if (player2.action(forKey: "left") == nil) {
player2.run(SKAction.moveTo(x: self.frame.width - player1.size.width / 2, duration: 0.1),withKey:"left")
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
let touch = t as UITouch
let location = touch.location(in: self)
let touchedNode = self.atPoint(location)
let tapCount = touch.tapCount
print("tapCount: \(tapCount) - touchedNode:\(touchedNode) - location:\(location)")
location.x < (self.size.width/2) ? rightActions() : leftActions()
}
}
}
Related
I am building a spritekit game and have just started the project. I have a circle on the screen which starts in the center, and when i drag my finger from the circle outward, it will show a dotted line/bezierpath connected to the ball which will help the user see where it is aiming the ball. When the user lifts their finger, the ball will shoot in the opposite direction of the aim line. (Think a game like soccer stars or pool). The issue is that the maneuver works the first time when everything starts in the middle: I drag my finger and the ball shoots in opposite direction then stops. But when I try it again, the position of the aiming line says it is the same as the ball (It should be), but then it shows up like an inch away from the ball on the screen. I feel like this may be an issue that the scene(s) behind the objects may not be the same size? But I'm confused because I think I'm only using one scene.
GameViewController viewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
// Load the SKScene from 'GameScene.sks'
if let scene = SKScene(fileNamed: "GameScene") {
// Set the scale mode to scale to fit the window
scene.scaleMode = .aspectFill
scene.size = view.bounds.size
//scene.anchorPoint = CGPoint(x: 0.0, y: 0.0)
// Present the scene
view.presentScene(scene)
}
view.ignoresSiblingOrder = true
view.showsFPS = true
view.showsNodeCount = true
}
}
GameScene Code (Doubt you need all of it but whatever):
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKShapeNode(circleOfRadius: 35)
var touchingBall = false
var aimLine = SKShapeNode()
var startAimPoint = CGPoint()
var endAimPoint = CGPoint()
let damping:CGFloat = 0.94
override func didMove(to view: SKView) {
ball.fillColor = SKColor.orange
ball.name = "ball"
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
var physicsBody = SKPhysicsBody(circleOfRadius: 35)
ball.physicsBody = physicsBody
ball.physicsBody?.affectedByGravity = false
ball.physicsBody?.friction = 10.0
ball.position = CGPoint(x: frame.midX, y: frame.midY)
self.addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOUCHES BEGAN.")
for touch in touches {
print("TB: \(touchingBall)")
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "ball" {
// touched inside node
if ball.physicsBody!.angularVelocity <= 0.0{
touchingBall = true
startAimPoint = ball.position
print(touchingBall)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOCUHES MOVED.")
for touch in touches {
let location = touch.location(in: self)
if touchingBall{
endAimPoint = location
assignAimLine(start: startAimPoint, end: endAimPoint)
print("Moving touched ball")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches ended. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches cancelled. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x - startAimPoint.x) * 3, dy: -(endAimPoint.y - startAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
print(ball.physicsBody!.velocity)
let dx2 = ball.physicsBody!.velocity.dx * damping
let dy2 = ball.physicsBody!.velocity.dy * damping
ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)
}
func assignAimLine(start: CGPoint, end: CGPoint){
aimLine.removeFromParent()
var bezierPath = UIBezierPath()
bezierPath.move(to: start)
bezierPath.addLine(to: shortenedEnd(startPoint: start, endPoint: end))
var pattern : [CGFloat] = [10.0, 10.0]
let dashed = SKShapeNode(path: bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern))
aimLine = dashed
aimLine.position = ball.position
aimLine.zPosition = 0
self.addChild(aimLine)
}
func hypotenuse(bp: UIBezierPath) -> Double{
var a2 = bp.cgPath.boundingBox.height * bp.cgPath.boundingBox.height
var b2 = bp.cgPath.boundingBox.width * bp.cgPath.boundingBox.width
return Double(sqrt(a2 + b2))
}
func hypotenuse(startP: CGPoint, endP: CGPoint) -> Double{
var bezierPath = UIBezierPath()
bezierPath.move(to: startP)
bezierPath.addLine(to: endP)
return hypotenuse(bp: bezierPath)
}
func shortenedEnd(startPoint: CGPoint, endPoint: CGPoint) -> CGPoint{
var endTemp = endPoint
//while hypotenuse(startP: startPoint, endP: endTemp) > 150{
endTemp = CGPoint(x: endTemp.x / 1.01, y: endTemp.y / 1.01)
//}
return endTemp
}
func addTestPoint(loc: CGPoint, color: UIColor){
var temp = SKShapeNode(circleOfRadius: 45)
temp.fillColor = color
temp.position = loc
self.addChild(temp)
}
}
I tried printing the frame size for the scene and it says 400 something x 700 something (I am testing on iPhone 6 Plus), and it says the UIScreen is same size so i don't know what issue is. Overall, I just need the aiming line to be on the center of the circle more than just the first time I try the maneuver. Thanks.
Like I mentioned in the comments, your problem was how you were laying out your paths. The code below makes the path relative to the ball instead of absolute to the scene. I also fixed the issue with creating new shapes every time.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKShapeNode(circleOfRadius: 35)
var touchingBall = false
var aimLine = SKShapeNode()
var endAimPoint = CGPoint()
override func didMove(to view: SKView) {
ball.fillColor = SKColor.orange
ball.name = "ball"
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
ball.position = CGPoint(x: frame.midX, y: frame.midY)
let physicsBody = SKPhysicsBody(circleOfRadius: 35)
physicsBody.affectedByGravity = false
physicsBody.friction = 10.0
physicsBody.linearDamping = 0.94
ball.physicsBody = physicsBody
self.addChild(ball)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOUCHES BEGAN.")
for touch in touches {
print("TB: \(touchingBall)")
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "ball" {
// touched inside node
if ball.physicsBody!.angularVelocity <= 0.0{
touchingBall = true
aimLine.path = nil
self.addChild(aimLine)
print(touchingBall)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
print("TOCUHES MOVED.")
for touch in touches {
let location = touch.location(in: self)
if touchingBall{
endAimPoint = self.convert(location, to: ball)
assignAimLine(end: endAimPoint)
print("Moving touched ball")
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches ended. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touches cancelled. \(touchingBall)")
if touchingBall == true{
ball.physicsBody!.applyImpulse(CGVector(dx: -(endAimPoint.x) * 3, dy: -(endAimPoint.y) * 3))
}
touchingBall = false
aimLine.removeFromParent()
print(touchingBall)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
print(ball.physicsBody!.velocity)
//let dx2 = ball.physicsBody!.velocity.dx * damping
//let dy2 = ball.physicsBody!.velocity.dy * damping
//ball.physicsBody!.velocity = CGVector(dx: dx2, dy: dy2)
}
func assignAimLine(end: CGPoint){
let bezierPath = UIBezierPath()
bezierPath.move(to: CGPoint.zero)
bezierPath.addLine(to: end)
let pattern : [CGFloat] = [10.0, 10.0]
aimLine.position = ball.position
aimLine.path = bezierPath.cgPath.copy(dashingWithPhase: 2, lengths: pattern)
aimLine.zPosition = 0
}
func addTestPoint(loc: CGPoint, color: UIColor){
var temp = SKShapeNode(circleOfRadius: 45)
temp.fillColor = color
temp.position = loc
self.addChild(temp)
}
}
I'm working on a game project with Xcode.
I've written the code that makes the ship shoot the projectiles, but I don't know what function to use to make the ship shoot automatically.
Could you help me? Thank you in advance!
Here's my code, from the GameScene :
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let projectile = SKSpriteNode(imageNamed: "projectile")
projectile.zPosition = 1
projectile.position = CGPoint(x: player.position.x, y: player.position.y)
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody?.isDynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.None
projectile.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(projectile)
let action = SKAction.moveTo(x: self.frame.width + projectile.size.width, duration: 0.5)
projectile.run(action, completion: {
projectile.removeAllActions()
projectile.removeFromParent()
})
}
Based on a comment by Jake I am assuming that you want the ship to fire "automatically" not repeating while holding the finger down.
You can use the update func to control the automatic shooting. in my example the update command fires every 1 second
private var updateTime: Double = 0
override func update(_ currentTime: TimeInterval) {
if updateTime == 0 {
updateTime = currentTime
}
if currentTime - updateTime > 1 {
self.shoot()
updateTime = currentTime
}
}
func shoot() {
let projectile = SKSpriteNode(imageNamed: "projectile")
projectile.zPosition = 1
projectile.position = CGPoint(x: player.position.x, y: player.position.y)
projectile.physicsBody = SKPhysicsBody(circleOfRadius: projectile.size.width/2)
projectile.physicsBody?.isDynamic = true
projectile.physicsBody?.categoryBitMask = PhysicsCategory.Projectile
projectile.physicsBody?.contactTestBitMask = PhysicsCategory.Monster
projectile.physicsBody?.collisionBitMask = PhysicsCategory.None
projectile.physicsBody?.usesPreciseCollisionDetection = true
self.addChild(projectile)
let action = SKAction.moveTo(x: self.frame.width + projectile.size.width, duration: 0.5)
projectile.run(action, completion: {
projectile.removeAllActions()
projectile.removeFromParent()
})
}
I've been able to detect degrees, but I'm unsure on how to move the sprite in 360 degrees.
I don't want the sprite to be able to only move in certain sections, as shown in the picture above, but rather have it be able to move in a full circle.
Code:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if (ball.frame.contains(location)) {
stickActive = true
}else {
stickActive = false
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if (stickActive == true) {
var v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
let angle = atan2(v.dy, v.dx)
var deg = angle * CGFloat(180 / M_PI)
print(deg + 180)
let lenght:CGFloat = base.frame.size.height / 2 - 20
let xDist: CGFloat = sin(angle - 1.57079633) * lenght
let yDist: CGFloat = cos(angle - 1.57079633) * lenght
ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)
if (base.frame.contains(location)) {
ball.position = location
}else {
ball.position = CGPoint(x: base.position.x - xDist, y: base.position.y + yDist)
}
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if (stickActive == true) {
let move: SKAction = SKAction.move(to: base.position, duration: 0.2)
move.timingMode = .easeOut
ball.run(move)
}
}
This is super simple, although it took me quite awhile to figure out how to do it.
TouchesBegan method:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if isTracking == false && DPad.contains(location) {
isTracking = true
}
}
}
TouchesMoved method:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location: CGPoint = touch.location(in: self)
if isTracking == true {
v = CGVector(dx: location.x - DPad.position.x, dy: location.y - DPad.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / Double.pi)
let Length:CGFloat = DPad.frame.size.height / 2
let xDist: CGFloat = sin(angle - 1.57079633) * Length
let yDist: CGFloat = cos(angle - 1.57079633) * Length
xJoystickDelta = location.x - DPad.position.x
yJoystickDelta = location.y - DPad.position.y
if DPad.contains(location) {
thumbNode.position = location
} else {
thumbNode.position = CGPoint(x: DPad.position.x - xDist, y: DPad.position.y + yDist)
}
}
}
}
TouchesEnded method:
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
isTracking = false
thumbNode.run(SKAction.move(to: DPad.position, duration: 0.01))
xJoystickDelta = 0
yJoystickDelta = 0
}
The update(_ currentTime:) method:
if v.dx > abs(v.dy) {
yourPlayer.texture = SKTexture(imageNamed: "rightTexture")
} else if v.dx < -abs(v.dy) {
player.texture = SKTexture(imageNamed: "leftTexture")
} else if v.dy < 0 {
yourPlayer.texture = SKTexture(imageNamed: "frontTexture")
} else if v.dy > 0 {
yourPlayer.texture = SKTexture(imageNamed: "backTexture")
}
//This code moves your character where-ever you want it too
let xScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
let yScale = CGFloat(4) //adjust to your preference. Higher means slower, lower means faster
let xAdd = xScale * self.xJoystickDelta
let yAdd = yScale * self.yJoystickDelta
yourPlayerNode.position.x += xAdd
yourPlayerNode.position.y += yAdd
These things need to be outside your didMove(toView:) method:
var xJoystickDelta:CGFloat = 0
var yJoystickDelta:CGFloat = 0
var v = CGVector()
var isTracking:Bool = false
var DPad = SKSpriteNode()
var thumbNode = SKSpriteNode()
-Explanation-
In the touchesBegan method, the if-statement is testing to see if you are not controlling the thumbNode and if your touch is inside the DPad Node. Then it starts the tracking.
In the touchesMoved once isTracking == true it starts calculating the neccessary math and then adjusting the various things required. (its complicated, what matters most is that it works.)
In the touchesEnded method, it is testing to see when you lift your finger off of the screen, then it resets everything for the next usage.
In the update(_ current:) method, the code is calculating the angle of the CGVector and then setting a texture (or whatever you want to do) inside of the various cases. Then its calculating the position of the thumbNode inside the DPad and moving your player (or whatever you need to move) around in the scene. Adjust the xScale and yScale floats higher to slow down the movement, and lower to increase the movement of whatever you are trying to move.
-Extra neccessary stuff-
You need to set up the DPad and thumbNode inside your didMove(toView:) method:
thumbNode.size = CGSize(width: 50, height: 50)
DPad.size = CGSize(width: 150, height: 150)
DPad.position = CGPoint(x: 0, y: 0)
thumbNode.position = DPad.position
DPad.zPosition = 3
thumbNode.zPosition = 4
DPad.texture = SKTexture(imageNamed: "yourBaseTexture")
thumbNode.texture = SKTexture(imageNamed: "yourStickTexture")
self.addChild(thumbNode)
self.addChild(DPad)
You only have to move the DPad.position to wherever you want. The thumbNode will move along with it. Also, if you have any problems be sure to ask me so I can help you.
Having some troubles figuring out how to move these objects with touch. Simply touching them and moving them is what i'm focusing on figuring out right now. Below I will add most of the code from GameScene.swift, it should be enough to help.. I think. However, I do have another class called Tetromino.swift and if you need that to help answer my question, let me know and I will add it in!
I've added touchesBegan, touchesMoved, and touchesEnded and i've been trying some different things but cannot get the objects to move - so the code isn't correct in them. The objects are squares that make up different Tetromino pieces. Thanks in advance!
class GameScene: SKScene {
var activeTetromino1 = Tetromino()
var activeTetromino2 = Tetromino()
var activeTetromino3 = Tetromino()
override func didMove(to view: SKView) {
// Setup scene
self.anchorPoint = CGPoint(x: 0, y: 0)
activeTetromino1 = Tetromino(drawTetrominoAtPoint(location: CGPoint(x: frame.width / 4, y: frame.height / 4)))
activeTetromino2 = Tetromino(drawTetrominoAtPoint(location: CGPoint(x: frame.width / 2, y: frame.height / 4)))
activeTetromino3 = Tetromino(drawTetrominoAtPoint(location: CGPoint(x: frame.width / 4 * 3, y: frame.height / 4)))
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in (touches) {
//let location = touch.location(in: self)
drawTetrominoAtPoint(location: touch.location(in: self))
/*
if activeTetromino1.contains(location) {
activeTetromino1.position = location
}
*/
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in (touches) {
drawTetrominoAtPoint(location: touch.location(in: self))
/*
let location = touch.location(in: self)
if activeTetromino1.contains(location) {
activeTetromino1.position = location
}
*/
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
//activeTetromino1 = Tetromino(position = CGPoint(x: frame.width / 4, y: frame.height / 4))
}
override func update(_ currentTime: CFTimeInterval) {
// Called before each frame is rendered
}
func drawTetrominoAtPoint(location: CGPoint) {
let t = Tetromino()
for row in 0..<t.bitmap.count {
for col in 0..<t.bitmap[row].count {
if t.bitmap[row][col] > 0 {
let block = t.bitmap[row][col]
let square = SKSpriteNode(color: colors[block], size: CGSize(width: blockSize, height: blockSize))
square.anchorPoint = CGPoint(x: 1.0, y: 0)
square.position = CGPoint(x: col * Int(blockSize) + col, y: -row * Int(blockSize) + -row)
square.position.x += location.x
square.position.y += location.y
self.addChild(square)
}
}
}
}
}
I followed many different tutorials on collision and created my own game where i want to declare a collision between a coin and a player. However, after implementing the collision code my two nodes are not responding to the collision...can someone help me out please?
import SpriteKit
import GameplayKit
// Collision categories
enum ColliderType: UInt32 {
case playerCase = 1
case coinCase = 2
case borderCase = 3
}
class GameScene: SKScene, SKPhysicsContactDelegate {
let player = SKSpriteNode(imageNamed:"block")
let buttonDirLeft = SKSpriteNode(imageNamed: "left")
let buttonDirRight = SKSpriteNode(imageNamed: "right")
let coins = SKSpriteNode(imageNamed: "coins")
let background = SKSpriteNode(imageNamed: "background")
var pressedButtons = [SKSpriteNode]()
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
//score label
let points = SKLabelNode(text: "0")
points.position = CGPoint(x: 530, y: 260)
points.zPosition = 6
points.fontColor = UIColor.black
points.fontSize = 50
addChild(points)
//Set Background
background.zPosition = 1
background.position = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
background.size.width = 580
background.size.height = 320
addChild(background)
// Player
player.position = CGPoint(x: 250, y: 40)
player.zPosition = 2
player.texture?.filteringMode = .nearest
// player!.collisionBitMask = 0 //
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.height / 2.0)
player.physicsBody?.isDynamic = false
player.physicsBody?.allowsRotation = false
player.physicsBody?.affectedByGravity = false
player.physicsBody!.categoryBitMask = ColliderType.playerCase.rawValue
player.physicsBody!.contactTestBitMask = ColliderType.coinCase.rawValue
player.physicsBody!.collisionBitMask = ColliderType.coinCase.rawValue
self.addChild(player)
// button left
buttonDirLeft.position = CGPoint(x: 30, y: 35)
buttonDirLeft.zPosition = 4
buttonDirLeft.size.width = 270
buttonDirLeft.size.height = 320
buttonDirLeft.alpha = 0.0
self.addChild(buttonDirLeft)
// button right
buttonDirRight.position = CGPoint(x: 530, y: 35)
buttonDirRight.zPosition = 4
buttonDirRight.size.width = 270
buttonDirRight.size.height = 320
buttonDirRight.alpha = 0.0
self.addChild(buttonDirRight)
// setting border around game
let borderBody = SKPhysicsBody(edgeLoopFrom: self.frame)
borderBody.friction = 0
self.physicsBody = borderBody
//ENEMY SETTINGS START
//repeat coing spawning
run(SKAction.repeatForever(
SKAction.sequence([
SKAction.run(spawnCoins),
SKAction.wait(forDuration: 1.0)])))
}
//coin settings
func random() -> CGFloat {
return CGFloat(Float(arc4random()) / 0xFFFFFFFF)
}
func random(min: CGFloat, max: CGFloat) -> CGFloat {
return random() * (max - min) + min
}
//spawn coins
func spawnCoins() {
// 2
let coins = SKSpriteNode(imageNamed: "coins")
coins.zPosition = 2
coins.size.width = 40
coins.size.height = 40
let action = SKAction.moveTo(y: -350, duration: TimeInterval(random(min: 1, max: 5)))
let remove = SKAction.run({coins.removeFromParent(); print("coins removed from scene")})
let sequence = SKAction.sequence([action,remove])
coins.physicsBody = SKPhysicsBody(rectangleOf: coins.size )
coins.physicsBody?.isDynamic = false
coins.physicsBody!.affectedByGravity = false
coins.physicsBody!.categoryBitMask = ColliderType.coinCase.rawValue
coins.physicsBody!.contactTestBitMask = ColliderType.playerCase.rawValue
coins.physicsBody!.collisionBitMask = ColliderType.playerCase.rawValue
coins.run(sequence)
coins.size.width = 20
coins.size.height = 20
coins.name = "coins"
// coins.physicsBody!.collisionBitMask = 0
coins.position = CGPoint(x: frame.size.width * random(min: 0, max: 1), y: frame.size.height + coins.size.height/2)
addChild(coins)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
/* Called before each frame is rendered */
if pressedButtons.index(of: buttonDirLeft) != nil {
player.position.x -= 3.0
}
if pressedButtons.index(of: buttonDirRight) != nil {
player.position.x += 3.0
}
// Update entities
}
//MOVEMENT FUNCTIONS START HERE
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// I check if they are already registered in the list
if button.contains(location) && pressedButtons.index(of: button) == nil {
pressedButtons.append(button)
}
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
// if I get off the button where my finger was before
if button.contains(previousLocation)
&& !button.contains(location) {
// I remove it from the list
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
// if I get on the button where I wasn't previously
else if !button.contains(previousLocation)
&& button.contains(location)
&& pressedButtons.index(of: button) == nil {
// I add it to the list
pressedButtons.append(button)
}}}}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.location(in: self)
let previousLocation = touch.previousLocation(in: self)
for button in [buttonDirLeft, buttonDirRight] {
if button.contains(location) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
else if (button.contains(previousLocation)) {
let index = pressedButtons.index(of: button)
if index != nil {
pressedButtons.remove(at: index!)
}
}
}
}
}
func didBeginContact(contact: SKPhysicsContact){
print("colliding!")
}
Contact will happen only if at least one body is dynamic. So either set your player or coin to be dynamic and if everything else is set correctly (if categories are set properly and didBeginContact method implementation is correct) your bodies will now collide / make contacts. If you are interested only in contacts, set collision bit mask to 0.