Run an SKSpriteNode object along a line drawn with the mouse in Swift - xcode

If you let go of the left mouse button, my SKSpriteNode object should move along the line previously "drawn" with the mouse.
My problem is that my sprite node is moving down when I release the left mouse button.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
let object: SKSpriteNode = SKSpriteNode(imageNamed: "rabbit")
var actionArray = [SKAction()]
override func didMove(to view: SKView) {
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
physicsWorld.contactDelegate = self
object.setScale(0.2)
object.position = CGPoint(x: size.width / 2, y: size.height / 2)
object.zPosition = 0
object.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "rabbit"), size: object.size)
object.physicsBody?.mass = 0
object.physicsBody?.categoryBitMask = 0
object.physicsBody?.contactTestBitMask = 1
object.physicsBody?.collisionBitMask = 0
addChild(object)
}
override func mouseDragged(with event: NSEvent) {
actionArray.append(SKAction.move(to: event.location(in: self), duration: 1))
}
override func mouseUp(with event: NSEvent) {
object.run(SKAction.sequence(actionArray))
// Remove all actions from 'actionArray'.
actionArray.removeAll()
}
}
I have already tried it as shown below. Now my sprite node moves to the first point, where I pressed down the left mouse button.
override func mouseUp(with event: NSEvent) {
let removeAllFromActionArray = SKAction.run {
self.actionArray.removeAll()
}
actionArray.append(removeAllFromActionArray)
object.run(SKAction.sequence(actionArray))
}
I've already tried view! .Convert (event.locationInWindow, to: view! .Scene!) Instead of event.location (in: self), as indicated in Position of mouse click relative to scene, not window, but the result was the same.
I suspect that the bug lies in override func mouseUp(with event: event).
Where does the error lie or is there another solution?

Related

error removing child node from parent node in spriteKit Swift4

I made a parallax background, in GameScene.sks I added an empty node, added two sprites to an empty node. I have a reset button, when I click on it I need the background to be removed and added to its position (restarted), but when I add in scrollBg.removeAllChildren restart function I error occurs, how do I properly add and remove children from the scene ?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var player: SKSpriteNode!
var scrollBg: SKNode!
var spawnTimer: CFTimeInterval = 0
let fixedDelta: CFTimeInterval = 1.0/60.0 /* 60 FPS */
let scrollSpeed: CGFloat = 700
var sinceTouch: CFTimeInterval = 0
func resetGameScene() {
scrollBG.removeAllChildren()
player.removeAllChildren()
player.position = CGPoint(x: 590 , y: 690)
pauseButton()
}
override func didMove(to view: SKView) {
physicsWorld.contactDelegate = self
player = childNode(withName: "player") as? SKSpriteNode
scrollBg = childNode(withName: "scrollBG")!
resetGameScene()
}
func scrollWorld() {
scrollBg.position.y -= scrollSpeed * CGFloat(fixedDelta)
for ground in scrollBg.children as! [SKSpriteNode] {
let groundPosition = scrollBg.convert(ground.position, to:
self)
if groundPosition.y <= -ground.size.width {
let newPosition = CGPoint(x: groundPosition.x, y:
(self.size.width ) + ground.size.width * 2)
ground.position = self.convert(newPosition, to:
scrollBg)
}
}
}
override func update(_ currentTime: TimeInterval) {
sinceTouch+=fixedDelta
spawnTimer+=fixedDelta
scrollWorld()
}
}

NSDocument printOperationWithSettings not showing all pages

In NSDocument subclass, have this function:
override func printOperationWithSettings(printSettings: [String : AnyObject]) throws -> NSPrintOperation {
let printInfo: NSPrintInfo = self.printInfo
var pageSize = printInfo.paperSize
pageSize.width -= printInfo.leftMargin + printInfo.rightMargin
pageSize.height -= printInfo.topMargin + printInfo.bottomMargin
pageSize.width = pageSize.width * 2
pageSize.height = pageSize.height * 2
let myPage = MyPage(frame: CGRect(origin: CGPoint(x: 0, y: 0), size: pageSize))
let printOperation = NSPrintOperation(view: myPage, printInfo: printInfo)
return printOperation
}
MyPage is, for this test, an NSView subclass that just draws an oval.
class MyPage: NSView {
override var flipped: Bool {
return true
}
override func drawRect(dirtyRect: NSRect) {
super.drawRect(dirtyRect)
NSColor.greenColor().set() // choose color
let figure = NSBezierPath() // container for line(s)
figure.appendBezierPathWithOvalInRect(self.frame)
figure.stroke() // draw line(s)
}
}
I'd expect this to show four pages in the print panel, but it only shows two, equating to the top left and bottom left of the oval. No matter how wide I make myPage's frame, only the leftmost pages are shown. Any ideas why? Thank you!

SKScene and Swift Files are not linking

In my xcode project I am trying to transition from one SKScene to another. What triggers the transition is the touching of a SKLabelNode. All of that is working correctly. But after the scene changes none of my code from my class that controls the "StartScence.sks" works. It seems as if my "StartScene.swift" and my "StartScene.sks" are not linked.
This is the code in my GameScene,
import SpriteKit
class GameScene: SKScene {
var isTouched: Bool = false
var booleanTouched: Bool!
let ns = SKScene(fileNamed: "StartScene")
let crosswf = SKTransition.crossFadeWithDuration(2)
override func didMoveToView(view: SKView) {
let backgroundimage = SKSpriteNode(imageNamed: "ipbg")
backgroundimage.size = CGSize(width: self.frame.size.width, height: self.frame.size.height)
backgroundimage.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2)
addChild(backgroundimage)
let playButton = SKLabelNode(fontNamed: "")
playButton.name = "play"
playButton.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height / 2 + 100)
playButton.text = "Play"
let wait = SKAction.waitForDuration(2)
let run = SKAction.runBlock({
let randomNumber = Int(arc4random_uniform(UInt32(4)))
switch(randomNumber){
case (0):
playButton.fontColor = UIColor.blueColor()
case 1:
playButton.fontColor = UIColor.yellowColor()
case 2:
playButton.fontColor = UIColor.purpleColor()
case 3:
playButton.fontColor = UIColor.orangeColor()
default: print("default")
}
})
addChild(playButton)
var repeatActionForever = SKAction.repeatActionForever(SKAction.sequence([wait, run]))
runAction(repeatActionForever)
backgroundimage.zPosition = 1
playButton.zPosition = 2
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let touch = touches.first! as UITouch
let touchLocation = touch.locationInNode(self)
let touchedNode = nodeAtPoint(touchLocation)
if (touchedNode.name == "play"){
scene!.view?.presentScene(ns!, transition: crosswf)
}else{
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
And this is the code that is my "StartScene.swift" that isnt controlling the "StartScene.sks" properly.
import SpriteKit
class StartScene: SKScene {
override func didMoveToView(view: SKView) {
print("Scene Loaded")
}
}
There's two things to be aware of.
In your code you are currently loading your .SKS file like this
let ns = SKScene(fileNamed: "StartScene")
Your new scene will load, as all SKS Files are of the class SKScene.
But, it will only use code from that class.
If you want it to load with the code in your class StartScene, a subclass of SKScene. Change the line to this
let ns = StartScene(fileNamed: "StartScene")
We can also make the SKS File have a custom class instead of it's default SKScene. So when it's loaded it uses a custom class.
Open the SKS File in Xcode so you can give the scene a Custom Class. In the scene editor and with nothing selected. Click in the utilities area, switch to the Custom Class Inspector, which is the last tab on the right.
Give it a Custom Class of StartScene.
It should work.

How can I make SKSpriteNode positions the same for any simulator/device?

In my game, the position of my SKNodes slightly change when I run the App on a virtual simulator vs on a real device(my iPad).
Here are pictures of what I am talking about.
This is the virtual simulator
This is my Ipad
It is hard to see, but the two red boxes are slightly higher on my iPad than in the simulator
Here is how i declare the size and position of the red boxes and green net:
The following code is located in my GameScene.swift file
func loadAppearance_Rim1() {
Rim1 = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake((frame.size.width) / 40, (frame.size.width) / 40))
Rim1.position = CGPointMake(((frame.size.width) / 2.23), ((frame.size.height) / 1.33))
Rim1.zPosition = 1
addChild(Rim1)
}
func loadAppearance_Rim2(){
Rim2 = SKSpriteNode(color: UIColor.redColor(), size: CGSizeMake((frame.size.width) / 40, (frame.size.width) / 40))
Rim2.position = CGPoint(x: ((frame.size.width) / 1.8), y: ((frame.size.height) / 1.33))
Rim2.zPosition = 1
addChild(Rim2)
}
func loadAppearance_RimNet(){
RimNet = SKSpriteNode(color: UIColor.greenColor(), size: CGSizeMake((frame.size.width) / 7.5, (frame.size.width) / 150))
RimNet.position = CGPointMake(frame.size.width / 1.99, frame.size.height / 1.33)
RimNet.zPosition = 1
addChild(RimNet)
}
func addBackground(){
//background
background = SKSpriteNode(imageNamed: "Background")
background.zPosition = 0
background.size = self.frame.size
background.position = CGPoint(x: self.size.width / 2, y: self.size.height / 2)
self.addChild(background)
}
Additionally my GameViewController.swift looks like this
import UIKit
import SpriteKit
class GameViewController: UIViewController {
var scene: GameScene!
override func viewDidLoad() {
super.viewDidLoad()
//Configure the view
let skView = view as! SKView
//If finger is on iphone, you cant tap again
skView.multipleTouchEnabled = false
//Create and configure the scene
//create scene within size of skview
scene = GameScene(size: skView.bounds.size)
scene.scaleMode = .AspectFill
scene.size = skView.bounds.size
//scene.anchorPoint = CGPointZero
//present the scene
skView.presentScene(scene)
}
override func shouldAutorotate() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
return .Landscape
} else {
return .All
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
How can I make the positions of my nodes be the same for each simulator/physical device?
You should round those floating point values to integers via a call to (int)round(float) so that the values snap to whole pixels. Any place where you use CGPoint or CGSize should use whole pixels as opposed to floating point values.
If you are making a Universal application you need to declare the size of the scene using integer values. Here is an example:
scene = GameScene(size:CGSize(width: 2048, height: 1536))
Then when you initialize the positions and sizes of your nodes using CGPoint and CGSize, make them dependant on SKScene size. Here is an example:
node.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
If you declare the size of the scene for a Universal App like this:
scene.size = skView.bounds.size
then your SKSpriteNode positions will be all messed up. You may also need to change the scaleMode to .ResizeFill. This worked for me.

Change scroll speed

var speed: CGFloat = 5
override func didMoveToView(view: SKView) {
/* Setup your scene here */
var move = SKAction.moveTo(CGPoint(x: node.position.x, y: -(self.frame.height)), duration: NSTimeInterval(speed))
var reset = SKAction.moveTo(CGPoint(x: node.position.x, y: self.frame.height ), duration: 0)
var scroll = SKAction.sequence([move, reset])
node.runAction(SKAction.repeatActionForever(scroll))
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
speed++
println(speed)
}
I have a node that i want to scroll, and i want it's speed changes depending on the player touch, my problem is when the player touch the value indeed increases but the node itself keeps the same initial value. I also tried changing in the update method and that didn't work either.
How to solve this ?

Resources