As sprite moves up, more jump pads appear on screen - ios

I am trying to make a Doodle Jump-like game. I want to make it so that as a sprite, my main character, moves above a certain Y point, more pads to jump on appear, giving it the illusion that it is jumping higher and higher.
How would I go about coding this? Any examples would be nice. I am using SpriteKit in Xcode 7.
Here is my code so far:
import SpriteKit
import Foundation
class GameScene: SKScene {
var mainSprite = SKSpriteNode()
var wallPair = SKNode()
var ground = SKSpriteNode()
var moveAndRemove = SKAction()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
mainSprite.size = CGSize(width: 30, height: 30)
mainSprite.color = SKColor.redColor();
mainSprite.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 - 100)
self.addChild(mainSprite)
ground.size = CGSize(width: self.frame.width, height: 300)
ground.color = SKColor.brownColor()
ground.position = CGPoint(x: self.frame.width / 2, y: 0)
self.addChild(ground)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
createWallMap()
for touch in touches {
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
func createWalls(height: CGFloat) {
wallPair = SKNode()
wallPair.name = "wallPair"
let rightWall = SKSpriteNode(imageNamed: "LeftWall.png") // I know it is opposite. Named the image wrong
let leftWall = SKSpriteNode(imageNamed: "RightWall.png")
rightWall.setScale(0.9)
leftWall.setScale(0.9)
rightWall.color = SKColor.redColor()
leftWall.color = SKColor.blueColor()
rightWall.position = CGPoint(x: self.frame.width / 2 + 340, y: height)
leftWall.position = CGPoint(x: self.frame.width / 2 - 340, y: height)
wallPair.addChild(rightWall)
wallPair.addChild(leftWall)
let randomPosition = CGFloat.random(min: -140, max: 140)
wallPair.position.x = wallPair.position.x + randomPosition
//wallPair.runAction(moveAndRemove)
self.addChild(wallPair)
}

Related

How can I alter my code to make my sprite, which rotates in a circular orbit, jump up then back down when a user taps the screen?

I'm trying to make my orange circle sprite, which orbits in a circular motion, jump at ant point in its rotation and fall back down again when the user taps the screen but can't seem to figure out what I'm doing wrong. Please help.
I've tried taking the advice to somewhat similar post o here but have had no luck.
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed: "circle")
let player = SKSpriteNode(imageNamed: "player")
var node2AngularDistance: CGFloat = 0
override func didMove(to view: SKView) {
backgroundColor = SKColor(red: 94.0/255, green: 63.0/255, blue: 107.0/255, alpha: 1)
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
sprite.size = CGSize(width: 150, height: 150)
sprite.position = CGPoint(x: 0,y: 0)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 10)
player.size = CGSize(width: 100, height: 100)
player.position = CGPoint(x: 0+50, y: 0)
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
self.addChild(sprite)
self.addChild(player)
}
//dont touch blue lines that discard code and don't allow you to undo
override func update(_ currentTime: TimeInterval) {
let dt: CGFloat = 1.0/60.0 //Delta Time
let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit.
let orbitPosition = sprite.position //Point to orbit.
let orbitRadius = CGPoint(x: 150, y: 150) //Radius of orbit.
let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.node2AngularDistance))*orbitRadius.x ,dy:orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y);
self.node2AngularDistance += (CGFloat(Double.pi)*2.0)/period*dt;
if (abs(self.node2AngularDistance)>CGFloat(Double.pi)*2) {
self.node2AngularDistance = 0
}
player.physicsBody!.velocity = CGVector(dx:(normal.dx-player.position.x)/dt ,dy:(normal.dy-player.position.y)/dt);
//func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
//sprite.position = (touches.first! as! UITouch).location(in: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
func jump() {
player.texture = SKTexture(imageNamed: "player")
player.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 500))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
player.texture = SKTexture(imageNamed: "player")
}
}
The expected results would be a small circle sprite called player that rotates in circular orbit around a larger circle called sprite and when the user taps the screen, the player(small circle) would jump up then back down at any point in its orbit.The actual results are the the circle rotates around the larger circle but does not jump up when I click on the screen in the iPhone simulator.
A jumpping state needs to record as : isJumpping. If isJumpping, the update will not perform, if this is what you need.
The second issue is after touching up, the player falls back to the orbital. A simple math is given here as the player directly falling to the circle.
But if the situation is complicated, you may consider to use PhysicsField to simulate the situation.
This is running in a Xcode 10 and playground
import UIKit
import PlaygroundSupport
import SpriteKit
import simd
class GameScene: SKScene {
let sprite = SKSpriteNode(imageNamed: "circle")
let player = SKSpriteNode(imageNamed: "player")
var node2AngularDistance: CGFloat = 0
override func didMove(to view: SKView) {
print(100)
// backgroundColor = SKColor(red: 94.0/255, green: 63.0/255, blue: 107.0/255, alpha: 1)
backgroundColor = SKColor.black
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
sprite.size = CGSize(width: 150, height: 150)
sprite.position = CGPoint(x: 0,y: 0)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 10)
player.size = CGSize(width: 100, height: 100)
player.position = CGPoint(x: 0+50, y: 0)
player.physicsBody = SKPhysicsBody(circleOfRadius: 10)
self.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
self.addChild(sprite)
self.addChild(player)
}
//dont touch blue lines that discard code and don't allow you to undo
override func update(_ currentTime: TimeInterval) {
guard !isJumpping else {
return
}
let dt: CGFloat = 1.0/60.0 //Delta Time
let period: CGFloat = 3 //Number of seconds it takes to complete 1 orbit.
let orbitPosition = sprite.position //Point to orbit.
let orbitRadius = CGPoint(x: 150, y: 150) //Radius of orbit.
let currentDistance = distance(double2(x: Double(orbitPosition.x), y: Double(orbitPosition.y)), double2(x: Double(player.position.x), y: Double(player.position.y)))
if ( currentDistance > 150){
player.physicsBody!.velocity = CGVector(dx:(orbitPosition.x - player.position.x) ,dy:(orbitPosition.y - player.position.y));
let x = Double(player.position.x) - Double(orbitPosition.x)
let y = Double(player.position.y) - Double(orbitPosition.y)
self.node2AngularDistance = CGFloat(acos(x/currentDistance))
if y < 0 {
self.node2AngularDistance = 2 * CGFloat.pi - self.node2AngularDistance }
return;
}
let normal = CGVector(dx:orbitPosition.x + CGFloat(cos(self.node2AngularDistance))*orbitRadius.x ,dy:orbitPosition.y + CGFloat(sin(self.node2AngularDistance))*orbitRadius.y);
self.node2AngularDistance += (CGFloat(Double.pi)*2.0)/period*dt;
if (abs(self.node2AngularDistance)>CGFloat(Double.pi)*2) {
self.node2AngularDistance = 0
}
player.physicsBody!.velocity = CGVector(dx:(normal.dx-player.position.x)/dt ,dy:(normal.dy-player.position.y)/dt);
//func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
//sprite.position = (touches.first! as! UITouch).location(in: self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
private var isJumpping : Bool = false
func jump() {
isJumpping.toggle()
player.texture = SKTexture(imageNamed: "player")
player.physicsBody?.applyImpulse(CGVector(dx: (self.player.position.x - self.sprite.position.x) / 100.0, dy: (self.player.position.y - self.sprite.position.y) / 100.0))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
isJumpping.toggle()
player.texture = SKTexture(imageNamed: "player")
}
}
class GameViewCointroller: UIViewController{
var skview: SKView!
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
skview = SKView.init(frame: view.bounds)
let scene = GameScene.init(size: view.frame.size)
skview.presentScene(scene)
view.addSubview(skview)
}
}
PlaygroundPage.current.liveView = GameViewCointroller()

Trouble converting between coordinate spaces in SpriteKit

I am trying to get a SKShapeNode to follow a UITouch
My problem is that the location of the UITouch is relative to the bottom-left corner of the screen and the position of the SKShapeNode is relative to the location I gave it when I created it, the center of the screen.
For example: ball is centered at (189.0, 335.0), the center of the view. I click the ball, the location of the touch tells me the touch event occurred at (189.0, 335.0), but the ball.position will tell me (0.0, 0.0). How can I get the ball's position in the view's coordinate system?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var touched = false
var location = CGPoint.zero
var ball: SKShapeNode = SKShapeNode(circleOfRadius: 15)
var background: SKSpriteNode = SKSpriteNode(imageNamed: "background")
override func didMove(to view: SKView) {
background.size = frame.size
background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
addChild(background)
let path = CGMutablePath()
path.addArc(center: CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: false)
ball = SKShapeNode(path: path) // Added to center of screen
ball.lineWidth = 1
ball.fillColor = .cyan
ball.strokeColor = .cyan
ball.glowWidth = 0.5
addChild(ball)
print(ball.position)
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
moveNode()
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
touched = true
for touch in touches {
location = touch.location(in: view)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
location = touch.location(in: view)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touched = false
}
func moveNode() {
if touched {
let speed: CGFloat = 1
if location.x < ball.position.x {
let newLocation = ball.position.x - speed
ball.position = CGPoint(x: newLocation, y: ball.position.y)
} else {
let newLocation = ball.position.x + speed
ball.position = CGPoint(x: newLocation, y: ball.position.y)
}
}
}
}
You never set the ball position so it is (0,0). The problem is that the ball is at (0,0) but its path represents something at (189,335) in ball coordinates.
Change to:
override func didMove(to view: SKView) {
background.size = frame.size
background.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
addChild(background)
let path = CGMutablePath()
// construct a path relative to center of the ball
path.addArc(center: CGPoint(x: 0, y: 0),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: false)
ball = SKShapeNode(path: path)
// locate the ball at the center of the screen
ball.position = CGPoint(x: view.frame.size.width / 2, y: view.frame.size.height / 2)
ball.lineWidth = 1
ball.fillColor = .cyan
ball.strokeColor = .cyan
ball.glowWidth = 0.5
addChild(ball)
print(ball.position)
}

My nodes aren't colliding

class GameScene: SKScene, SKPhysicsContactDelegate {
let balls = [
SKSpriteNode(imageNamed: "blueball.png"),
SKSpriteNode(imageNamed: "greenball.png"),
SKSpriteNode(imageNamed: "realredball.png")
]
let redRectangle = SKSpriteNode(imageNamed: "redrectangle.png")
let blueRectangle = SKSpriteNode(imageNamed: "bluerectangle.png")
let greenRectangle = SKSpriteNode(imageNamed: "greenrectangle.png")
override func didMove(to view: SKView) {
spawnBalls()
rectangles()
physicsWorld.contactDelegate = self
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for ball in balls{
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.affectedByGravity = true
}
}
func spawnBalls() {
let ball = balls[Int(arc4random_uniform(UInt32(balls.count)))]
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.affectedByGravity = false
ball.position = CGPoint(x: 0, y: 250)
ball.size = CGSize(width: 70, height: 70)
ball.physicsBody?.categoryBitMask = 0
ball.physicsBody?.collisionBitMask = 1
self.addChild(ball)
}
func rectangles() {
redRectangle.position = CGPoint(x: -316.5, y: -657)
redRectangle.size = CGSize(width: 400, height: 20)
redRectangle.physicsBody = SKPhysicsBody()
redRectangle.physicsBody?.categoryBitMask = 1
redRectangle.physicsBody?.collisionBitMask = 0
blueRectangle.size = CGSize(width: 400, height: 20)
blueRectangle.position = CGPoint(x: -100, y: -657)
blueRectangle.physicsBody = SKPhysicsBody()
greenRectangle.position = CGPoint(x: 0, y: -657)
greenRectangle.size = CGSize(width: 400, height: 20)
greenRectangle.physicsBody = SKPhysicsBody()
self.addChild(redRectangle)
self.addChild(blueRectangle)
self.addChild(greenRectangle)
}
}
I want the balls to drop down and make contact with the rectangle nodes, although it looks like the balls are just going through them. I used collision and category bitmask. I'm wondering if someone could help fix this problem, thanks.
You initialise the balls correctly, but remove their physics body by creating a new one inside touchesBegan(_:). Just remove this line from the touchesBegan(_:) function:
ball.physicsBody = SKPhysicsBody()

Why won't anything show up in my Swift Playground?

I have a pong game in a Swift Playground that I made by following a tutorial online but my assistant editor won't show anything! Where is my pong game!? My code is below the image, which shows that nothing is showing up.
import SpriteKit
import PlaygroundSupport
// Declare some global constants
let width = 800 as CGFloat
let height = 1200 as CGFloat
let racketHeight = 150 as CGFloat
let ballRadius = 20 as CGFloat
// Three types of collision objects possible
enum CollisionTypes: UInt32 {
case Ball = 1
case Wall = 2
case Racket = 4
}
// Racket direction
enum Direction: Int {
case None = 0
case Up = 1
case Down = 2
}
// Make a SpriteKit scene
class gameScene: SKScene, SKPhysicsContactDelegate {
let racketSpeed = 500.0
var direction = Direction.None
var score = 0
var gameRunning = false
// Screen elements
var racket: SKShapeNode?
var ball: SKShapeNode?
let scoreLabel = SKLabelNode()
// Initialize objects during first start
override func sceneDidLoad() {
super.sceneDidLoad()
scoreLabel.fontSize = 40
scoreLabel.position = CGPoint(x: width/2, y: height - 100)
self.addChild(scoreLabel)
createWalls()
createBall(position: CGPoint(x: width / 2, y: height / 2))
createRacket()
startNewGame()
self.physicsWorld.contactDelegate = self
}
// Create the ball sprite
func createBall(position: CGPoint) {
let physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)
ball = SKShapeNode(circleOfRadius: ballRadius)
physicsBody.categoryBitMask = CollisionTypes.Ball.rawValue
physicsBody.collisionBitMask = CollisionTypes.Wall.rawValue | CollisionTypes.Ball.rawValue | CollisionTypes.Racket.rawValue
physicsBody.affectedByGravity = false
physicsBody.restitution = 1
physicsBody.linearDamping = 0
physicsBody.velocity = CGVector(dx: -500, dy: 500)
ball!.physicsBody = physicsBody
ball!.position = position
ball!.fillColor = SKColor.white
}
// Create the walls
func createWalls() {
createWall(rect: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: ballRadius, height: height)))
createWall(rect: CGRect(origin: CGPoint(x: 0, y: 0), size: CGSize(width: width, height: ballRadius)))
createWall(rect: CGRect(origin: CGPoint(x: 0, y: height - ballRadius), size: CGSize(width: width, height: ballRadius)))
}
func createWall(rect: CGRect) {
let node = SKShapeNode(rect: rect)
node.fillColor = SKColor.white
node.physicsBody = getWallPhysicsbody(rect: rect)
self.addChild(node)
}
// Create the physics objetcs to handle wall collisions
func getWallPhysicsbody(rect: CGRect) -> SKPhysicsBody {
let physicsBody = SKPhysicsBody(rectangleOf: rect.size, center: CGPoint(x: rect.midX, y: rect.midY))
physicsBody.affectedByGravity = false
physicsBody.isDynamic = false
physicsBody.collisionBitMask = CollisionTypes.Ball.rawValue
physicsBody.categoryBitMask = CollisionTypes.Wall.rawValue
return physicsBody
}
// Create the racket sprite
func createRacket() {
racket = SKShapeNode(rect: CGRect(origin: CGPoint.zero, size: CGSize(width: ballRadius, height: racketHeight)))
self.addChild(racket!)
racket!.fillColor = SKColor.white
let physicsBody = SKPhysicsBody(rectangleOf: racket!.frame.size, center: CGPoint(x: racket!.frame.midX, y: racket!.frame.midY))
physicsBody.affectedByGravity = false
physicsBody.isDynamic = false
physicsBody.collisionBitMask = CollisionTypes.Ball.rawValue
physicsBody.categoryBitMask = CollisionTypes.Racket.rawValue
physicsBody.contactTestBitMask = CollisionTypes.Ball.rawValue
racket!.physicsBody = physicsBody
}
// Start a new game
func startNewGame() {
score = 0
scoreLabel.text = "0"
racket!.position = CGPoint(x: width - ballRadius * 2, y: height / 2)
let startLabel = SKLabelNode(text: "Game Over")
startLabel.position = CGPoint(x: width / 2, y: height / 2)
startLabel.fontSize = 160
self.addChild(startLabel)
// Animated countdown
let fadeIn = SKAction.fadeIn(withDuration: 0.5)
let fadeOut = SKAction.fadeOut(withDuration: 0.5)
startLabel.text = "3"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "2"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "1"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.text = "0"
startLabel.run(SKAction.sequence([fadeIn, fadeOut]), completion: {
startLabel.removeFromParent()
self.gameRunning = true
self.ball!.position = CGPoint(x: 30, y: height / 2)
self.addChild(self.ball!)
})
})
})
})
}
// Handle touch events to move the racket
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if location.y > height / 2 {
direction = Direction.Up
} else if location.y < height / 2{
direction = Direction.Down
}
}
}
// Stop racket movement
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
direction = Direction.None
}
// Game loop:
var dt = TimeInterval(0)
override func update(_ currentTime: TimeInterval) {
if gameRunning {
super.update(currentTime)
checkGameOver()
if dt > 0 {
moveRacket(dt: currentTime - dt)
}
dt = currentTime
}
}
// Move the racket up or down
func moveRacket(dt: TimeInterval) {
if direction == Direction.Up && racket!.position.y < height - racketHeight {
racket!.position.y = racket!.position.y + CGFloat(racketSpeed * dt)
} else if direction == Direction.Down && racket!.position.y > 0 {
racket!.position.y = racket!.position.y - CGFloat(racketSpeed * dt)
}
}
// Check if the ball is still on screen
// Game Over animation
func checkGameOver() {
if ball!.position.x > CGFloat(width) {
gameRunning = false
ball!.removeFromParent()
let gameOverLabel = SKLabelNode(text: "Game Over")
gameOverLabel.position = CGPoint(x: width / 2, y: height / 2)
gameOverLabel.fontSize = 80
self.addChild(gameOverLabel)
// Game Over animation
let rotateAction = SKAction.rotate(byAngle: CGFloat(M_PI), duration: 1)
let fadeInAction = SKAction.fadeIn(withDuration: 2)
gameOverLabel.run(SKAction.repeat(rotateAction, count: 2))
gameOverLabel.run(SKAction.scale(to: 0, duration: 2.5), completion: {
gameOverLabel.removeFromParent()
self.startNewGame()
})
}
}
// Detect collisions between ball and racket to increase the score
func didBegin(_ contact: SKPhysicsContact) {
if contact.bodyA.categoryBitMask == CollisionTypes.Racket.rawValue || contact.bodyB.categoryBitMask == CollisionTypes.Racket.rawValue {
score += 1
scoreLabel.text = String(score)
}
}
}
//Initialize the playground and start the scene:
let skView = SKView(frame: CGRect(origin: CGPoint.zero, size: CGSize(width: width, height: height)))
let scene = gameScene(size: skView.frame.size)
skView.presentScene(scene)
PlaygroundPage.current.liveView = skView
This happens to me sometimes. Playgrounds with SpriteKit just would not show anything in the Timeline view - you do have the Timeline view open, right? If you don't, tap the "Show the Assistant editor" button on the toolbar to open the Timeline view.
If you have the Timeline view open and nothing shows, try shutting down Xcode and restarting it. That generally resolves this issue for me.

Contain a sprite node within the screen/view

I have a sprite node which moves left to right with user touch.
However currently it will exit the screen, I want to add a node either side so if the sprite node touches the node on either side it hugs it and remains there until user touch to make it travel the opposite direction.
This is what I thought of doing but it isn't working currently.
let shipTexture = SKTexture(imageNamed: "ship.png")
ship = SKSpriteNode(texture: shipTexture)
ship.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
ship.zPosition = 3
ship.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 100))
ship.physicsBody!.isDynamic = true
ship.physicsBody?.collisionBitMask = 0b1
ship.physicsBody?.contactTestBitMask = 0b1
ship.physicsBody!.collisionBitMask = 0b1
ship.physicsBody?.affectedByGravity = false
self.addChild(ship)
let side = SKNode()
side.position = CGPoint(x: self.frame.width / 2, y: self.frame.midY)
side.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: -240, y: -160, width: 480, height: 320))
side.physicsBody!.isDynamic = false
side.physicsBody?.collisionBitMask = 0b1
side.physicsBody?.contactTestBitMask = 0b1
side.physicsBody!.collisionBitMask = 0b1
self.addChild(side)
func didBegin(_ contact: SKPhysicsContact) {
print("Collision")
}
}
//var moveLeft = SKAction.moveBy(x: 800, y: 0, duration: 2)
//frame.size.width
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
ship.removeAllActions()
switch direction ?? .left {
case .left:
ship.run(SKAction.moveBy(x: -frame.size.width, y: 0, duration: 3))
case .right:
ship.run(SKAction.moveBy(x: frame.size.width, y: 0, duration: 3))
}
direction = direction == nil || direction == .right ? .left : .right
}
I got it. The reason is - you use action to move your node, but should use physics - force and impulse
Try this one:
import SpriteKit
import GameplayKit
var ship = SKSpriteNode()
var bg = SKSpriteNode()
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMove(to view: SKView) {
let bgTexture = SKTexture(imageNamed: "bg.png")
let moveBGanimation = SKAction.move(by: CGVector(dx: 0, dy: -bgTexture.size().height), duration: 4)
let shiftBGAnimation = SKAction.move(by: CGVector(dx: 0, dy: bgTexture.size().height), duration: 0)
let moveBGForever = SKAction.repeatForever(SKAction.sequence([moveBGanimation, shiftBGAnimation]))
var i: CGFloat = 0
while i < 3 {
bg = SKSpriteNode(texture: bgTexture)
bg.position = CGPoint(x: self.frame.midX, y: bgTexture.size().height * i)
bg.size.width = self.frame.width
bg.run(moveBGForever)
self.addChild(bg)
i += 1
}
let shipTexture = SKTexture(imageNamed: "ship.png")
ship = SKSpriteNode(texture: shipTexture)
ship.position = CGPoint(x: self.frame.midX, y: self.frame.midY)
ship.zPosition = 3
ship.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 30, height: 100))
ship.physicsBody!.isDynamic = true
ship.physicsBody?.collisionBitMask = 0b1
ship.physicsBody?.contactTestBitMask = 0b1
ship.physicsBody!.categoryBitMask = 0b1
ship.physicsBody?.affectedByGravity = false
self.addChild(ship)
let side = SKNode()
side.position = CGPoint(x: 0, y: 0)
side.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: -self.frame.width/2, y: -self.frame.height/2, width: self.frame.width, height: self.frame.height))
side.physicsBody!.isDynamic = false
side.physicsBody?.collisionBitMask = 0b1
side.physicsBody?.contactTestBitMask = 0b1
side.physicsBody!.categoryBitMask = 0b1
self.addChild(side)
self.physicsWorld.contactDelegate = self
func didBegin(_ contact: SKPhysicsContact) {
print("Collision")
}
}
//var moveLeft = SKAction.moveBy(x: 800, y: 0, duration: 2)
//frame.size.width
enum Direction: Int {
case left = 0
case right
}
var direction: Direction?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
ship.removeAllActions()
switch direction ?? .left {
case .left:
ship.physicsBody?.applyImpulse(CGVector(dx: -20, dy: 0))
//ship.run(SKAction.moveBy(x: -frame.size.width, y: 0, duration: 3))
case .right:
ship.physicsBody?.applyImpulse(CGVector(dx: 20, dy: 0))
//ship.run(SKAction.moveBy(x: frame.size.width, y: 0, duration: 3))
}
direction = direction == nil || direction == .right ? .left : .right
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func update(_ currentTime: TimeInterval) {
}
}

Resources