sprite nodes on touch first one only takes physics body - swift

I am using Xcode 8.1 Swift 3 to make small bouncing game.
The player is supposed to create walls around a bouncing ball and this ball is supposed to bounce on each wall.
On touch down, I move to point and on touch ended, I create a line share node between the two touches began and end.
I added the physics that were needed to my node, then I added child to this node (see my node below).
What happens is that for each touches began and touches ends, 'Swift' draws the line node and attaches it to self but only the first node bounces the ball.
All lines (walls) after the first one is not affecting the ball.
Here is my code the GameScene Swift file:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
// vars lets and nodes
let startingBall = SKShapeNode(circleOfRadius: 10)
let myPath = CGMutablePath()
let ballCategory : UInt32 = 1
let wallCategory : UInt32 = 2
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
myPath.move(to: t.location(in: self))
}
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
myPath.addLine(to: t.location(in: self))
let wallNode = SKShapeNode(path: myPath)
wallNode.lineWidth = 5.0
wallNode.fillColor = SKColor.green
wallNode.strokeColor = SKColor.green
wallNode.physicsBody = SKPhysicsBody(edgeLoopFrom: myPath)
wallNode.physicsBody?.categoryBitMask = wallCategory
self.addChild(wallNode)
}
}
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
self.physicsBody?.categoryBitMask = wallCategory
startingBall.fillColor = SKColor.red
startingBall.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
startingBall.physicsBody = SKPhysicsBody(circleOfRadius: 10)
startingBall.physicsBody?.affectedByGravity = false
startingBall.physicsBody?.isDynamic = true
startingBall.physicsBody?.restitution = 1.0
startingBall.physicsBody?.friction = 0.0
startingBall.physicsBody?.linearDamping = 0.0
startingBall.physicsBody?.angularDamping = 0.0
self.addChild(startingBall)
startingBall.physicsBody?.applyImpulse(CGVector(dx: 3.0, dy: 3.0))
}
}

thanks all i've fixed it
actually mutable path myPath defines line between touch begin and touch end lines to draw shape node only ... while physics edge created for each touch series from node to node ...
in steps
1- i added start point and end point variables
2- pick up start node in touch begin and end node in touch end
3- i set physical body for from point to point start node and end node
1-
var startPoint : CGPoint = CGPoint.zero
var endPoint : CGPoint = CGPoint.zero
2- ..
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
startPoint = t.location(in: self)
myPath.move(to: t.location(in: self))
}
}
endPoint = t.location(in: self)
3- ..
wallNode.physicsBody = SKPhysicsBody(edgeFrom: startPoint, to: endPoint)
for help you can set show physics to true in skiver
skview.showsPhysics = true
thanks

Related

Make sprite move with velocity

I am trying to make a sprite follow my finger using velocity so it doesn't phase through other sprite nodes, or push them around. I just want the sprite node, aka the ball, to simply hit the other sprite node and either bounce off or just simply hit it and sit there until its moved again.
At the moment I am using location based movement:
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
print("x: \(ball.position.x), y: \(ball.position.y)")
}
}
how can I make it so it doesn't move around other sprite nodes and actually reacts with categoryBitMask elements?
I'm new to this whole thing. Hopefully you understand :)
REST OF MY 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
danger1.physicsBody = SKPhysicsBody()
danger1.physicsBody?.categoryBitMask = PhysicsCategories.dangerCategory
danger2.physicsBody = SKPhysicsBody()
danger2.physicsBody?.categoryBitMask = PhysicsCategories.dangerCategory
ball.physicsBody = SKPhysicsBody()
ball.physicsBody?.categoryBitMask = PhysicsCategories.ballCategory
ball.physicsBody?.contactTestBitMask = PhysicsCategories.dangerCategory
ball.physicsBody?.collisionBitMask = PhysicsCategories.none
goal.physicsBody = SKPhysicsBody(circleOfRadius: goal.size.width/2)
goal.physicsBody?.categoryBitMask = PhysicsCategories.goalCategory
danger1.physicsBody?.isDynamic = true
ball.physicsBody?.isDynamic = true
goal.physicsBody?.isDynamic = true
danger2.physicsBody?.isDynamic = true
danger2.physicsBody!.affectedByGravity = false
danger1.physicsBody!.affectedByGravity = false
goal.physicsBody!.affectedByGravity = false
ball.physicsBody!.affectedByGravity = false
setupPhysics()
}
func setupPhysics() {
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
physicsWorld.contactDelegate = self
}
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
print("x: \(ball.position.x), y: \(ball.position.y)")
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if contactMask == PhysicsCategories.ballCategory | PhysicsCategories.dangerCategory {
ball.position = CGPoint(x: 0, y: 550)
} else if contactMask == PhysicsCategories.ballCategory | PhysicsCategories.goalCategory {
print("Goal!")
}
}
}
Try commenting out this line:
ball.physicsBody?.collisionBitMask = PhysicsCategories.none
which prevents the ball from colliding with anything, i.e. it is unaffected by collisions with any object. Note - this does NOT mean that other objects are unaffected by collision with the ball. collision are 2-way - given 2 node A and B, you have to define if A collides with B and if B collides with A. This isn;t necessary for contact - it's enough to define that A contacts B. If it's actually b that moves into A, didBegin() will still get called. you don't have to define that B contact A also.
You haven't appeared to set the collisionBitMask on any other physics body, which means those will collide with everything.
this explains why the ball moves through the wall - because it isn't colliding with it, although every other object should get pushed around by the ball.
Try putting a:
print("Contact")
as the first line of your didBegin() to see if any contacts are being registered.
If you want to drag sprites with your finger then making them bounce off (collide with) other sprites can be tricky, because dragging implies that you want to set their position manually and bouncing off implies that your want the sprites to be moved by the Sprite-Kit engine and the 2 are not really compatible.
It's probably worth pointing our that 'collisions' are sprites bouncing off each other and are handled by the SK engine. The collisionBitMask controls what objects bounce off each other.
'Contacts' are just a way to get notified when 2 objects touch. They are controlled by the contactTestBitMask.
Both contact and collisions rely on the categoryBitMAsk
My step-by-step guide for collisions and contacts:
https://stackoverflow.com/a/51041474/1430420
And a guide to collision and contactTest bit masks:
https://stackoverflow.com/a/40596890/1430420
Manipulating bit masks to turn individual collision and contacts off and on. https://stackoverflow.com/a/46495864/1430420

How to move sprite relative to its original position with touch in spritekit

I looking to move a sprite relative to the player's touch. I am familiar with the moveTo SKActions, however I am wondering how to implement sprite movement where the sprite moves along with the user's touch movement.
For example, I have a sprite in the centre of the screen. If I apply a touch at the bottom of the screen and move my finger up , the sprite will move up from the centre(it's original position).
Thanks!
Try this :
import SpriteKit
class GameScene: SKScene {
var node = SKSpriteNode()
var nodePosition = CGPoint()
var startTouch = CGPoint()
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
// node set up
node = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
node.position = CGPoint.zero
self.addChild(node)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
startTouch = location
nodePosition = node.position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
node.run(SKAction.move(to: CGPoint(x: nodePosition.x + location.x - startTouch.x, y: nodePosition.y + location.y - startTouch.y), duration: 0.1))
}
}
}

Making my game object bounce forever?

So I am trying to make a ping pong game and I am able to get the ball moving and bouncing but the ball slows down. Whats the code to keep the balls velocity at a constant? Here's what I got:
var ball = SKSpriteNode()
var enemy = SKSpriteNode()
var main = SKSpriteNode()
override func didMove(to view: SKView) {
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width)
ball = self.childNode(withName: "ball") as! SKSpriteNode
enemy = self.childNode(withName: "enemy") as! SKSpriteNode
main = self.childNode(withName: "main") as! SKSpriteNode
ball.physicsBody?.applyImpulse(CGVector(dx: 20, dy: 20))
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.0))
}
}
My physics settings are set to the following:
physics definition
Thanks in advance!

How do I properly add a SKPhysicsBody to a drawn line using SKShapeNode in Spritekit?

I'm creating a game where the user must draw a line to collide with a ball to move it from one location to another. I just can't seem to find a way to put a physics body that collides with another object. The drawn line goes through other objects. I've tried several different SKPhysicBody init's on my shape, and none of them seem to work.
What's the best SKPhysicsBody initializer for a drawn line?
Are my category bit mask correct?
I understand the SkShapeNode can be converted to a SkSpriteNode, but I don't want to do this unless its the only way.
import SpriteKit
import UIKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var lines: [Line] = []
var lastTouch: CGPoint?
var touchLocation: CGPoint!
var linePhysics: CGPoint?
var ballCategory:UInt32 = 0b1
var lineCategory:UInt32 = 0b1 << 1
var goalCategory:UInt32 = 0b1 << 2
var floorCategory:UInt32 = 0b1 << 3
override func didMove(to view: SKView) {
self.physicsWorld.contactDelegate = self
// assigns metal ball that was a color Sprite node, and is now a SKSpriteNode
let metalBall:SKSpriteNode = self.childNode(withName: "ball") as! SKSpriteNode
//assigns physical properties
metalBall.position = CGPoint(x: -150, y: 100)
metalBall.physicsBody? = SKPhysicsBody(circleOfRadius: metalBall.size.width / 2)
metalBall.physicsBody?.affectedByGravity = true
metalBall.physicsBody?.isDynamic = true
metalBall.physicsBody?.categoryBitMask = ballCategory
metalBall.physicsBody?.collisionBitMask = floorCategory | lineCategory
let floor: SKSpriteNode = self.childNode(withName: "floor") as! SKSpriteNode
floor.position = CGPoint (x: 0, y: -76)
floor.physicsBody = SKPhysicsBody(rectangleOf: floor.size)
floor.physicsBody?.affectedByGravity = false
floor.physicsBody?.isDynamic = false
floor.physicsBody?.categoryBitMask = floorCategory
floor.physicsBody?.collisionBitMask = ballCategory
}
/**
* Assigns the first touch location to a variable lastTouch
**/
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let firstTouch = touches.first {
lastTouch = firstTouch.location(in: self)
}
}
/**
* Assigns a path to where the finger touches then adds it to the line array and draws a path using shape nodes
**/
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let firstTouch = touches.first {
touchLocation = firstTouch.location(in: self)
//adds coordinates of lines to the line array
lines.append(Line(start: lastTouch!, end: touchLocation))
lastTouch = touchLocation
}
// path is a changeable variable that assigns a path depending on touch
let path = CGMutablePath()
for line in lines {
path.move(to: CGPoint(x: line.start.x, y: line.start.y))
path.addLine(to: CGPoint(x: line.end.x , y: line.end.y))
}
// colors in the path with ui color black
let shape = SKShapeNode()
shape.path = path
shape.strokeColor = UIColor.black
shape.lineWidth = 2
addChild(shape)
**shape.physicsBody = SKPhysicsBody(edgeChainFrom: shape.path!)**
shape.physicsBody?.affectedByGravity = true
shape.physicsBody?.isDynamic = false
shape.physicsBody?.friction = 1
shape.physicsBody?.restitution = 0.1
shape.physicsBody?.angularDamping = 0.0
shape.physicsBody?.linearDamping = 0
**shape.physicsBody?.categoryBitMask = lineCategory
shape.physicsBody?.collisionBitMask = ballCategory**
}
}

Swift detecting if a SKNode is a property of custom class

Hi I have a custom class, Ship, that has a property 'Parrent' that is an SKNode. When the class is initialized a bunch of nodes are added to that 'Parrent' making up the appearance of the class ship. 'Ship' has a method 'Explode' that shoots all of the nodes in different directions. This part works great, on to my issue.
I am trying to get the Ships to explode when I touch them, but I am having trouble passing which 'Ship' is to explode. Right now when I touch I use nodeAtPoint but this only gets me one of the appearance nodes. From there I need a way to go up a parent to 'Parrent' node and then from there up to Ship object as a whole.
AKA touch->nodeAtPoint->Appearance node->.parrent->'Parrent'->(get stuck here)->Ship->Ship.explode
I hope what is I am trying to accomplish makes sense, thanks for any help.
Ship class:
class Ship: NSObject {
var Position: CGPoint!
var Scene: SKNode!
var Parrent = SKNode();
let Parts = [
SKSpriteNode(imageNamed: "Ship/Ship1.png"),
SKSpriteNode(imageNamed: "Ship/Ship2.png"),
SKSpriteNode(imageNamed: "Ship/Ship3.png"),
SKSpriteNode(imageNamed: "Ship/Ship4.png"),
SKSpriteNode(imageNamed: "Ship/Ship5.png"),
SKSpriteNode(imageNamed: "Ship/Ship6.png"),
];
init(position : CGPoint, parrent : SKNode, scaleFactor: CGFloat) {
self.Position = position;
self.Scene = parrent;
self.Parrent.position = self.Position
var x = 0;
for part in Parts {
x++;
part.xScale = scaleFactor
part.yScale = abs(scaleFactor)
part.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ship/Ship\(x).png"), size: part.size)
part.physicsBody?.collisionBitMask = PhysicsCategory.Ship
part.physicsBody?.categoryBitMask = PhysicsCategory.Something
part.position = CGPoint(x: 0, y: 0)
self.Parrent.addChild(part)
}
self.Scene.addChild(self.Parrent)
}
//other functions including explode
}
Touches began in SKScene
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let targetShip = nodeAtPoint(location)
let targetParrent = targetShip.parent
//decide if it is a 'Ship' here
}
}
Thanks! Id greatly appreciate any help!
This is what finally worked. I changed the ship class to inherit from SKNode and edited touches began as such:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let targetShip = nodeAtPoint(location)
if targetShip.isMemberOfClass(Ship){
print("Ship")
Ship1.shootLazer(targetShip as! Ship)
}else if targetShip.parent!.isMemberOfClass(Ship){
print("Ship parrent")
Ship1.shootLazer(targetShip.parent! as! Ship)
}
}
}