Node's path particle effect with SpriteKit - swift

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.

Related

Sprite Nodes Phasing

I am trying to make a maze app. The goal is to move a ball (drag the ball with your finger) through a "maze" like level which has traps and other dangers. However, when I made it so the ball/player moves when its dragged, it started to now phase though the other sprite nodes instead of staying inside of the level. How can I make it so it doesn't go outside of the level?
Code:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKSpriteNode()
var danger1 = SKSpriteNode()
var danger2 = SKSpriteNode()
var goal = SKSpriteNode()
override func didMove(to view: SKView) {
ball = self.childNode(withName: "ball") as! SKSpriteNode
danger1 = self.childNode(withName: "danger1") as! SKSpriteNode
danger2 = self.childNode(withName: "danger2") as! SKSpriteNode
goal = self.childNode(withName: "goal") as! SKSpriteNode
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 0
print("x: \(ball.position.x), y: \(ball.position.y)")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
ball.position.x = location.x
ball.position.y = location.y
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
Screenshot of game:
Maze Level
You need to set up a collisionBitMask for your nodes and set up your desired collision rules accordingly (i.e. prevent ball from clipping through the maze walls or dangers):
I'd recommend looking at the corresponding apple developer docs: https://developer.apple.com/documentation/spritekit/skphysicsbody/1520003-collisionbitmask
This other question's answer may also prove helpful: What are Sprite Kit's "Category Mask" and "Collision Mask"?
This was also a video that I found helpful when learning about bitmasks for detecting collisions & contact between SKSpriteNodes: https://youtu.be/467Doas5J6I?t=1114
*Edit*
You will also need to set up contact detection via contactTestBitMask so that you know when the ball has contacted the wall, at which point you can implement logic to ‘drop’ it from the dragging gesture. As #Steve Ives correctly noted, the dragging will override the collision physics and you would still get clipping without this.
Your major problem is you are moving your ball directly, ala hand of god.
What you need to do is play by the systems rules. Instead of applying the position directly, set the velocity of your ball to push your ball to where your finger is. This requires some math:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
//set the location's coordinate system to match the ball
let location = touch.location(in: ball.parent)
let angle = atan2(location.x,location.y)
let velocity = 1.0f //(change this to whatever speed you want your ball to move at)
ball.velocity = CGVector(velocity * cos(angle),velocity * sin(angle)) // you may have to swap around the sin/-sin/cos/-cos to get it the way you like it, I am assuming at angle 0 your ball is facing right, and it rotates in a counter clockwise direction)
}
}
Now your ball will forever be pushed towards the touching point.
To avoid bouncing, make sure you set the restitution to 0 on the physics body so that it loses all of its energy when it hits a wall.
Also check categoryBitmask is of some power of 2 on all objects that require physics (1 works in your example) so that it can collide with whatever is in its way

Sprite won't move with finger/ SpriteKit / Swift 3

*I searched most places and could not find a "basic solution" to my question
Hi there, I am trying to create a simple SKSpriteNode that will move along with my finger anywhere on the screen (x & y coords). So far what I have done is the code below, and I can't seem to figure out much else because my Sprite won't even move when the game is ran. I am also getting an error at:
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
This line of code causes my program to not run since I've added it. Please and thanks for your help.
In this case Sprite "simpleS" is the Sprite I am trying to move when touches begin.
CODE STARTS HERE:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var simpleS = SKSpriteNode()
override func didMove(to view: SKView) {
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
simpleS.physicsBody?.affectedByGravity = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
simpleS.run(SKAction.moveTo(x: location.x, duration: 0.0))
simpleS.run(SKAction.moveTo(y: location.y, duration: 0.0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
simpleS.run(SKAction.moveTo(x: location.x, duration: 0.0))
simpleS.run(SKAction.moveTo(y: location.y, duration: 0.0))
}
}
}
this code
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
connects the sprites in your GameScene.sks with GameScene.swift
so in the first step you have to make sure that you set the right name (exactly "simpleS") in your sks file.
if you did it right, so please send the error for us.
i have built and ran your code and everything works in a right way.
another point is that if you want your sprites only moves by your finger movement you have to delete the codes in touchesBegan function, because touchesBegan moves your sprite wherever you touch.

Why my node is invisible

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.

SpriteKit Gravity

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

swift moving and releasing object with touch

I'm new to coding. I have created a scene in swift sprite kit with a ball and floor. When executed, the ball drops and bounces on the floor. I am looking for a bit advise on how to move and drop the ball with touches.
To detect drag ball you have to create UIPanGestureRecognizer and add it to the ball's view
let dragBall = UIPanGestureRecognizer(target: self, action:"dragBall:")
ball.addGestureRecognizer(dragBall)
Next step is implementing "dragBall" function which will handle drag event, example:
#IBAction func dragBall(recognizer: UIPanGestureRecognizer) {
let point = recognizer.locationInView(self.view);
ball.center.x=point.x
ball.center.y=point.y
}
You should also disable gravity for this object for time of dragging, you can check if Pan gesture ended by checking state of gesture recognizer, if state is UIGestureRecognizerStateEnded you should add gravity again
import SpriteKit
class GameScene: SKScene {
let ball = SKSpriteNode(imageNamed: "ball")
override func didMoveToView(view: SKView) {
/* Setup your scene here */
ball.position = CGPoint(x:500,y:500)
ball.anchorPoint = CGPoint(x:0.0,y:0.0)
ball.size = CGSize(width: 60, height: 60)
// physics
ball.physicsBody = SKPhysicsBody(circleOfRadius: 1)
// this defines the mass, roughness and bounciness
ball.physicsBody.friction = 0.2
ball.physicsBody.restitution = 0.8
ball.physicsBody.mass = 0.1
// this will allow the balls to rotate when bouncing off each other
ball.physicsBody.allowsRotation = true
self.addChild(ball)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent)
{ ball.position = touches.anyObject().locationInNode(self); }
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
by the end of the day i worked out this bit of code but it seems very hard to keep hold of ball