moving buttons along with the camera in swift - ios

I am working on a game where my player moves when buttons are pressed, so I made the buttons children of the camera. However when my camera moves, the buttons appear where they should, but when I press again nothing happens.
Here is some code about the camera and buttons.
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
enumerateChildNodes(withName: "//*", using: { node, _ in
if let eventListenerNode = node as? EventListenerNode {
eventListenerNode.didMoveToScene()
}
})
world = childNode(withName: "World")!
player = (world.childNode(withName: "player") as! Player)
spikes = world.childNode(withName: "spikes") as! SKSpriteNode
spikes.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: spikes.size.width/2, height: spikes.size.height/2))
spikes.physicsBody?.categoryBitMask = PhysicsCategory.Spikes
spikes.physicsBody?.isDynamic = false
self.addChild(cameraNode)
camera = cameraNode
cameraNode.position = CGPoint(x: 0 , y: 0)
cameraToMove = cameraNode.position.y - player.position.y
setupCamera()
left = SKSpriteNode(imageNamed: "leftButton")
right = SKSpriteNode(imageNamed: "rightButton")
jump = SKSpriteNode(imageNamed: "upButton")
jump.size.width /= 2
jump.size.height /= 2
left.position = CGPoint(x: -self.size.width/2 + left.size.width, y: -self.size.height/2 + left.size.height)
right.position = CGPoint(x: left.position.x + 2 * right.size.width, y:(camera?.position.y)! - self.size.height/2 + left.size.height)
jump.position = CGPoint(x: self.frame.width/2 - jump.size.width, y:(camera?.position.y)! - self.size.height/2 + left.size.height)
cameraNode.addChild(left)
cameraNode.addChild(right)
cameraNode.addChild(jump)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let location:CGPoint = (touch?.location(in: self))!
if left.contains(location){
move(forTheKey: "left")
print("left")
}
else if right.contains(location){
move(forTheKey: "right")
print("right")
}
else if jump.contains(location){
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 240))
}else{
print(location)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
let location:CGPoint = (touch?.location(in: self))!
if left.contains(location){
player.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
print("left removed")
}
else if right.contains(location){
player.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
print("right removed")
}
else if jump.contains(location){
print("jump removed")
}else{
print("else")
print(location)
print(left.position)
print(convert(left.position, from: cameraNode))
print(convert(left.position, to: cameraNode))
print(camera?.position.y)
player.physicsBody?.velocity.dx = 0
}
}
As you can see I have a lot of prints to check the left button position.
In the beginning the y position is at -577. after the camera moves, the button appears where it should at -450. but cant press it because its position is still at -577. I also tried to update its position by converting the position to the camera, but didn't work.
I would really appreciate if someone can help.

You want to use the touch as it is relative to your camera, not relative to the scene, since your buttons are in the coordinate system of the camera.
Change let location:CGPoint = (touch?.location(in: self))! to let location:CGPoint = (touch?.location(in: self.camera))!
then your buttons should function properly.

Related

why when ever I try to tap on my SKSpriteNode it is not interactive

I am trying to have my SKSpriteNode named "slots" be tapped on when ever a user is trying to hit a target in the middle of the sprite. But whenever I Tapp on the slot in does not blink or do anything really.
I was trying to have it blink and print("Tapped on shotSlotNode") before I'll go on to continue creating this game but im still struck on this part of the game.
var slots = [shotSlot]()
var targets = [shotSlot]()
var gameScore: SKLabelNode!
var slotsRed = [targetSlotRed]()
var shotSlotNode: shotSlot? // Define a property for shotSlotNode
override func didMove(to view: SKView) {
let backGround = SKSpriteNode(imageNamed: "background")
backGround.position = CGPoint(x: 512, y: 384)
backGround.blendMode = .replace
backGround.zPosition = -1
// line 20 makes sure things go on top of the background view.
backGround.scale(to: CGSizeMake(1024, 768))
// I used line 21 to strech the image out to fix my scrrens size because I know I set my screen size to 1024 in the GameScene UI
addChild(backGround)
gameScore = SKLabelNode(fontNamed: "Chalkduster")
gameScore.text = "Score: 0"
gameScore.position = CGPoint(x: 480, y: 70)
addChild(gameScore)
self.view?.isMultipleTouchEnabled = true
for i in 0 ..< 3 { createSlot(at: CGPoint(x: 120 + (i * 370), y: 560)) }
for i in 0 ..< 3 { createSlot(at: CGPoint(x: 120 + (i * 370), y: 370)) }
for i in 0 ..< 3 { createSlot(at: CGPoint(x: 120 + (i * 370), y: 200)) }
// this code breaks my slots into 3 rows and 3 cloumms of the shotSlots.
for i in 0 ..< 1 { createGreenTarget(at: CGPoint(x: 120 + (i * 370), y: 560)) }
for i in 0 ..< 1 { createRedTarget(at: CGPoint(x: 860 + (i * 370), y: 200)) }
}
func slotTapped(_ slot: shotSlot) {
// Make the slot sprite blink
print("Tapped on slot")
let blinkOut = SKAction.fadeAlpha(to: 0.2, duration: 0.15)
let blinkIn = SKAction.fadeAlpha(to: 1, duration: 0.15)
let blink = SKAction.sequence([blinkOut, blinkIn])
let blinkForever = SKAction.repeatForever(blink)
slot.sprite.run(blinkForever)
print("Started blinking")
// Handle the slot tap logic
if slot === shotSlotNode {
print("Tapped on shot slot node")
}
}
// now we need to make this greenTarget slide.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
for slot in slots {
if slot.contains(location) {
// The touch is inside the slot node
print("Tapped on shot slot")
slotTapped(slot)
// You can also check if the tapped slot is your `shotSlotNode`
if slot === shotSlotNode {
print("Tapped on shot slot node")
}
}
}
}
}
func createSlot(at position: CGPoint) {
let slot = shotSlot()
slot.configure(at: position)
slot.zPosition = 1
slot.isUserInteractionEnabled = true
addChild(slot)
targets.append(slot) // Add the slot to the targets array
if position == CGPoint(x: 512, y: 100) {
slot.sprite.name = "shotSlotNode"
slot.isUserInteractionEnabled = true
self.shotSlotNode = slot
print("Set shotSlotNode to sprite with name \(slot.sprite.name)")
}
}
class shotSlot: SKNode {
let sprite = SKSpriteNode(imageNamed: "slots")
func configure(at position: CGPoint) {
self.position = position
sprite.name = "shotSlotNode"
// sprite.position = CGPoint(x: frame.midX, y: frame.midY)
sprite.scale(to: CGSizeMake(220, 140))
sprite.isUserInteractionEnabled = true
sprite.zPosition = 13
addChild(sprite)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if let node = self.childNode(withName: "shotSlotNode") {
let convertedLocation = node.convert(location, from: self)
if node.contains(convertedLocation) {
print("Tapped on shotSlotNode")
}
}
}
}
}

SpriteKit keep moving player in current direction while falling after touchesEnded

I'm making my own Mario Bros. replica for the first level to learn how to make games with iOS, with my own assets. So far I've managed to place three SKSpriteNodes for the controls (left, right, up), and my player node can move in those three directions, but if I make my player jump while running in either direction, as soon as I remove my finger from the "left control", the player loses all its momentum and falls right there (as if it hit a wall) instead of following the parabola.
I don't know what might be needed in this case to be an MRE, so this is basically the whole thing that can reproduce the issue, along with some attempts I've made to make it work.
Basically I tried to apply an impulse / set the velocity / change the position directly and this last one was the one with better results (yet it still makes the player node to fall as soon as I remove the finger from the direction controls).
Here's a video demonstrating the issue.
This is the GameScene
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var player = SKSpriteNode()
private var bg = SKSpriteNode()
private var leftArrow = SKSpriteNode()
private var rightArrow = SKSpriteNode()
private var upArrow = SKSpriteNode()
private var floor = [SKSpriteNode]()
private var isLeftTouched = false
private var isRightTouched = false
private var selectedNodes: [UITouch:SKSpriteNode] = [:]
override func didMove(to view: SKView) {
addBackground()
addFloor()
addPlayer(xOffset: 0, yOffset: 0)
addControls()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 50))
let touch = touches.first! as UITouch
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
for touch in touches {
let location = touch.location(in:self)
if let node = self.atPoint(location) as? SKSpriteNode {
if let name = touchedNode.name {
selectedNodes[touch] = node
if name == "up" {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 60))
} else if name == "left" {
isLeftTouched = true
} else if name == "right" {
isRightTouched = true
}
}
}
}
if let name = touchedNode.name {
if name == "up" {
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 60))
} else if name == "left" {
isLeftTouched = true
} else if name == "right" {
isRightTouched = true
}
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//let direction = ((touches.first?.location(in: self).x)! < (touches.first?.previousLocation(in: self).x)!) ? Direction.LEFT : Direction.RIGHT
//runIn(direction: direction)
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
if selectedNodes[touch] != nil {
if selectedNodes[touch]?.name == "left" {
isLeftTouched = false
} else if selectedNodes[touch]?.name == "right" {
isRightTouched = false
}
selectedNodes[touch] = nil
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
if isLeftTouched {
runIn(direction: Direction.LEFT)
}
if isRightTouched {
runIn(direction: Direction.RIGHT)
}
}
// MARK: INTERACTION METHODS
func runIn(direction: Direction) {
let x = player.position.x + (direction == Direction.RIGHT ? 5 : -5)
let position = CGPoint(x: x, y: player.position.y)
if position.x >= self.frame.maxX || position.x <= self.frame.minX {
return
}
player.position = position
//player.physicsBody?.velocity = CGVector(dx: direction == Direction.RIGHT ? 50 : -50, dy: 0)
//player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 5 : -5 , dy: 0))
}
// MARK: UI METHODS
func addBackground() {
let bgTexture = SKTexture(imageNamed: "bg")
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
bg.size.height = self.frame.height
bg.zPosition = -10
self.addChild(bg)
}
func addPlayer(xOffset: CGFloat, yOffset: CGFloat) {
let playerTexture = SKTexture(imageNamed: "player")
player = SKSpriteNode(texture: playerTexture)
//let xPos = calculateXOffset(for: player, from: self.frame.midX, offset: xOffset)
//let yPos = calculateXOffset(for: player, from: self.frame.midY, offset: yOffset)
player.position = CGPoint(x: self.frame.midX,
y: self.frame.midY)
player.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: player.frame.width, height: player.frame.height))
player.physicsBody?.isDynamic = true
self.addChild(player)
}
func addFloor() {
let blockTexture = SKTexture(imageNamed: "block")
for i in 0 ... (Int) (self.frame.width / blockTexture.size().width) {
let blockNode = SKSpriteNode(texture: blockTexture)
blockNode.position = CGPoint(x: self.frame.minX + (blockNode.frame.width * CGFloat(i)),
y: self.frame.minY + blockNode.frame.height / 2)
blockNode.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: blockNode.frame.width, height: blockNode.frame.height))
blockNode.physicsBody?.isDynamic = false
floor.append(blockNode)
self.addChild(blockNode)
}
}
func addControls() {
addLeftArrow()
addRightArrow()
addUpArrow()
}
func addLeftArrow() {
let leftTexture = SKTexture(imageNamed: "left")
leftArrow = SKSpriteNode(texture: leftTexture)
leftArrow.name = "left"
leftArrow.position = CGPoint(x: calculateXOffset(for: leftArrow, from: self.frame.minX, offset: 50),
y: calculateXOffset(for: leftArrow, from: self.frame.minY, offset: 50))
self.addChild(leftArrow)
}
func addRightArrow() {
let rightTexture = SKTexture(imageNamed: "right")
rightArrow = SKSpriteNode(texture: rightTexture)
rightArrow.name = "right"
rightArrow.position = CGPoint(x: calculateXOffset(for: rightArrow, from: self.frame.minX, offset: 150),
y: calculateXOffset(for: rightArrow, from: self.frame.minY, offset: 50))
self.addChild(rightArrow)
}
func addUpArrow() {
let upTexture = SKTexture(imageNamed: "up")
upArrow = SKSpriteNode(texture: upTexture)
upArrow.name = "up"
upArrow.position = CGPoint(x: calculateXOffset(for: upArrow, from: self.frame.maxX, offset: -(125 + upTexture.size().width)),
y: calculateXOffset(for: upArrow, from: self.frame.minY, offset: 50))
self.addChild(upArrow)
}
// MARK: UTILITY FUNCTIONS
func calculateXOffset(for asset: SKSpriteNode, from coord: CGFloat, offset: CGFloat) -> CGFloat {
let width = asset.frame.width
return coord + offset + width;
}
func calculateYOffset(for asset: SKSpriteNode, from coord: CGFloat, offset: CGFloat) -> CGFloat {
let height = asset.frame.height
return coord + offset + height;
}
}
My Direction enum:
enum Direction {
case LEFT
case RIGHT
case UP
case DOWN
}
And the only change I made in GameViewController was this:
scene.scaleMode = .resizeFill
My GameScene.sks is 926 x 428, only supporting landscape. I also set the LaunchScreen to Main due to a bug in Xcode 12: Background is not filling the whole view SpriteKit
And these are all my assets:
Edit
I tried applying an impulse in my runIn method like this:
player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 2 : -2 , dy: 0))
This makes the player node move in the parabola but now from time to time it gets stuck and the only way to make it move is to make it jump until it happens again.
Here's a video demonstrating the issue again.
If I try to set the velocity instead, then I'm not able to jump while moving and it seems to glide when jumping and moving after.
I ended up following #JohnL suggestion in the comments above, to use an impulse as well to move my player node:
player.physicsBody?.applyImpulse(CGVector(dx: direction == Direction.RIGHT ? 2 : -2 , dy: 0))
The issue where the player node was stuck while moving was removed when changing the floor for a single asset rather than multiple blocks one next to each other.

How to drag and flick a node in SpriteKit while gravity is present?

With my current code, the node is extremely laggy, and moves or teleports in random directions for some reason when its flicked. How can i fix this, and also can someone explain why it is teleporting and moving to random places in the scene.
Also, is there anyway to allow the node to be moved only when it is dragged from its position, rather than being at the gesturerecognizer's coordinates at all times?
override func didMove(to view: SKView) {
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.pan(_:)))
view.addGestureRecognizer(gestureRecognizer)
circleNode.physicsBody = SKPhysicsBody(circleOfRadius: 20)
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
self.addChild(circleNode)
}
#objc func pan(_ recognizer: UIPanGestureRecognizer) {
if recognizer.state == .changed {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
var location = recognizer.location(in: self.view!)
location = self.convertPoint(fromView: location)
circleNode.position = location
}
if recognizer.state == .ended {
self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
let transformerX = 1024/self.view!.frame.size.width
let transformerY = 768/self.view!.frame.size.height
let velocity = recognizer.velocity(in: self.view)
circleNode.physicsBody?.applyForce(CGVector(dx: velocity.x * transformerX, dy: velocity.y * transformerY))
}
}
Here is some code I was playing around with. I'm able to drag and flick a spear (spear Image) and also "pop" a pig head. This is the whole GameScene.Remove the code you don't need. :)
import SpriteKit
import CoreMotion
class GameScene: SKScene, SKPhysicsContactDelegate {
enum CollisionTypes: UInt32{
case spear = 1
case wall = 2
case head = 4
}
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
//Add contact delegate
physicsWorld.contactDelegate = self
self.backgroundColor = .white
self.addChild(spearNode)
self.addChild(headNode)
}
lazy var spearNode: SKSpriteNode = {
let node = SKSpriteNode(imageNamed: "spear2")
node.name = "Spear"
node.physicsBody = SKPhysicsBody(texture: node.texture!,
size: CGSize(width: node.frame.width , height: node.frame.height))
node.position = CGPoint(x:self.frame.midX , y:self.frame.midY)
node.physicsBody?.affectedByGravity = true
node.physicsBody?.allowsRotation = false
node.size = CGSize(width: node.frame.width , height: node.frame.height )
node.physicsBody?.categoryBitMask = CollisionTypes.spear.rawValue
node.physicsBody?.contactTestBitMask = CollisionTypes.head.rawValue
node.physicsBody?.collisionBitMask = CollisionTypes.head.rawValue
return node
}()
lazy var headNode: SKSpriteNode = {
let node = SKSpriteNode(imageNamed: "Pig")
node.name = "Pig"
node.physicsBody = SKPhysicsBody(texture: node.texture!,
size: CGSize(width: node.frame.width , height: node.frame.height))
node.position = CGPoint(x:self.frame.midX , y:self.frame.maxY - 100)
node.physicsBody?.affectedByGravity = true
node.physicsBody?.allowsRotation = false
node.size = CGSize(width: node.frame.width / 2 , height: node.frame.height / 2 )
node.physicsBody?.categoryBitMask = CollisionTypes.head.rawValue
return node
}()
func didBegin(_ contact: SKPhysicsContact){
guard let nodeA = contact.bodyA.node else {return}
guard let nodeB = contact.bodyB.node else {return}
print("Contacted")
if nodeA.name == "Pig" && nodeB.name == "Spear"{
nodeA.removeFromParent()
}
if nodeA.name == "Spear" && nodeB.name == "Pig"{
nodeB.removeFromParent()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in:self)
if spearNode.frame.contains(location) {
touchPoint = location
touching = true
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in: self)
touchPoint = location
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func update(_ currentTime: TimeInterval) {
physicsWorld.gravity = CGVector(dx:0, dy: -9.8)
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-spearNode.position.x, dy: touchPoint.y-spearNode.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
spearNode.physicsBody!.velocity=velocity
}
}
}
Why not simply impart a force to the object based upon the swipe gesture rather than turning off gravity, manually moving the object, and then turning on gravity again when the swipe is over?

make SKPhysicsBody unidirectional

I have a SKSpriteNode as a ball, it's been given all the SKPhysicsBody properties move around in all direction. What I want now is to make it unidirectional (only move in that direction it hasn't move to before and not go back in to a path it had move upon). Currently I have following thoughts on this the problem,
make a fieldBitMask, to the path that is iterated by it and repel
the ball to not go back
apply some kind of force/ impulses on the ball from touchesBegan/ touchesMoved method to keep it from going back
something that can be handled in update method
a lifesaver from stackflowoverflow, who is coding even on the weekend :)
Supporting Code snippets for better understanding,
//getting current touch position by using UIEvent methods
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {return}
let location = touch.location(in: self)
lastTouchPoint = location
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {return}
let location = touch.location(in: self)
lastTouchPoint = location
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
lastTouchPoint = nil
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
lastTouchPoint = nil
}
//ball created
func createPlayer(){
player = SKSpriteNode(imageNamed: "player")
player.position = CGPoint(x: 220, y: 420)
player.zPosition = 1
//physics for ball
player.physicsBody = SKPhysicsBody(circleOfRadius: player.size.width / 2)
player.physicsBody?.allowsRotation = false
player.physicsBody?.linearDamping = 0.5
player.physicsBody?.categoryBitMask = collisionTypes.player.rawValue
player.physicsBody?.contactTestBitMask = collisionTypes.finish.rawValue
player.physicsBody?.collisionBitMask = collisionTypes.wall.rawValue
addChild(player)
}
//unwarp the optional property, calclulate the postion between player touch and current ball position
override func update(_ currentTime: TimeInterval) {
guard isGameOver == false else { return }
if let lastTouchPosition = lastTouchPoint {
//this usually gives a large value (related to screen size of the device) so /100 to normalize it
let diff = CGPoint(x: lastTouchPosition.x - player.position.x, y: lastTouchPosition.y - player.position.y)
physicsWorld.gravity = CGVector(dx: diff.x/100, dy: diff.y/100)
}
}
Well it was a combination little hacks in touchesBegan/ touchesMoved and update func,
First you need to catch on which touch occurred, get it's name (in my
case I made nodes which had alpha of 0, but become visible upon
moving over them i.e alpha 1). In touchesBegan, touchesMoved as follow
guard let touch = touches.first else {return}
let location = touch.location(in: self)
lastTouchPoint = location
let positionInScene = touch.location(in: self)
let touchedNode = self.atPoint(positionInScene)
if let name = touchedNode.name
{
if name == "vortex"
{
touching = false
self.view!.isUserInteractionEnabled = false
print("Touched on the interacted node")
}else{
self.view!.isUserInteractionEnabled = true
touching = true
}
}
}
Second use a BOOL touching to track user interactions, on the screen by using getting a tap recogniser setup, as follow
func setupTapDetection() {
let t = UITapGestureRecognizer(target: self, action: #selector(tapped(_:)))
view?.addGestureRecognizer(t)
}
#objc func tapped(_ tap: UITapGestureRecognizer) {
touching = true
}
Finally in update put checks as follow,
guard isGameOver == false else { return }
self.view!.isUserInteractionEnabled = true
if(touching ?? true){
if let lastTouchPosition = lastTouchPoint {
//this usually gives a large value (related to screen size of the device) so /100 to normalize it
let diff = CGPoint(x: lastTouchPosition.x - player.position.x, y: lastTouchPosition.y - player.position.y)
physicsWorld.gravity = CGVector(dx: diff.x/100, dy: diff.y/100)
}
}
}

Trying to rotate bird up when touch began, and when touch ended rotate down (SceneKit)

When I touch the screen the bird is rotating up at the right angle, but is staying there once touch is ended.
The walls in my game have stopped spawning aswell!?
Here is my code, if anyone can see what I'm doing wrong let me know :D.
Will be very appreciative. Thanks
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameStarted == false{
gameStarted = true
bird.physicsBody?.affectedByGravity = true
let spawn = SKAction.run({
() in
self.createWalls()
})
let delay = SKAction.wait(forDuration: 2.0)
let spawnDelay = SKAction.sequence([delay, spawn])
let spawnDelayForever = SKAction.repeatForever(spawnDelay)
self.run(spawnDelayForever)
let distance = CGFloat(self.frame.width + wallPair.frame.width)
let movePipes = SKAction.moveBy(x: -distance - 50, y: 0, duration: TimeInterval( 0.01 * distance))
let removePipes = SKAction.removeFromParent()
moveAndRemove = SKAction.sequence([movePipes,removePipes])
bird.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
bird.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 35))
let rotateUp = SKAction.rotate(byAngle: 0.2, duration: 0)
bird.run(rotateUp)
}
else{
if died == true{
}
else{
bird.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
bird.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 35))
}
}
for touch in touches{
let location = touch.location(in: self)
if died == true{
if restartButton.contains(location){
restartScene()
}
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameStarted == false{
gameStarted = true
bird.physicsBody?.affectedByGravity = true
let rotateDown = SKAction.rotate(byAngle: -0.2, duration: 0)
bird.run(rotateDown)
}
}
There is not a lot of information here but from what I see. When you start touching you set gameStarted to true. So your if statement in touches ended will not fire because gameStarted is true.

Resources