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.
Related
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 am making a game with Sprite kit, I recently added background music to the game and it works, but i want to put a mute button that can allow the player to stop and play the background music while the game is running in case he don't like it. Thanks.
import AVFoundation
class GameScene: SKScene, SKPhysicsContactDelegate {
var backgroundMusic = SKAudioNode()
func restartScene(){
self.removeAllChildren()
self.removeAllActions()
died = false
gameStarted = false
score = 0
createScene()
}
func createScene(){
backgroundMusic = SKAudioNode(fileNamed: "Musicnamefile.mp3")
addChild(backgroundMusic)
}
override func didMoveToView(view: SKView) {
/* Setup your scene here */
createScene()
}
To create a button add this in didMoveToView:
// pause button
let pauseButton = SKLabelNode()
let pauseContainer = SKSpriteNode()
pauseContainer.position = CGPointMake(hud.size.width/1.5, 1)
pauseContainer.size = CGSizeMake(hud.size.height*3, hud.size.height*2)
pauseContainer.name = "PauseButtonContainer" // pause button
let pauseButton = SKLabelNode()
let pauseContainer = SKSpriteNode()
pauseContainer.position = CGPointMake(hud.size.width/1.5, 1)
pauseContainer.size = CGSizeMake(hud.size.height*3, hud.size.height*2)
pauseContainer.name = "PauseButtonContainer"
hud.addChild(pauseContainer)
pauseButton.position = CGPointMake(hud.size.width/2, 1)
pauseButton.text="I I"
pauseButton.fontSize=hud.size.height
//pauseButton.fontColor = UIColor.blackColor()
pauseButton.horizontalAlignmentMode = SKLabelHorizontalAlignmentMode.Center
pauseButton.name="PauseButton"
hud.addChild(pauseButton)
I'm using the SKLabel to show the pause symbol and a container to increase the touch area. HUD is an rectangle of type SKNode at the top of my game. You have to add the nodes to an element in your game and change the size and position.
To react on the touch:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "PauseButton" || node.name == "PauseButtonContainer") {
Insert your code here ....
}
}
}
Im just messing around in sprite-kit working on my game design skills and I came across something that I dont know how to do. That is make the physicsworld gravity more like moon gravity. I have a SKSpriteNode which is a red ball and I can drag that ball and click wherever I want it to go. What I wanted to create is somewhat of a throwing mechanism. Is this possible with one line of physics world gravity code? Or is it way more in depth this is code that I have.
import SpriteKit
class GameScene: SKScene {
let redBall = SKSpriteNode(imageNamed: "redball")
override func didMoveToView(view: SKView) {
let worldBorder = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = worldBorder
self.physicsBody?.friction = 1
self.physicsWorld.gravity = CGVectorMake(0, -1)
redBall.position = CGPoint(x:250,y:50)
addChild(redBall)
redBall.physicsBody = SKPhysicsBody(circleOfRadius: redBall.size.width/2)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
redBall.position = location
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
redBall.position = location
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
My game state right now is when I drag a ball to where I want and release it just drops. What I want to accomplish is for example if I grab the ball and drag up and to the right I want the ball to follow my the direction it was going when I released it. How would I create that in my code thanks!
In my code all I do is self.physicsworld.gravity = CGVectorMake(0, 0) (this would turn off gravity completely). Then just mess around with that vector and find something that feels like moon gravity.
You might have to make your game-scene be a SKPhysicsContactDelegate
I'm working with Swift, Sprite Kit and Xcode 6,
I would like to create a particle effect in SpriteKit a little bit like the particles effects of the balls in the iOS game named "Duet", but I don't know how to proceed, I managed to create a particle effect, but not a particle like in this game who follows a node and draw the node's path...
Here is my code :
let firstCircle = SKSpriteNode(imageNamed: "Circle")
let particle = SKEmitterNode(fileNamed: "FirstParticle.sks")
override func didMoveToView(view: SKView)
{
firstCircle.physicsBody = SKPhysicsBody(circleOfRadius: 7)
firstCircle.physicsBody?.affectedByGravity = false
particle.targetNode = firstCircle
addChild(firstCircle)
addChild(particle)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent)
{
for touch: AnyObject in touches
{
firstCircle.position = touch.locationInNode(self)
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent)
{
for touch: AnyObject in touches
{
firstCircle.position = touch.locationInNode(self)
}
}
To achieve a Duet like effect you need particle to be a child of the trailed node and targetNode set to the parent scene. targetNode controls which node the particles are rendered as a child of.
When particle is a child of the trailed node, it will emit particles with the trailed node as the origin. Changing targetNode to the parent scene leaves already emitted particles behind as the trailed node moves.
This code should work but you may need to fine tune FirstParticle.sks.
let firstCircle = SKSpriteNode(imageNamed: "Circle")
let particle = SKEmitterNode(fileNamed: "FirstParticle.sks")
override func didMoveToView(view: SKView)
{
firstCircle.physicsBody = SKPhysicsBody(circleOfRadius: 7)
firstCircle.physicsBody?.affectedByGravity = false
particle.targetNode = self
addChild(firstCircle)
firstCircle.addChild(particle)
}
I was able to get a similar effect and ended up creating a Playground to demonstrate it. Check it out here.
I have several programmatically made SKSpriteNode's. Some of them I want to move around, some I want to be static (have a fixed position). When adding physics to the nodes (need that to be able to do collision detection, right?) and set physicsBodyXXXX.dynamic = false they stay in the same position when moving other object over them. That's fine!
But, I'm still able to grab the node I want to be statically positioned, and move them around. How can I mask out the node I don't want to move in touches function? Or is there another solution?
Tried to find a property like static which made the node's position fixed, but can't find it...
Here's my code for auto generating nodes (in override func didMoveToView(view: SKView):
for Character in englishWord{
// Make letters:
let letterToMove = SKSpriteNode(imageNamed: "\(Character)")
//then setting size and position
var physicsBodyLetterToMove = SKPhysicsBody(rectangleOfSize: letterToMove.size)
physicsBodyLetterToMove.affectedByGravity = false
physicsBodyLetterToMove.allowsRotation = false
physicsBodyLetterToMove.dynamic = false
letterToMove.physicsBody = physicsBodyLetterToMove
self.addChild(letterToMove)
// Make empty boxes for the letters:
let letterRecBox = SKSpriteNode(imageNamed: "EmptyBox")
//then setting size and position
var physicsBodyLetterRecBox = SKPhysicsBody(rectangleOfSize: letterRecBox.size)
physicsBodyLetterToMove.affectedByGravity = false
physicsBodyLetterRecBox.dynamic = false
letterRecBox.physicsBody = physicsBodyLetterRecBox
self.addChild(letterRecBox)
}
So the touches func's:
var selected: [UITouch: SKNode] = [:]
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
selected = [:]
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
selected[touch as UITouch] = nodeAtPoint(location)
}
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
for (touch, node) in selected{
if !contains([self], node){
let action = SKAction.moveTo(location, duration: 0.1)
node.runAction(SKAction.repeatAction(action, count: 1))
}
}
}
}
Any idea?
Setting dynamic to false will make the node unaffected by physics. SKActions and touch events are not considered physics so they will still affect your nodes that are not dynamic.
You could do something like:
YourSpriteNode.name = #"staticNode"; //Right after you create it
Then alter your touch method:
for (touch, node) in selected{
if !contains([self], node){
if(![node.name isEqualToString:#"staticNode"])
{
let action = SKAction.moveTo(location, duration: 0.1)
node.runAction(SKAction.repeatAction(action, count: 1))
}
}
}
The newly introduced if statement will prevent any node named "staticNode" from getting moved due to your SKActions. Other nodes will move as expected.
Thanx, that worked.
Only, I had to write it like this:
letterRecBox.name = "staticNode"
...
if !(node.name == "staticNode"){
...then do something...
}