spritekit + swift, change scene doesnot work good - swift

I'm new to SpriteKit, and I'm following some tutorial, but I got a problem which does not mentioned in the tutorial.
Here is what I'm gonna do, when I touch the screen each time, the scene changes from A to B, and repeat.
I have GameScene.swift and MenuScene.swift, almost the same code.
(Xcode version 7.3.1)
GameScene.swift:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
createScene()
}
func createScene() {
self.backgroundColor = SKColor.blueColor()
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.name = "label"
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPoint(x:500, y:300)
self.addChild(myLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let nextScene = MenuScene()
let doors = SKTransition.doorsOpenVerticalWithDuration(0.5)
self.view!.presentScene(nextScene, transition: doors)
}
override func update(currentTime: CFTimeInterval) {
}
}
MenuScene.swift:
import SpriteKit
class MenuScene: SKScene {
override func didMoveToView(view: SKView) {
createScene()
}
func createScene() {
self.backgroundColor = SKColor.redColor()
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.name = "label"
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPoint(x:500, y:300)
self.addChild(myLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let nextScene = GameScene()
let doors = SKTransition.doorsOpenVerticalWithDuration(0.5)
self.view!.presentScene(nextScene, transition: doors)
}
override func update(currentTime: CFTimeInterval) {
}
}
The problem is when I ran the code, it displayed the blue background and the text "hello world", which is what I expected, and I touched the screen, the background changed to red, but the text disappeared, then I touched again, the background changed back to blue, but the text is still disappeared, I could not find out why?

You need to set size of the scene and scale mode. Try this code:
import SpriteKit
class MenuScene: SKScene {
override func didMoveToView(view: SKView) {
createScene()
}
func createScene() {
self.backgroundColor = SKColor.redColor()
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.name = "label"
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPoint(x:500, y:300)
self.addChild(myLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let nextScene = GameScene(size: scene!.size)
nextScene.scaleMode = .AspectFill
let doors = SKTransition.doorsOpenVerticalWithDuration(0.5)
self.view!.presentScene(nextScene, transition: doors)
}
override func update(currentTime: CFTimeInterval) {
}
}
and
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
createScene()
}
func createScene() {
self.backgroundColor = SKColor.blueColor()
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.name = "label"
myLabel.text = "Hello, World!"
myLabel.fontSize = 45
myLabel.position = CGPoint(x:500, y:300)
myLabel.zPosition = 2.0
self.addChild(myLabel)
print(myLabel.position)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let nextScene = MenuScene(size: scene!.size)
nextScene.scaleMode = .AspectFill
let doors = SKTransition.doorsOpenVerticalWithDuration(0.5)
self.view!.presentScene(nextScene, transition: doors)
}
override func update(currentTime: CFTimeInterval) {
}
}

Related

my code doesn't draw a line, it only draws a very tiny circle

My code isn't behaving the way I want it, why is the so? I don't understand what went wrong. So I'm playing around with swift, trying to transition from android to swift, I'm trying to make this simple app that draws lines, its not working as I want it, can someone please help me with what I'm doing wrong?
//
// DrawView.swift
// IOSTouch
import Foundation
import UIKit
class DrawView: UIView {
var currentLine: Line?
var finishedLines = [Line]();
//for debug
let line1 = Line(begin: CGPoint(x:50,y:50), end: CGPoint(x:100,y:100));
let line2 = Line(begin: CGPoint(x:50,y:100), end: CGPoint(x:100,y:300));
func strokeLine(line: Line){
//Use BezierPath to draw lines
let path = UIBezierPath();
path.lineWidth = 5;
path.lineCapStyle = CGLineCap.round;
path.move(to: line.begin);
path.addLine(to: line.end);
path.stroke(); //actually draw the path
}
override func draw(_ rect: CGRect) {
//draw the finished lines
UIColor.black.setStroke() //finished lines in black
for line in finishedLines{
strokeLine(line: line);
}
//for debug
strokeLine(line: line1);
strokeLine(line: line2);
//draw current line if it exists
if let line = currentLine {
UIColor.red.setStroke(); //current line in red
strokeLine(line: line);
}
}
//Override Touch Functions
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print(#function) //for debugging
let touch = touches.first!; //get first touch event and unwrap optional
let location = touch.location(in: self); //get location in view co-ordinate
currentLine = Line(begin: location, end: location);
setNeedsDisplay(); //this view needs to be updated
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
//TODO
setNeedsDisplay()
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
//TODO
setNeedsDisplay()
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
//TODO
}
#IBInspectable var finishedLineColor: UIColor = UIColor.black {
didSet {
setNeedsDisplay()
}
}
#IBInspectable var currentLineColor: UIColor = UIColor.red {
didSet {
setNeedsDisplay()
}
}
#IBInspectable var lineThickness: CGFloat = 10 {
didSet {
setNeedsDisplay()
}
}
}
another file
import Foundation
import CoreGraphics
struct Line {
var begin = CGPoint.zero
var end = CGPoint.zero
}
This code is works, I use it:
import UIKit
class ViewController: UIViewController {
var firstPoint: CGPoint?
var secondPoint: CGPoint?
var currentLine: CAShapeLayer?
override func viewDidLoad() {
super.viewDidLoad()
}
func addLine(fromPoint start: CGPoint, toPoint end:CGPoint) {
let line = CAShapeLayer()
let linePath = UIBezierPath()
linePath.move(to: start)
linePath.addLine(to: end)
line.path = linePath.cgPath
line.strokeColor = UIColor.black.cgColor
line.lineWidth = 3
line.lineJoin = kCALineJoinRound
self.view.layer.addSublayer(line)
}
func setCurrentLine(fromPoint start: CGPoint, toPoint end: CGPoint) {
let line = CAShapeLayer()
let linePath = UIBezierPath()
linePath.move(to: start)
linePath.addLine(to: end)
line.path = linePath.cgPath
line.strokeColor = UIColor.red.cgColor
line.lineWidth = 3
line.lineJoin = kCALineJoinRound
currentLine = line
if let current = currentLine {
self.view.layer.addSublayer(current)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
firstPoint = touches.first?.location(in: self.view)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
currentLine?.removeFromSuperlayer()
currentLine = nil
if let first = firstPoint, let current = touches.first?.location(in: self.view) {
setCurrentLine(fromPoint: first, toPoint: current)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
secondPoint = touches.first?.location(in: self.view)
if let first = firstPoint, let second = secondPoint {
addLine(fromPoint: first, toPoint: second)
currentLine?.removeFromSuperlayer()
currentLine = nil
}
}
}
It should work now
override func touchesMoved(_ touches: Set, with event: UIEvent?) {
print(#function)
let touch = touches.first!
let location = touch.location(in: self);
currentLine?.end = location;
setNeedsDisplay();
}
override func touchesEnded(_ touches: Set, with event: UIEvent?) {
print(#function) //for debugging
if var line = currentLine {
let touch = touches.first!;
let location = touch.location(in: self);
line.end = location;
finishedLines.append(line);
}
currentLine = nil;
setNeedsDisplay();
}
override func touchesCancelled(_ touches: Set<UITouch>?, with event: UIEvent?) {
print(#function) //for debugging
currentLine = nil;
setNeedsDisplay();
}

Joystick+Firebutton dont work together

I'm making an app where you controll the ship's movement with a joystick, and fires a bullet with a shoot button. These two functions works great separately but if i tap the shooting button while i move the ship with the joystick, the joystick becomes uncontrolable. So what i need is that the joystick functions normally when i tap anywhere on the screen.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
let player=SKSpriteNode(imageNamed: "prez")
let joystickback=SKSpriteNode(imageNamed: "0")
let joystickbutton=SKSpriteNode(imageNamed: "1")
let shootbutton=SKSpriteNode(imageNamed: "1")
var joystickinuse=false
var velocityX : CGFloat=0.0
var velocityY : CGFloat=0.0
override func didMove(to view: SKView) {
let background=SKSpriteNode(imageNamed: "back")
background.size=self.size
background.position=CGPoint(x: self.size.width/2, y: self.size.height/2)
background.zPosition=0
self.addChild(background)
//joystick back
self.joystickback.position=CGPoint(x: (self.view?.frame.width)!*0.1, y: (self.view?.frame.height)!/5)
self.joystickback.zPosition=1
//jostick butt
self.joystickbutton.position=CGPoint(x: (self.view?.frame.width)!*0.1, y: (self.view?.frame.height)!/5)
self.joystickbutton.zPosition=2
//shootingbutton
self.shootbutton.position=CGPoint(x: (self.view?.frame.width)!*0.9, y: (self.view?.frame.height)!/5)
self.shootbutton.zPosition=2
self.shootbutton.setScale(0.4)
self.ship.position=CGPoint(x: (self.view?.frame.width)!/2, y: (self.view?.frame.height)!/2)
self.ship.setScale(0.2)
self.ship.zPosition=3
self.joystickback.setScale(0.5)
self.joystickbutton.setScale(0.5)
self.addChild(shootbutton)
self.addChild(ship)
self.addChild(joystickback)
self.addChild(joystickbutton)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches{
let location=t.location(in: self)
if (joystickbutton.frame.contains(location)){
joystickinuse=true
}
}
}
func touchMoved(touch:UITouch){
let location=touch.location(in: self)
if (joystickinuse){
let vecktor=CGVector(dx: location.x-joystickback.position.x, dy: location.y-joystickback.position.y)
let angle=atan2(vecktor.dy, vecktor.dx)
let DistanceFromCenter=CGFloat(joystickback.frame.size.height/2)
let DistanceX=CGFloat(sin(angle-CGFloat(M_PI)/2)*DistanceFromCenter)
let DistanceY=CGFloat(cos(angle-CGFloat(M_PI)/2)*DistanceFromCenter)
if(joystickback.frame.contains(location)){
joystickbutton.position=location
}
else{
joystickbutton.position=CGPoint(x: joystickback.position.x-DistanceX, y: joystickback.position.y+DistanceY)
}
velocityX=(joystickbutton.position.x-joystickback.position.x)/10
velocityY=(joystickbutton.position.y-joystickback.position.y)/10
}
}
func firebullet(){
let bullet=SKSpriteNode(imageNamed: "rocket")
bullet.position=urhajo.position
bullet.setScale(0.2)
bullet.zPosition=1
self.addChild(bullet)
let movebullet=SKAction.moveTo(x: self.size.width+bullet.size.width, duration: 1)
let deletebullet=SKAction.removeFromParent()
let bulletsequence=SKAction.sequence([movebullet,deletebullet])
bullet.run(bulletsequence)
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches{
self.touchMoved(touch: t)
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if(joystickinuse){
movementOver()
}
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if(joystickinuse){
movementOver()
}
}
func movementOver(){
let moveBack=SKAction.move(to: CGPoint(x: joystickback.position.x,y: joystickback.position.y), duration: TimeInterval(floatLiteral:0.1))
moveBack.timingMode = .linear
joystickbutton.run(moveBack)
joystickinuse=false
velocityY=0
velocityX=0
}
override func update(_ currentTime: TimeInterval) {
if(ship.position.x>=(self.view?.frame.width)!+urhajo.frame.width/2){
}
else{ self.ship.position.x+=velocityX
}
self.ship.position.y+=velocityY
}
}
try setting this is your Scene code
func didMove(to view: SKView) {
self.view!.isMultipleTouchEnabled = true
}

Swift 3: How do I pinch to scale and rotate UIImageView?

I am really struggling to find tutorials online as well as already answered questions (I have tried them and they don't seem to work). I have a UIImageView that I have in the centre of my view. I am currently able to tap and drag this wherever I want on screen. I want to be able to pinch to scale and rotate this view. How do I achieve this? I have tried the code for rotation below but it doesn't seem to work? Any help will be a massive help and marked as answer. Thank you guys.
import UIKit
class DraggableImage: UIImageView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.backgroundColor = .blue
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
self.backgroundColor = .green
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: superview)
center = CGPoint(x: position.x, y: position.y)
}
}
}
class CVController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateAction(sender:)))
firstImageView.addGestureRecognizer(rotateGesture)
setupViews()
}
func rotateAction(sender: UIRotationGestureRecognizer) {
let rotatePoint = sender.location(in: view)
let firstImageView = view.hitTest(rotatePoint, with: nil)
firstImageView?.transform = (firstImageView?.transform.rotated(by: sender.rotation))!
sender.rotation = 0
}
let firstImageView: DraggableImage = {
let iv = DraggableImage()
iv.backgroundColor = .red
iv.isUserInteractionEnabled = true
return iv
}()
func setupViews() {
view.addSubview(firstImageView)
let firstImageWidth: CGFloat = 50
let firstImageHeight: CGFloat = 50
firstImageView.frame = CGRect(x: (view.frame.width / 2) - firstImageWidth / 2, y: (view.frame.height / 2) - firstImageWidth / 2, width: firstImageWidth, height: firstImageHeight)
}
}
You have a some problems in your code. First you need to add the UIGestureRecognizerDelegate to your view controller and make it your gesture recognizer delegate. You need also to implement shouldRecognizeSimultaneously method and return true. Second when applying the scale you need to save the transform when the pinch begins and apply the scale in top of it:
class DraggableImageView: UIImageView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
backgroundColor = .blue
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
backgroundColor = .green
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let position = touches.first?.location(in: superview){
center = position
}
}
}
class ViewController: UIViewController, UIGestureRecognizerDelegate {
var identity = CGAffineTransform.identity
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
setupViews()
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(scale))
let rotationGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotate))
pinchGesture.delegate = self
rotationGesture.delegate = self
view.addGestureRecognizer(pinchGesture)
view.addGestureRecognizer(rotationGesture)
}
let firstImageView: DraggableImageView = {
let iv = DraggableImageView()
iv.backgroundColor = .red
iv.isUserInteractionEnabled = true
return iv
}()
func setupViews() {
view.addSubview(firstImageView)
let firstImageWidth: CGFloat = 50
let firstImageHeight: CGFloat = 50
firstImageView.frame = CGRect(x: view.frame.midX - firstImageWidth / 2, y: view.frame.midY - firstImageWidth / 2, width: firstImageWidth, height: firstImageHeight)
}
#objc func scale(_ gesture: UIPinchGestureRecognizer) {
switch gesture.state {
case .began:
identity = firstImageView.transform
case .changed,.ended:
firstImageView.transform = identity.scaledBy(x: gesture.scale, y: gesture.scale)
case .cancelled:
break
default:
break
}
}
#objc func rotate(_ gesture: UIRotationGestureRecognizer) {
firstImageView.transform = firstImageView.transform.rotated(by: gesture.rotation)
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}

How to add 1 point every time SKNode is touched

I created a game involving falling balls. Every time the player taps a ball, they're supposed to get a point. I set up the score label, but it just stays at 0.
Is there something wrong with my code?
I use a GameElements.swift file as an extension. Here is the file:
extension GameScene {
//1st Ball//
func createPlayer() -> SKNode {
let playerNode = SKNode()
playerNode.position = CGPoint(x:self.size.width / 2, y:440)
let sprite = SKSpriteNode(imageNamed: "Ball")
sprite.name = "ballPoints"
playerNode.addChild(sprite)
playerNode.physicsBody = SKPhysicsBody(circleOfRadius: 120)
playerNode.physicsBody?.dynamic = true
playerNode.physicsBody?.allowsRotation = false
playerNode.physicsBody?.restitution = 3
playerNode.physicsBody?.friction = 0
playerNode.physicsBody?.angularDamping = 0
playerNode.physicsBody?.linearDamping = 0
playerNode.physicsBody?.usesPreciseCollisionDetection = true
playerNode.physicsBody?.categoryBitMask = CollisionBitMask.Player
playerNode.physicsBody?.categoryBitMask = 0
return playerNode
}
}
Here is the GameScene.swift file:
class GameScene: SKScene {
var foreground: SKNode!
var hud: SKNode!
var firstBall: SKNode!
var scoreLabel: SKLabelNode!
private var score = 0
override func didMoveToView(view: SKView) {
scoreLabel = SKLabelNode(fontNamed:"Geared-Slab")
scoreLabel.fontColor = UIColor.blackColor()
scoreLabel.position = CGPoint( x: self.frame.midX, y: 3 * self.frame.size.height / 4 )
scoreLabel.fontSize = 100.0
scoreLabel.zPosition = 100
scoreLabel.text = String(score)
self.addChild(scoreLabel)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if(firstBall.containsPoint(location)) {
firstBall.physicsBody?.velocity = CGVectorMake(0, 600)
firstBall.physicsBody?.applyImpulse(CGVectorMake(0, 1100))
}
if
let touch : UITouch! = touches.first,
let tappedSprite = nodeAtPoint(touch!.locationInNode(self)) as? SKSpriteNode,
let scoreLabel = childNodeWithName("scoreLabel") as? SKLabelNode
where tappedSprite.name == "ballPoints" {
score += 1
scoreLabel.text = "Score: \(score)"
}
}
}
override init(size:CGSize) {
super.init(size: size)
foreground = SKNode()
addChild(foreground)
//1st Ball//
firstBall = createPlayer()
foreground.addChild(firstBall)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I know this is a lot of code, but I want experts to be able to test the code themselves. For background, I was following this tutorial: https://www.youtube.com/watch?v=0gOi_2Jwt28 up until a certain point.
Step 1
First of all let's create a class for the Ball
class Ball: SKSpriteNode {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let scene = self.scene as! GameScene
scene.score += 1
}
}
Step 2
Then inside createPlayer() let's replace this
let sprite = SKSpriteNode(imageNamed: "Ball")
with this
let sprite = Ball(imageNamed: "Ball")
sprite.userInteractionEnabled = true
Step 3
Let's remove the touchesBegan from GameScene.
Update
This code is working as expected for me
class GameScene: SKScene {
var scoreLabel: SKLabelNode!
var ball: Ball!
private var score = 0 {
didSet {
scoreLabel.text = "\(score)"
print(score)
}
}
override func didMoveToView(view: SKView) {
let ball = Ball()
ball.position = CGPoint(x:frame.midX, y: frame.midY)
addChild(ball)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// this is called when you tap outside of the Ball
// use self.ball to make the ball to jump
}
}
class Ball: SKSpriteNode {
init() {
let texture = SKTexture(imageNamed: "ball")
super.init(texture: texture, color: .clearColor(), size: texture.size())
userInteractionEnabled = true
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let scene = self.scene as! GameScene
scene.score += 1
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

Player not moving when tapped

I have it set up so that my player should jump to wherever I tap on the screen, however, it won't budge. I triple checked my code and can't find anything wrong. Can someone please help?
Here is my code for my GameScene:
import SpriteKit
var player: Player!
var snowflake: Snowflake!
var isFingerOnPlayer = false
var gameOver = false
var playerTouched = false
var touching: Bool = false
var lastTouch: CGPoint? = nil
let xPlayerForce: CGFloat = 30
let yPlayerForce: CGFloat = 40
var touchPoint: CGPoint = CGPoint()
class GameScene: SKScene, SKPhysicsContactDelegate {
override func didMoveToView(view: SKView) {
player = Player()
addChild(player)
backgroundColor = UIColor.whiteColor()
snowflake = Snowflake()
addChild(snowflake)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
lastTouch = location
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
lastTouch = nil
}
override func update(currentTime: NSTimeInterval) {
if let touch = lastTouch {
var xForce: CGFloat = 0.0
var yForce: CGFloat = 0.0
let xTouchOffset = (touch.x - player.position.x)
let yTouchOffset = (touch.y - player.position.y)
if xTouchOffset > 0.0
{
xForce = xPlayerForce
}
else if xTouchOffset < 0.0
{
xForce = -xPlayerForce
} // else we do nothing
if yTouchOffset > 0.0
{
yForce = yPlayerForce
} // here you can choose whether you want it to push
// the player node down, using similar code from the
// above if statement
let impulseVector = CGVector(dx: xForce, dy: yForce)
player.physicsBody?.applyImpulse(impulseVector)
}
}
You are right by saying you don't NEED code in touches began, but from what you are saying you should probably. I would try just setting the location of the object in touches began and then updating it in touches moved.