How to add levels to Flappybird like game? - ios

This might be bit confusing.
This is my override function ATM, where my walls are spawning every 2 seconds.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if gameStarted == false{
gameStarted = true
mexican.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])
mexican.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
mexican.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 65))
I have found a tutorial where the wall spawn duration is made faster but I am unsure how to incorporate this into my code as they have used a new function.
My walls are being spawned in the override function which makes it hard for me to call this when adding my if statement.
func startNewLevel(){
levelNumber += 1
if self.actionForKey("spawningEnemies") != nil{
self.removeActionForKey("spawningEnemies")
}
var levelDuration = timeInterval()
switch levelNumber {
case 1: levelDuration = 2.0
case 2: levelDuration = 1.8
case 3: levelDuration = 1.6
default: levelDuration = 0.5
print("Cannot find level into")
}
let spawn = SKAction.run(spawnEnemy)
let waitToSpawn = SKAction.waitForDuration(levelDuration)
let spawnSequence = SKAction.sequence([waitToSpawn, spawn])
let spawnForever = SKAction.repeatActionForever(spawnSequence)
self.runAction(spawnForever, withKey: "spawningEnemies")
This is where I would be calling the function startNewLevel() but my wall spawning is set up in override func touchedBegan.
func didBegin(_ contact: SKPhysicsContact) {
let firstBody = contact.bodyA
let secondBody = contact.bodyB
if firstBody.categoryBitMask == physicsCategory.bird && secondBody.categoryBitMask == physicsCategory.wall{
score += 1
scoreLabel.text = "\(score)"
firstBody.node?.removeFromParent()
if score == 10 || score == 15 || score == 20{
startNewLevel()
if score > UserDefaults().integer(forKey: "HIGHSCORE") {
saveHighScore()
}
}
else if firstBody.categoryBitMask == physicsCategory.bird && secondBody.categoryBitMask == physicsCategory.wall{
score += 1
scoreLabel.text = "\(score)"
secondBody.node?.removeFromParent()
if score > UserDefaults().integer(forKey: "HIGHSCORE") {
saveHighScore()
}
}
This is probably really confusing but if anyone gets me HOLA you will be my favourite person on the earth.

Related

Why am I getting "Exception caught in AudioQueueInternalNotifyRunning - error -66671" when playing audio?

I have three different AVAudio instances. When trying to play my sound that is "audioPlayer3" I get an exception. Can someone take a look for me?" Also when clicking the button "playAgain"
button it plays "audioPlayer3" and I am not sure why. "audioPlayer" and audioPlayer2 work just fine. The issue is only with "audioPlayer3".
import AVFoundation
import SpriteKit
import GameplayKit
import GameKit
class EggCatchScene: SKScene {
var mainMenuButton = SKSpriteNode(imageNamed: "mainmenuButton2")
var isfacingRight = true;
var isfacingLeft = false
var audioPlayer3 : AVAudioPlayer!
var audioPlayer = AVAudioPlayer()
var audioPlayer2 = AVAudioPlayer()
var submitButton = SKSpriteNode(imageNamed: "submitButton.png")
var scoresubmitAlert = SKSpriteNode(imageNamed: "scoresubmittedAlert.png")
var playagainButton2 = SKSpriteNode(imageNamed: "playagainButton")
var levelLabel: SKLabelNode!
var scoreLabel: SKLabelNode!
var gameoverscoreLabel: SKLabelNode!
var birdSprite = SKSpriteNode(imageNamed: "birdAnimation1.png")
var playagainButton = SKSpriteNode(imageNamed: "playagainButton")
var gameoverScreen = SKSpriteNode(imageNamed: "gameoverScreen")
var leftbuttonisPressed = false
var rightbuttonisPressed = false
var score = 0
private var bear = SKSpriteNode()
private var bearWalkingFrames: [SKTexture] = []
var rightButton = SKSpriteNode(imageNamed: "rightButton")
var eggcatchBackground = SKSpriteNode(imageNamed: "eggcatchBackground")
var leftButton = SKSpriteNode(imageNamed: "leftButton")
var eggcatchGround = SKSpriteNode(imageNamed: "eggcatchGround2")
var flyButton = SKSpriteNode(imageNamed: "upButton")
var eggSprite = SKSpriteNode(imageNamed: "eggSprite")
var number = Int.random(in: 20..<620)
override func didMove(to view: SKView) {
let sound = Bundle.main.path(forResource: "bgMusic.mp3", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer2 = try AVAudioPlayer(contentsOf: url)
audioPlayer2.play()
audioPlayer2.numberOfLoops = 1
} catch {
print(error)
}
let atlas = SKTextureAtlas(named: "BirdAnimation")
let m1 = atlas.textureNamed("birdAnimation1.png")
let m2 = atlas.textureNamed("birdAnimation2.png")
let m3 = atlas.textureNamed("birdAnimation3.png")
let m4 = atlas.textureNamed("birdAnimation4.png")
let m5 = atlas.textureNamed("birdAnimation5.png")
let textures = [m1, m2, m3, m4, m5]
let meleeAnimation = SKAction.animate(with: textures, timePerFrame: 0.07)
birdSprite.run(SKAction.repeatForever(meleeAnimation))
birdSprite.position = CGPoint(x: frame.midX, y: frame.midY)
birdSprite.zPosition = 2
birdSprite.setScale(1)
self.addChild(birdSprite)
eggcatchBackground.position = CGPoint(x: frame.midX, y: frame.midY)
eggcatchBackground.zPosition = 0
eggcatchBackground.size.height = self.size.height
eggcatchBackground.size.width = self.size.width
self.addChild(eggcatchBackground)
mainMenuButton.isHidden = true
mainMenuButton.position = CGPoint(x: frame.midX, y: frame.midY - 260)
mainMenuButton.zPosition = 5
mainMenuButton.setScale(0.5)
self.addChild(mainMenuButton)
submitButton.isHidden = true
submitButton.position = CGPoint(x: frame.midX, y: frame.midY - 75)
submitButton.zPosition = 5
submitButton.setScale(0.5)
self.addChild(submitButton)
gameoverScreen.isHidden = true
gameoverScreen.position = CGPoint(x: frame.midX, y: frame.midY)
gameoverScreen.zPosition = 5
gameoverScreen.setScale(0.5)
self.addChild(gameoverScreen)
eggSprite.position = CGPoint(x: frame.midX, y: self.size.height)
eggSprite.zPosition = 2
eggSprite.setScale(0.2)
self.addChild(eggSprite)
eggcatchGround.position = CGPoint(x: frame.midX, y: 25)
eggcatchGround.zPosition = 2
eggcatchGround.size.width = self.size.width
self.addChild(eggcatchGround)
scoresubmitAlert.isHidden = true
scoresubmitAlert.position = CGPoint(x: frame.midX, y:frame.midY + 65)
scoresubmitAlert.zPosition = 3
scoresubmitAlert.setScale(0.7)
self.addChild(scoresubmitAlert)
flyButton.position = CGPoint(x: 550, y:150 )
flyButton.zPosition = 3
flyButton.setScale(0.2)
self.addChild(flyButton)
playagainButton.isHidden = true
playagainButton.position = CGPoint(x: frame.midX, y:frame.midY )
playagainButton.zPosition = 3
playagainButton.setScale(0.5)
self.addChild(playagainButton)
playagainButton2.isHidden = true
playagainButton2.position = CGPoint(x: frame.midX, y:frame.midY - 320 )
playagainButton2.zPosition = 3
playagainButton2.setScale(0.5)
self.addChild(playagainButton2)
rightButton.position = CGPoint(x: 240, y:150 )
rightButton.zPosition = 3
rightButton.setScale(0.2)
self.addChild(rightButton)
leftButton.position = CGPoint(x: 85, y:150 )
leftButton.zPosition = 3
leftButton.setScale(0.2)
self.addChild(leftButton)
scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
scoreLabel.zPosition = 2
scoreLabel.fontColor = UIColor.red
scoreLabel.position = CGPoint(x: 100, y: 800)
addChild(scoreLabel)
levelLabel = SKLabelNode(fontNamed: "Chalkduster")
levelLabel.zPosition = 2
levelLabel.fontColor = UIColor.red
levelLabel.position = CGPoint(x: 550, y: 800)
addChild(levelLabel)
}
func checkforCollision(){
if(eggSprite.frame.intersects(eggcatchGround.frame)) || (birdSprite.frame.intersects(eggcatchGround.frame)){
let sound = Bundle.main.path(forResource: "gameoverSound.wav", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer3 = try AVAudioPlayer(contentsOf: url)
audioPlayer3.play()
audioPlayer3.numberOfLoops = 0
} catch {
print(error)
}
eggSprite.position.y = 960
submitButton.isHidden = false
playagainButton.isHidden = false
self.birdSprite.removeFromParent()
self.eggSprite.removeFromParent()
self.rightButton.removeFromParent()
self.leftButton.removeFromParent()
self.flyButton.removeFromParent()
print("Game Over")
}
}
override func update(_ currentTime: TimeInterval){
birdSprite.position.y -= 1
checkforCollision()
scoreLabel.text = "Score: \(score)"
if(rightbuttonisPressed == true){
birdSprite.xScale = 1;
birdSprite.position.x += 10
}
if(leftbuttonisPressed == true){
birdSprite.position.x -= 10
birdSprite.xScale = -1;
}
if (score <= 10){
levelLabel.text = "Level 1"
eggSprite.position.y -= 1
}
if (score >= 10){
levelLabel.text = "Level 2"
eggSprite.position.y -= 1.1
}
if (score >= 20){
levelLabel.text = "Level 3"
eggSprite.position.y -= 1.2
}
if (score >= 30){
levelLabel.text = "Level 4"
eggSprite.position.y -= 1.3
}
if (score >= 40){
levelLabel.text = "Level 5"
eggSprite.position.y -= 1.4
}
if (score >= 60){
levelLabel.text = "Level 6"
eggSprite.position.y -= 1.5
}
if (score >= 70){
levelLabel.text = "Level 7"
eggSprite.position.y -= 1.6
}
if (score >= 80){
levelLabel.text = "Level 8"
eggSprite.position.y -= 1.7
}
if (score >= 90){
levelLabel.text = "Level 9"
eggSprite.position.y -= 1.8
}
if (score >= 100){
levelLabel.text = "Level 10"
eggSprite.position.y -= 1.9
}
if (score >= 110){
levelLabel.text = "Level 11"
eggSprite.position.y -= 2
}
if (score >= 120){
levelLabel.text = "Level 12"
eggSprite.position.y -= 2.1
}
if (score >= 130){
levelLabel.text = "Level 13"
eggSprite.position.y -= 2.2
}
if (score >= 140){
levelLabel.text = "Level 14"
eggSprite.position.y -= 2.3
}
if (score >= 150){
levelLabel.text = "Max"
eggSprite.position.y -= 2.4
}
/* if(birdSprite.frame.intersects(eggcatchGround.frame)){
// gameoverScreen.isHidden = false
let sound = Bundle.main.path(forResource: "gameoverSound", ofType: "mp3")!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
audioPlayer.numberOfLoops = 0
} catch {
print(error)
}
submitButton.isHidden = false
playagainButton.isHidden = false
self.birdSprite.removeFromParent()
self.eggSprite.removeFromParent()
self.rightButton.removeFromParent()
self.leftButton.removeFromParent()
self.flyButton.removeFromParent()
print("Game Over")
}*/
let xRange = SKRange(lowerLimit:0,upperLimit:size.width)
let yRange = SKRange(lowerLimit:0,upperLimit:size.height)
//sprite.constraints = [SKConstraint.positionX(xRange,Y:yRange)] // iOS 9
birdSprite.constraints = [SKConstraint.positionX(xRange,y:yRange)] // iOS 10
if(eggSprite.frame.intersects(birdSprite.frame)){
let sound = Bundle.main.path(forResource: "itemGet.wav", ofType: nil)!
let url = URL(fileURLWithPath: sound)
do{
audioPlayer = try AVAudioPlayer(contentsOf: url)
audioPlayer.play()
audioPlayer.numberOfLoops = 0
} catch {
print(error)
}
eggSprite.position.y = self.size.height
//eggSprite.position.x = number
score += 1
}
}
/*func startTimer()
{
countdownTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(decrementCounter), userInfo: nil, repeats: true)
}*/
func decrementTimer(){
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if submitButton.frame.contains(location) {
//submitButton.isHidden = true
submitButton.removeFromParent()
mainMenuButton.isHidden = false
playagainButton.removeFromParent()
playagainButton2.isHidden = false
scoresubmitAlert.isHidden = false
let score1 = GKScore(leaderboardIdentifier: "birdmemoirsleaderboard")
score1.value = Int64(score)
GKScore.report([score1]) { error in
guard error == nil else {
print(error?.localizedDescription ?? "")
return
}
print("done")
}
print("clicked")
}
if playagainButton.frame.contains(location) {
if let eggcatchScene = EggCatchScene(fileNamed: "EggCatchScene") {
let eggcatchScene = EggCatchScene(size: CGSize(width:640, height: 960))
self.view?.presentScene(eggcatchScene, transition: SKTransition.fade(withDuration: 1))
}
}
if playagainButton2.frame.contains(location) {
if let eggcatchScene = EggCatchScene(fileNamed: "EggCatchScene") {
let eggcatchScene = EggCatchScene(size: CGSize(width:640, height: 960))
self.view?.presentScene(eggcatchScene, transition: SKTransition.fade(withDuration: 1))
}
}
if mainMenuButton.frame.contains(location) {
if let mainmenuScene = GameScene2(fileNamed: "GameScene2") {
let mainmenuScene = GameScene2(size: CGSize(width:640, height: 960))
self.view?.presentScene(mainmenuScene, transition: SKTransition.fade(withDuration: 1))
}
}
if flyButton.frame.contains(location) {
birdSprite.position.y += 50
}
if rightButton.frame.contains(location) {
print("clicked")
rightbuttonisPressed = true
//sprite.position.x += 10
}
if leftButton.frame.contains(location) {
print("clicked")
leftbuttonisPressed = true
birdSprite.xScale = -1; }
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
if leftButton.contains(touch.location(in: self)) {
leftbuttonisPressed = false
}
if rightButton.contains(touch.location(in: self)) {
rightbuttonisPressed = false
}
}
}```

Collide type source error - spritekit swift game

So I have adjusted my games ball type from a shape to an image which forced me to redo the physics of my game. I am new to swift and have struggled with fixing my collisions in my swift game.
class GameScene: SKScene, GameDelegate, SKPhysicsContactDelegate {
var ball: Ball!
let ballSpeedX = CGFloat(500)
//ball = Ball(imageNamed:"colorBall.png")
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
// board
let boards = Boards.make(CollideType.BoardStart.rawValue)
var lastBoard: SKNode?
var boardSpeedY: CGFloat { get { return CGFloat(160) * accelerate }}
let boardDistanceY = CGFloat(300)
let boardYDistanceHide = CGFloat(30)
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
let flooeBody = SKPhysicsBody.init(edgeLoopFromRect: self.frame)
self.physicsBody = floorBody
self.physicsBody!.affectedByGravity = false
self.physicsBody!.usesPreciseCollisionDetection = true
self.physicsBody!.dynamic = true
self.physicsBody!.mass = 0
self.physicsBody!.friction = 0
self.physicsBody!.linearDamping = 0
self.physicsBody!.angularDamping = 0
self.physicsBody!.restitution = 1
self.physicsBody!.categoryBitMask = CollisionTypes.Floor.rawValue
self.physicsBody!.contactTestBitMask = CollisionTypes.Ball.rawValue
// Prepare the ball - physics engine.
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.width/2)
ball.physicsBody!.affectedByGravity = true
ball.physicsBody!.restitution = 0.8
ball.physicsBody!.linearDamping = 0
ball.physicsBody!.friction = 0.3
ball.physicsBody!.dynamic = true
ball.physicsBody!.mass = 0.5
ball.physicsBody!.allowsRotation = true
ball.physicsBody!.categoryBitMask = CollisionTypes.Ball.rawValue
ball.physicsBody!.contactTestBitMask = CollisionTypes.Floor.rawValue
ball.physicsBody!.collisionBitMask = CollisionTypes.Floor.rawValue
ball.hidden = false
self.addChild(ball)
// scene
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody!.categoryBitMask = CollideType.Scene.toMask()
self.physicsBody!.dynamic = false
self.physicsBody!.friction = 0
// ceil
let ceil = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
ceil.position.x = CGRectGetMidX(self.frame)
ceil.position.y = self.frame.height - CGRectGetMidY(ceil.frame)
ceil.physicsBody = SKPhysicsBody(rectangleOfSize: ceil.frame.size)
ceil.physicsBody!.categoryBitMask = CollideType.Ceil.toMask()
ceil.physicsBody!.dynamic = false
ceil.alpha = 0
self.addChild(ceil)
// floor
let floor = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 2))
floor.position.x = CGRectGetMidX(self.frame)
floor.position.y = CGRectGetMidY(floor.frame)
floor.physicsBody = SKPhysicsBody(rectangleOfSize: floor.frame.size)
//floor.physicsBody!.categoryBitMask = CollideType.Floor.toMask() two
floor.physicsBody!.dynamic = false
floor.alpha = 0
self.addChild(floor)
}
That is the scene and physics I attempted to set up and was directed with. Below is the collide errors which cause the app to crash upon touch.
func didBeginContact(contact: SKPhysicsContact) {
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board error: CANNOT CONVERT VALUE OF TYPE BOOL TO EXPCTD ARG TYPE UIINT32
if bitMaskAAndB | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didBeginContact(boardNode, ball: ball, contact: contact, game: self)
}
// ball and ceil => ERROR
else if bitMaskAAndB == CollideType.toMask([.Ball, .Ceil]) {
stopGame()
}
// ball and floor => stop game
else if bitMaskAAndB == CollideType.toMask([.Ball, .Floor]) {
stopGame()
}
}
func didEndContact(contact: SKPhysicsContact) {
let ballAndBoardMask = CollideType.Ball.toMask() | boards.usedCollideMasks
// ball and board, handle it by board delegate
if contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask | ballAndBoardMask == ballAndBoardMask {
let boardNode: SKNode! = contact.bodyA.categoryBitMask == CollideType.Ball.toMask() ? contact.bodyB.node : contact.bodyA.node
let board = boardNode.bind as! BoardDelegate
board.didEndContact(boardNode, ball: ball, contact: contact, game: self)
}
}
CollideType definition as below:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
So the issue now is that you have two definition for your masks:
Remove this one:
enum CollisionTypes: UInt32 {
case Floor = 1
case Ball = 2
}
Use only this one:
enum CollideType: Int {
case Scene = 0
case Ceil = 1
case Floor = 2
case Ball = 3
case BoardStart = 4
func toMask()-> UInt32 {
return UInt32(1 << self.rawValue)
}
static func toMask(masks: [CollideType])-> UInt32 {
var toMask = UInt32(0)
for type in masks {
toMask |= type.toMask()
}
return toMask
}
Correct all code to match with CollideType definitions.
Correct this line in didBeginContact:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollisionTypes.Floor.rawValue && contact.bodyB.categoryBitMask == CollisionTypes.Ball.rawValue
with:
let bitMaskAAndB = contact.bodyA.categoryBitMask == CollideType.Floor.toMask() ? contact.bodyB.categoryBitMask : CollideType.Ball.toMask()
If you have correct all you will don't have yet this error:
// ball and ceil => ERROR

fatal error: unexpectedly found nil while unwrapping an Optional value for physics body contact

I can't seem to figure out which optional value it is talking about or why i am getting this error. I checked my score integer and made sure that I declared its value is 0 until it makes contact with the enemy. In the simulator the counter counts the first 4 or 5 enemies then crashes.
var score = Int? ()
var scoreLabel = UILabel ()
override func didMoveToView(view: SKView) {
scoreLabel.text = "\(score)"
scoreLabel = UILabel(frame: CGRect(x: 0, y: 0, width: 100, height:
20))
scoreLabel.textColor = UIColor.blackColor()
score = nil
if score == nil {
score = 0
scoreLabel.text = "\(score!)"
}
func didBeginContact(contact: SKPhysicsContact) {
let firstBody : SKPhysicsBody = contact.bodyA
let secondBody : SKPhysicsBody = contact.bodyB
if ((firstBody.categoryBitMask == PhysicsCategory.bullet) &&
(secondBody.categoryBitMask == PhysicsCategory.enemy) ||
(firstBody.categoryBitMask == PhysicsCategory.enemy) &&
(secondBody.categoryBitMask == PhysicsCategory.bullet)) {
//i get the error next line
collisionWithBullet((firstBody.node as! SKSpriteNode),
bullet: (secondBody.node as! SKSpriteNode))
}
}
func collisionWithBullet(enemy: SKSpriteNode, bullet: SKSpriteNode){
score? += 1
scoreLabel.text = "\(score!)"
enemy.removeFromParent ()
bullet.removeFromParent ()
}
Change score to
var score = 0
instead of
var score = Int? ()
and instead of this part
score = nil
if score == nil {
score = 0
scoreLabel.text = "\(score!)"
}
write only this
scoreLabel.text = "\(score)"
Edit:
instead of this part
collisionWithBullet((firstBody.node as! SKSpriteNode),
bullet: (secondBody.node as! SKSpriteNode))
do something like this
if let firstNode = firstBody.node as? SKSpriteNode,
secondNode = secondBody .node as? SKSpriteNode {
collisionWithBullet((firstNode),
bullet: (secondNode))
}

How to make objects exempt from SKcameranode movement

I'm currently developing a scrolling platformer game, and I was wondering how I could have the joystick object move along with the screen but still be useable. Ive tried a number of things, but none of them have produced any viable options. At the moment, the joystick is usable but will scroll off the screen with the rest of the map.
Here is my code:
import SpriteKit
import UIKit
var map = SKNode()
var idleFrames = [SKTexture]()
var walkFrames = [SKTexture]()
var idleFrames1 = [SKTexture]()
var walkFrames1 = [SKTexture]()
var attackFrames1 = [SKTexture]()
var idling = 0
var bullets = 0
var bullet = SKSpriteNode()
var leaf = SKEmitterNode()
var hud: SKSpriteNode?
class GameScene: SKScene, SKPhysicsContactDelegate {
var sp33d: CGVector = CGVectorMake(0.0,0.0)
var knock: CGVector = CGVectorMake(-10.0, 0.0)
var knock1: CGVector = CGVectorMake(10.0, 0.0)
var jsp33d: CGFloat = 170
var gameStick: Joystick?
var player: SKSpriteNode?
var ground: SKSpriteNode?
var ground2: SKSpriteNode?
var ground3: SKSpriteNode?
var canJump = false
var specialbutton = SKSpriteNode(imageNamed: "special")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
hud = self.childNodeWithName("hud") as? SKSpriteNode
gameStick = Joystick()
gameStick?.createJoystick(hud!.frame.width/4, nameBack: "joystick", nameMoving: "joystick1")
gameStick!.backPart!.zPosition = 4
gameStick!.movingPart!.zPosition = 5
map.addChild(gameStick!.backPart!)
map.addChild(gameStick!.movingPart!)
self.addChild(map)
player = self.childNodeWithName("player") as? SKSpriteNode
ground = self.childNodeWithName("testGround") as? SKSpriteNode
ground2 = self.childNodeWithName("testGround2") as? SKSpriteNode
player?.physicsBody?.categoryBitMask = category.player
ground?.physicsBody?.categoryBitMask = category.ground
ground2?.physicsBody?.categoryBitMask = category.ground
player?.physicsBody?.collisionBitMask = category.ground
ground?.physicsBody?.collisionBitMask = category.player
player!.position = CGPoint(x: CGRectGetMidX(self.frame), y: 70)
specialbutton.position = CGPointMake(600, 83)
specialbutton.xScale = 0.165
specialbutton.yScale = 0.165
specialbutton.alpha = 0.5
map.addChild(specialbutton)
camera = self.childNodeWithName("camera") as? SKCameraNode
camera?.position = player!.position
if charnumber == 2{
player?.texture = SKTexture(imageNamed:"Sarah")
}
let idleAtlas = SKTextureAtlas(named: "idle.atlas")
var idleframes = [SKTexture]()
for var i=1; i<=4; i++ {
let idleframe = "JohnIdle\(i)"
idleframes.append(idleAtlas.textureNamed(idleframe))
}
idleFrames = idleframes
let walkAtlas = SKTextureAtlas(named: "jrun.atlas")
var walkframes = [SKTexture]()
for var i=1; i<=8; i++ {
let walkframe = "Johnrun\(i)"
walkframes.append(walkAtlas.textureNamed(walkframe))
}
walkFrames = walkframes
let idleAtlas1 = SKTextureAtlas(named: "Sarahidle.atlas")
var idleframes1 = [SKTexture]()
for var i=1; i<=4; i++ {
let idleframe1 = "SarahIdle\(i)"
idleframes1.append(idleAtlas1.textureNamed(idleframe1))
}
idleFrames1 = idleframes1
let walkAtlas1 = SKTextureAtlas(named: "Sarahrun.atlas")
var walkframes1 = [SKTexture]()
for var i=1; i<=8; i++ {
let walkframe1 = "Sarahrun\(i)"
walkframes1.append(walkAtlas1.textureNamed(walkframe1))
}
walkFrames1 = walkframes1
let attackAtlas1 = SKTextureAtlas(named: "sattack.atlas")
var attackframes1 = [SKTexture]()
for var i=1; i<=9; i++ {
let attackframe1 = "sattack\(i)"
attackframes1.append(attackAtlas1.textureNamed(attackframe1))
}
attackFrames1 = attackframes1
self.physicsWorld.gravity = CGVectorMake(0, -10.0)
self.physicsWorld.contactDelegate = self
}
func didBeginContact(contact:SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == category.player) && (contact.bodyB.categoryBitMask == category.ground) {
idling = 0
johnmove()
print("hit")
canJump = true
}else{
}
}
func didEndContact(contact: SKPhysicsContact) {
if (contact.bodyA.categoryBitMask == category.player) && (contact.bodyB.categoryBitMask == category.ground) {
canJump = false
}
}
func bulletfire(){
bullet = SKSpriteNode(imageNamed: "bullet1")
leaf = SKEmitterNode(fileNamed: "leafParticle")!
bullets = bullets + 1
bullet.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(0.1, 0.1))
bullet.physicsBody?.collisionBitMask = category.ground
bullet.xScale = 0.016
bullet.yScale = 0.016
bullet.physicsBody?.affectedByGravity = false
self.addChild(bullet)
self.addChild(leaf)
if player?.xScale == 1{
bullet.xScale = -0.016
bullet.position.x = (player?.position.x)! + 21.5
bullet.position.y = (player?.position.y)! + 15.4
bullet.physicsBody?.velocity = (CGVectorMake(1000.0, 0.0))
}else{
bullet.position.x = (player?.position.x)! - 21.5
bullet.position.y = (player?.position.y)! + 15.4
bullet.physicsBody?.velocity = (CGVectorMake(-1000.0, 0.0))
}
let action = SKAction.sequence([SKAction.waitForDuration(1), SKAction.removeFromParent()])
bullet.runAction(action, completion: {bullets = bullets - 1})
leaf.runAction(action)
}
func move(){
if player?.xScale == 1 {
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! - 20
}else{
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! + 20
}
}
func johnmove() {
if charnumber == 1 {
if idling == 1 {
player?.size = CGSizeMake(80,80)
player?.removeActionForKey("idle")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(walkFrames, timePerFrame: 0.12, resize: false, restore: true)),withKey: "walk")
}
else if idling == 0 {
player?.removeActionForKey("walk")
player?.size = CGSizeMake(80,80)
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(idleFrames, timePerFrame: 0.6, resize: false, restore: true)),withKey: "idle")
}else if idling == 2 {
player?.removeActionForKey("walk")
player?.removeActionForKey("idle")
player?.size = CGSizeMake(80,80)
player?.texture = SKTexture(imageNamed: "JohnJump.png")
}
}else{
sarahhmove()
}
}
func sarahhmove() {
if idling == 1 {
player?.removeActionForKey("idle1")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(walkFrames1, timePerFrame: 0.12, resize: true, restore: true)),withKey: "walk1")
}
else if idling == 0 {
player?.removeActionForKey("walk1")
player?.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(idleFrames1, timePerFrame: 0.6, resize: false, restore: true)),withKey: "idle1")
}else if idling == 2 {
player?.removeActionForKey("wal1k")
player?.removeActionForKey("idle1")
player?.texture = SKTexture(imageNamed: "SarahJump.png")
}
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
gameStick?.movingPart?.position = location
if location.x > gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2, gameStick!.movingPart!.position.y)
}
if location.y > gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.movingPart!.position.x, gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2)
}
}
}
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
gameStick?.movingPart?.position = location
if location.x > gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.backPart!.position.x + gameStick!.backPart!.frame.width/2, gameStick!.movingPart!.position.y)
}
if location.y > gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2{
gameStick?.movingPart?.position = CGPointMake(gameStick!.movingPart!.position.x, gameStick!.backPart!.position.y + gameStick!.backPart!.frame.height/2)
}
}else if idling == 0 && charnumber == 2{
player?.size = CGSizeMake(80,80)
player?.removeAllActions()
if player?.xScale == 1 {
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! + 20
}else{
player?.size = CGSizeMake(80,80)
player?.position.x = (player?.position.x)! - 20
}
player?.size = CGSizeMake(80,80)
player?.runAction(SKAction.repeatAction(SKAction.animateWithTextures(attackFrames1, timePerFrame: 0.09, resize: true, restore: true),count: 1),completion: {self.move()})
player?.size = CGSizeMake(80,80)
player?.texture = SKTexture(imageNamed: "Sarah")
}else if charnumber == 1 && idling == 0{
player?.removeAllActions()
bulletfire()
let yrand = (arc4random_uniform(100) + 50)
let xrand = (arc4random_uniform(300) + 80)
let cartridge = SKSpriteNode(imageNamed: "casing")
cartridge.physicsBody = SKPhysicsBody(rectangleOfSize: CGSizeMake(0.1, 0.1))
cartridge.physicsBody?.collisionBitMask = category.ground
cartridge.xScale = 0.05
cartridge.yScale = 0.05
cartridge.zPosition = 3
cartridge.physicsBody?.restitution = 0.5
let spin = SKAction.rotateByAngle(CGFloat(M_PI), duration:0.6)
cartridge.runAction(SKAction.repeatActionForever(spin))
cartridge.physicsBody?.dynamic = true
let flash = SKEmitterNode(fileNamed: "muzzleFlash")
if player?.xScale == 1{
leaf.xScale = -1
flash?.position.x = (player?.position.x)! + 40
flash?.position.y = (player?.position.y)! + 15.3
cartridge.position.x = (player?.position.x)! + 27
cartridge.position.y = (player?.position.y)! + 15.3
player?.physicsBody?.applyImpulse(knock)
cartridge.physicsBody?.velocity = CGVectorMake(-CGFloat(yrand), CGFloat(xrand))
}else{
flash?.position.x = (player?.position.x)! - 40
flash?.position.y = (player?.position.y)! + 15.3
flash?.xAcceleration = -5000
cartridge.position.x = (player?.position.x)! - 27
cartridge.position.y = (player?.position.y)! + 15.3
player?.physicsBody?.applyImpulse(knock1)
cartridge.physicsBody?.velocity = CGVectorMake(CGFloat(yrand), CGFloat(xrand))
}
flash?.zPosition = 3
flash?.xScale = 0.15
flash?.yScale = 0.15
self.addChild(flash!)
self.addChild(cartridge)
let action = SKAction.sequence([SKAction.waitForDuration(0.15), SKAction.removeFromParent()])
let action1 = SKAction.sequence([SKAction.waitForDuration(1.5), SKAction.removeFromParent()])
flash?.runAction(action)
cartridge.runAction(action1)
johnmove()
}
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
var nodeTouched = SKNode()
nodeTouched = self.nodeAtPoint(location)
if nodeTouched.name == "joystick1" {
let act = SKAction.moveTo(gameStick!.backPart!.position, duration: 0.2)
gameStick?.movingPart?.runAction(act)
}
}
}
override func update(currentTime: CFTimeInterval) {
hud!.position = (camera?.position)!
let action = SKAction.moveTo((player?.position)!, duration: 0.01)
camera!.runAction(action)
player?.size = CGSizeMake(80,80)
leaf.position = bullet.position
print(canJump)
if (sp33d.dx > 1.5 || sp33d.dx < -1.5) && idling != 1 && idling != 2 {
idling = 1
johnmove()
}else if sp33d.dx < 0.1 && sp33d.dx > -0.1 && idling != 0 && idling != 2{
idling = 0
johnmove()
}
if sp33d.dx > 0.1 {
player!.xScale = 1
} else if sp33d.dx < -0.1 {
player!.xScale = -1
}
/* Called before each frame is rendered */
let vX = gameStick!.movingPart!.position.x - gameStick!.backPart!.position.x
let vY: CGFloat = gameStick!.movingPart!.position.y
if vY > gameStick!.backPart!.position.y + 20 && canJump == true{
sp33d = CGVectorMake(vX/13, jsp33d)
idling = 2
johnmove()
}else{
sp33d = CGVectorMake(vX/13, 0)
}
player?.physicsBody?.applyImpulse(sp33d)
}
}
This is the class in which the joystick is created:
import Foundation
import UIKit
import SpriteKit
class Joystick: UIView {
var movingPart: SKSpriteNode?
var backPart: SKSpriteNode?
let speed: CGFloat = 0.4
var joyStickCenter: CGPoint?
func createJoystick(dimensions: CGFloat, nameBack: String, nameMoving: String)
{
backPart = SKSpriteNode(imageNamed: "joystick")
backPart?.size = CGSizeMake(dimensions, dimensions)
backPart?.position = CGPoint(x: backPart!.size.width/2, y: backPart!.size.width/2)
backPart?.name = nameBack
backPart?.alpha = 0.4
movingPart = SKSpriteNode(imageNamed: "joystick")
movingPart?.size = CGSizeMake(dimensions*0.5, dimensions*0.5)
movingPart?.position = backPart!.position
movingPart?.name = nameMoving
movingPart?.alpha = 0.8
joyStickCenter = backPart!.position
}
func getDistance(p1: CGPoint, p2: CGPoint) -> Double
{
let firstPow = p2.x-p1.x
let secondPow = p2.y-p1.y
var squaredAdded = pow(firstPow, 2)
squaredAdded += pow(secondPow, 2)
let theSquirt = sqrt(Double(squaredAdded))
return theSquirt
}
func resetMovingPart()
{
movingPart?.runAction(SKAction.moveTo(joyStickCenter!, duration: 0.4))
}
func calcXYDiff(loc: CGPoint) -> CGPoint
{
let oldMovingPartPoint = movingPart?.position
movingPart?.position = loc
if movingPart!.position.x-joyStickCenter!.x > backPart!.frame.width/2
{
movingPart?.position.x = oldMovingPartPoint!.x
}
if movingPart!.position.y-joyStickCenter!.y > backPart!.frame.height/2
{
movingPart?.position.y = oldMovingPartPoint!.y
}
let x = loc.x - joyStickCenter!.x
let y = loc.y - joyStickCenter!.y
return CGPoint(x: x*speed, y: y*speed)
}
Any help would be greaty appreciated.
Thanks in advance!
Try calling the resetMovingPart() in your update() func.

How may i detect contact and collision correctly? Swift iOS SKScene

The problem is i can't detect the collision //or contact in any way i have found on the internet
This is my code:
The declaration of my masks:
private let ballCategory : UInt32 = 0x1 << 0
private let holeCategory : UInt32 = 0x1 << 1
The adding of both the hole and the ball:
func addHole(#size : CGSize) {
let actionMoveDown = SKAction.moveToY(CGRectGetMidY(self.frame)-500, duration: 4.7)
let hole = shapedHoles()
let UT = UTIL()
var position:CGFloat
let randomPosition = UT.randomNumberWith(Min: 1, Max: 3)
switch randomPosition{
case 1:
position = CGRectGetMidX(self.frame)
case 2:
position = CGRectGetMidX(self.frame)+size.width
default:
position = CGRectGetMidX(self.frame)-(size.width)
}
var createdHole = hole.createHoleAtPosition(position: CGPointMake(position ,CGRectGetMaxY(self.frame) + (size.height/2)),size: size )//CGSizeMake(CGRectGetMaxX(self.frame)/3 - 10, 70)
createdHole.physicsBody = SKPhysicsBody(rectangleOfSize: createdHole.frame.size)
createdHole.physicsBody?.categoryBitMask = holeCategory
createdHole.physicsBody?.collisionBitMask = 0
createdHole.physicsBody?.contactTestBitMask = ballCategory
createdHole.physicsBody?.affectedByGravity = false
createdHole.physicsBody?.dynamic = false
lastHolePosition = randomPosition
createdHole .runAction(actionMoveDown)
self.addChild(createdHole)
}
func addSphere(){
let mainCharacterController = circle()
let character: (SKNode) = mainCharacterController.createCircleAtPosition(position: CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame)+100))
character.physicsBody = SKPhysicsBody(circleOfRadius: character.frame.size.height/2)
character.physicsBody?.categoryBitMask = ballCategory
character.physicsBody?.collisionBitMask = 0
character.physicsBody?.contactTestBitMask = holeCategory
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
self.addChild(character)
} func addHole(#size : CGSize) {
let actionMoveDown = SKAction.moveToY(CGRectGetMidY(self.frame)-500, duration: 4.7)
let hole = shapedHoles()
let UT = UTIL()
var position:CGFloat
let randomPosition = UT.randomNumberWith(Min: 1, Max: 3)
switch randomPosition{
case 1:
position = CGRectGetMidX(self.frame)
case 2:
position = CGRectGetMidX(self.frame)+size.width
default:
position = CGRectGetMidX(self.frame)-(size.width)
}
var createdHole = hole.createHoleAtPosition(position: CGPointMake(position ,CGRectGetMaxY(self.frame) + (size.height/2)),size: size )//CGSizeMake(CGRectGetMaxX(self.frame)/3 - 10, 70)
createdHole.physicsBody = SKPhysicsBody(rectangleOfSize: createdHole.frame.size)
createdHole.physicsBody?.categoryBitMask = holeCategory
createdHole.physicsBody?.collisionBitMask = 0
createdHole.physicsBody?.contactTestBitMask = ballCategory
createdHole.physicsBody?.affectedByGravity = false
createdHole.physicsBody?.dynamic = false
lastHolePosition = randomPosition
createdHole .runAction(actionMoveDown)
self.addChild(createdHole)
}
func addSphere(){
let mainCharacterController = circle()
let character: (SKNode) = mainCharacterController.createCircleAtPosition(position: CGPointMake(CGRectGetMidX(self.frame), CGRectGetMinY(self.frame)+100))
character.physicsBody = SKPhysicsBody(circleOfRadius: character.frame.size.height/2)
character.physicsBody?.categoryBitMask = ballCategory
character.physicsBody?.collisionBitMask = 0
character.physicsBody?.contactTestBitMask = holeCategory
character.physicsBody?.affectedByGravity = false
character.physicsBody?.dynamic = false
self.addChild(character)
}
And last but not least the didBeginContactMethod
func didBeginContact(contact: SKPhysicsContact) {
var firstBody: SKPhysicsBody!
var secondBody: SKPhysicsBody!
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
firstBody = contact.bodyA
secondBody = contact.bodyB
}
else {
firstBody = contact.bodyB
secondBody = contact.bodyA
}
if (firstBody.categoryBitMask & holeCategory) != 0 &&
(secondBody.categoryBitMask & ballCategory) != 0 {
println("HO")
}
}
Thank you and hope you know what is happening, and if you need any extra code just comment it
You have to make sure that the SKScene subclass you are using also implements the SKPhysicsContactDelegate protocol. For example, it would look like this.
class MyScene : SKScene, SKPhysicsContactDelegate
Then you have to set your physics worlds contact delegate to yourself.
override init() {
self.physicsWorld.contactDelegate = self;
}
Tell me how this works out, but it should solve the problem and successfully allow you to listen in on collisions.
There is a couple things it might be. First you can try using an enum for the contact categories.
enum collisionBodies:UInt32 {
case ballCategory = 1
case holeCategory = 2
}
func Collisions() {
character.physicsBody.categoryBitMask = collisionBodies.ballCategory.rawValue
character.physicsBody.contactTestBitMask = collisionBodies.holeCategory.rawValue
character.physicsBody.collisionBitMask = 0
createdHole.physicsBody.categoryBitMask = collisionBodies.holeCategory.rawValue
createdHole.physicsBody.contactTestBitMask = collisionBodies.ballCategory.rawValue
createdHole.physicsBody.collisionBitMask = 0
}
Also try setting one of your physics bodies to dynamic = true or collisions will likely not work.
A better way to test for collisions in the didBeginContact function is to use a switch statement.
func didBeginContact(contact: SKPhysicsContact) {
let categoryMask = contact.BodyA.categoryBitMask | contact.BodyB.categoryBitMask
switch (categoryMask) {
case collisionBodies.holeCategory.rawValue | collisionBodies.ballCategory.rawValue:
//code to run when contact is detected
default:
return
}
}

Resources