import SpriteKit
class GameScene: SKScene {
let bgline1 = SKSpriteNode(imageNamed: "Line.png")
let bgline2 = SKSpriteNode(imageNamed: "Line.png")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
backgroundColor = SKColor.whiteColor()
bgline1.anchorPoint = CGPointZero
bgline1.position = CGPointZero
bgline1.zPosition = 1
bgline1.size = CGSizeMake(self.frame.size.width, self.frame.size.height)
self.addChild(bgline1)
bgline2.anchorPoint = CGPointZero
bgline2.position = CGPointMake(bgline1.position.x-1, 0)
bgline2.zPosition = 1
bgline2.size = CGSizeMake(self.frame.size.width, self.frame.size.height)
self.addChild(bgline2)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered*/
bgline1.position = CGPoint(x: bgline1.position.x-4, y: bgline1.position.y)
bgline2.position = CGPoint(x: bgline2.position.x-4, y: bgline2.position.y)
if bgline1.position.x < -bgline1.size.width{
bgline1.position = CGPointMake(bgline2.position.x + bgline2.size.width, bgline1.position.y)
}
if bgline2.position.x < -bgline2.size.width{
bgline2.position = CGPointMake(bgline1.position.x + bgline1.size.width, bgline2.position.y)
}
}
}
This is my code for creating a scrolling horizontal endless background. It is supposed to make an endless background but it isn't. The code is not looping the first try but after that it does. I would like to know why it does not work and how should I fix it.
EDIT- Starts out with 2 nodes and a line and the fps is <20. Then the line ends and when it "runs out" the node count becomes 0 and fps becomes 60. Than after a few seconds the line pops back up and it runs perfectly like a endless scrolling background.
bgline2.position = CGPointMake(bgline1.size.width-1, 0)
This line of code somehow fixed the problem for me. I don't know how it fixed it but it did. If someone wants to explain this for me please do. I have not seen any tutorials out there that use this but it worked for me.
Rohit
Related
It's the third time I'm looking for help in this question.
I have a class name BallNode of kind SKShapeNode. Inside my code I also have a function the spawn ball every 3 second from the top side of the screen. Now, I want to set a function that locate the ball position every 1 second, and so, if the ball.position.y > 200 to print a message to the console.
The purpose of this is that if any ball will be at this position (not while it's falling down) the I will call another function. I tried to do it via SKAction, update(_ currentTime: CFTimeInterval), Timer but I didn't succeed and I really have no idea what to do...
update - my current code:
var timeType1: CFTimeInterval = 0.0
var timeType2: CFTimeInterval = 2.0
override func update(_ currentTime: CFTimeInterval) {
if (currentTime - timeType1 > timeType2){
print("time")
self.checkBallsPosition()
self.timeType1 = currentTime
}
self.enumerateChildNodes(withName: "color.BallNode") { node, _ in
self.checkBallsPosition()
}
}
func checkBallsPosition() {
self.enumerateChildNodes(withName: "BALL") { (node: SKNode, nil) in
let x = self.createTopBorder()
x.isHidden = true
let wait2 = SKAction.wait(forDuration: 1)
let action2 = SKAction.run {
let position = Double(node.position.y)
if position < 200 {
}
else if position > 200 {
print("bolbo")
node.removeFromParent()
}
}
self.run(SKAction.sequence([wait2,action2]))
}
}
thats what I try do to so far, as I said the problem is that I want to get the ball last position. because the ball fall down the screen the last position should be when it touch the bottom border of the screen or when it touches another ball. if I set it at update I get the ball position every frame or (as I did) every second - but not the last. another problem is that the ball position can always change depends on another balls (when collision occurs).
update #2 - another functions:
func spawnBalls() {
let wait = SKAction.wait(forDuration: 3)
let action = SKAction.run {
self.createBall()
}
run(SKAction.repeatForever((SKAction.sequence([wait, action]))))
}
func createBall(){
let ball = BallNode(radius: 65)
print(ball.Name)
print(ball._subName!)
ball.position.y = ((frame.size.height) - 200)
let ballXPosition = arc4random_uniform(UInt32(frame.size.width))
ball.position.x = CGFloat(ballXPosition)
ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
ball.physicsBody?.collisionBitMask = PhysicsCategory.ball
ball.physicsBody?.contactTestBitMask = PhysicsCategory.topBorder
ball.delegate = self
addChild(ball)
}
You did not post the entire code you are using. Not knowing how you are spawning your balls, how is the hierarchy and how you are moving them, I can't reproduce it here.
I am not sure if I understand it right, but I believe it might be simpler than what you are doing. See if the code below helps you, I am making the balls fall with SKAction (you can do it with physics also), and checking when they go below zero, when I remove them.
private let ballSpeed : CGFloat = 400
private let ballRadius : CGFloat = 10
private func spawnBall(atPoint pos : CGPoint){
let b = SKShapeNode(circleOfRadius: ballRadius)
b.name = "ball"
b.position = pos
addChild(b)
b.run(SKAction.moveTo(y: -size.height, duration: TimeInterval((pos.y+size.height)/400)))
}
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
enumerateChildNodes(withName: "ball") { (node, _) in
if node.position.y < 0 {
node.removeFromParent()
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let pos = touch.location(in: self)
spawnBall(atPoint: pos)
}
}
I am new to swift and looking to build my first basic game. The game I have in mind involves sprites generating at random and then disappearing based on time or a click if the click is within the time allocated. So far I have created the basic framework and am still messing around with design. My problem comes in where I can't seem to remove the sprite based on time (its generating fine). Any help is appreciated and thanks in advance😊
Below is the framework I've built up so far.
import SpriteKit
var one = SKSpriteNode()
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myFunction = SKAction.runBlock({()in self.addOne()})
let wait = SKAction.waitForDuration(5)
let remove = SKAction.runBlock({() in self.removeOne()})
self.runAction(SKAction.sequence([myFunction, wait, remove]))
}
func addOne() {
let oneTexture = SKTexture(imageNamed: "blue button 10.png")
let one = SKSpriteNode(texture: oneTexture)
one.position = CGPoint(x: CGRectGetMidX(self.frame) - 100, y: CGRectGetMidY(self.frame) + 250)
one.zPosition = 1
self.addChild(one)
}
func removeOne() {
one.removeFromParent()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
It doesn't disappear because your create a new SpiteNode, but try to remove the old one, do it like this:
var one : SKSpriteNode! //instead of creating it without data, just define the type(not necessary, but I would do it)
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myFunction = SKAction.runBlock({()in self.addOne()})
let wait = SKAction.waitForDuration(5)
let remove = SKAction.runBlock({() in self.removeOne()})
self.runAction(SKAction.sequence([myFunction, wait, remove]))
}
func addOne() {
let oneTexture = SKTexture(imageNamed: "blue button 10.png")
one = SKSpriteNode(texture: oneTexture) //removed the let, so you dont create a new "one"
one.position = CGPoint(x: CGRectGetMidX(self.frame) - 100, y: CGRectGetMidY(self.frame) + 250)
one.zPosition = 1
self.addChild(one)
}
func removeOne() {
one.removeFromParent()
}
}
I'm currently trying to make a node that can change it's texture, but it's not visible on the simulator. I know it's there, cause I set showNodesCount to true and it displays that 2 nodes are on scene. It's displaying a cannon node, but not rgyBox node, that should change it's texture if I tap on cannon node. Here is my code:
class GameScene: SKScene {
var gameOver = false
let cannon = SKSpriteNode(imageNamed: "cannon")
let rgyArray = ["redBox", "greenBox", "yellowBox"]
var rgyBlock = SKSpriteNode()
func changeRgyColor() {
var randomRGY = Int(arc4random_uniform(3))
rgyBlock.texture = SKTexture(imageNamed: rgyArray[randomRGY])
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
cannon.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
self.addChild(cannon)
rgyBlock.texture = SKTexture(imageNamed: rgyArray[1])
rgyBlock.position = CGPointMake(self.cannon.position.x, self.cannon.position.y + 20)
self.addChild(rgyBlock)
rgyBlock.zPosition = 10
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
if self.nodeAtPoint(location) == self.cannon {
changeRgyColor()
}
}
}
What am I doing wrong?
You need to recreate the rgyBlock by calling rgyBlock = SKSpriteNode(imageNamed: rgyArray[1]). Where it is defined at the top, it is defined as nothing. You then need to recreate it in didMoveToView. You can remove the texture set in didMoveToView for the rgyBlock.
You could do it a different way, and put imageNamed: "aTextureNameHere" into the define of rgyBlock. This will give rgyBlock a value. Then you can set the texture (as you already do) in didMoveToView. This way may be quicker and easier.
I'm trying to understand how Instruments works and to make my apps better. Below is an image of the result for default SpriteKit Template. I don't understand why are so many Allocations, because the code is small
override func didMoveToView(view: SKView) {
/* Setup your scene here */
let myLabel = SKLabelNode(fontNamed:"Chalkduster")
myLabel.text = "Hello, World!";
myLabel.fontSize = 65;
myLabel.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(myLabel)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
for touch in (touches as! Set<UITouch>) {
let location = touch.locationInNode(self)
let sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite.xScale = 0.5
sprite.yScale = 0.5
sprite.position = location
let action = SKAction.rotateByAngle(CGFloat(M_PI), duration:1)
sprite.runAction(SKAction.repeatActionForever(action))
self.addChild(sprite)
}
}
I try to find tutorials but many of them are very old
Well we aren't apple programmers, we don't really know what's going on inside SpriteKit.
I'm guessing it's just because of the complexity of the physics engine.
I suggest just watching out for leaks.
I am using Swift and Sprite Kit to develop a game on XCode Beta 6.
In order to detect if all nodes are sleeping, i check their physicsBody.resting property.
In update method i print out the result.
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var hero:SKSpriteNode!
override func didMoveToView(view: SKView) {
self.physicsWorld.gravity = CGVectorMake(0, 0)
self.physicsWorld.contactDelegate = self
self.physicsBody = SKPhysicsBody(edgeLoopFromRect:self.frame)
hero = SKSpriteNode(imageNamed: "Spaceship")
hero.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame))
hero.zPosition = 10.0
hero.physicsBody = SKPhysicsBody(circleOfRadius: hero.size.width/2)
hero.physicsBody.allowsRotation = false
hero.physicsBody.linearDamping = 0.5
self.addChild(hero)
}
override func update(currentTime: CFTimeInterval) {
if hero.physicsBody.resting {
println("resting")
} else {
println("moving")
}
}
}
To my surprise, the results are:
moving
resting
moving
(n times the same)
moving
resting
So why the hero is moving, although i didn't do anything. The node moves N times and takes a break(resting), after that goes on moving.
Can anyone explain that behaviour? Is that a bug or do i miss something? Thanks in advance.
If you examine the velocity of a physics body, you'll see that it is indeed moving but at a rate that is not perceivable. That's why the resting property is not set. A more reliable way to check if a SKPhysicsBody is at rest is to test if its linear and angular speeds are nearly zero. Here's an example of how to do that:
func speed(velocity:CGVector) -> Float {
let dx = Float(velocity.dx);
let dy = Float(velocity.dy);
return sqrtf(dx*dx+dy*dy)
}
func angularSpeed(velocity:CGFloat) -> Float {
return abs(Float(velocity))
}
// This is a more reliable test for a physicsBody at "rest"
func nearlyAtRest(node:SKNode) -> Bool {
return (self.speed(node.physicsBody.velocity)<self.verySmallValue
&& self.angularSpeed(node.physicsBody.angularVelocity) < self.verySmallValue)
}
override func update(_ currentTime: TimeInterval) {
/* Enumerate over child nodes with names starting with "circle" */
enumerateChildNodesWithName("circle*") {
node, stop in
if (node.physicsBody.resting) {
println("\(node.name) is resting")
}
if (self.nearlyAtRest(node)) {
println("\(node.name) is nearly resting")
}
}
}