PhysicsBody covers half of sprite - sprite-kit

PhysicsBody added only to half of a sprite
I have add a sprite to a GameScene and set a Body type in Physics Definitions to Alpha mask.
Then I want to check if I've clicked on physics body or not.
But, it shows yes only when I click on green area.
override func didMove(to view: SKView) {
let texture = SKTexture(imageNamed: "walking_walking_2")
let wallS = SKSpriteNode (texture: texture)
wallS.physicsBody = SKPhysicsBody(texture: texture, size: texture.size())
wallS.physicsBody?.isDynamic = false
self.addChild(wallS)
view.showsPhysics = true
}
override func touchesBegan (_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches {
touchLocation = t.location(in: self)
let touchedNode = physicsWorld.body(at: touchLocation!)
if (touchedNode?.categoryBitMask == 1)
{
print("yes")
} else {
print ("no")
}
}
}

Related

Move sprite with velocity to follow finger

Is there a way to use velocity to make a sprite follow your finger? I want a sprite to follow my finger but I don't want it to be drag and drop. I want it to be able to interact with other sprite with the delegate properties.
For example: I want a ball to reset when it hits a wall.
I have the code set up to reset the ball. When the ball hits the wall, it doesn't reset. I put in a print statement to see if its registering the collisions. When the ball hits the wall, it prints the statement.
Thats a problem with how I'm making the ball move, right?
Or could there be an error with my code.
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) {
physicsWorld.contactDelegate = self
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(rectangleOf: danger1.size)
danger1.physicsBody?.categoryBitMask = PhysicsCategories.dangerCategory
danger1.physicsBody?.isDynamic = false
danger2.physicsBody = SKPhysicsBody(rectangleOf: danger2.size)
danger2.physicsBody?.categoryBitMask = PhysicsCategories.dangerCategory
danger2.physicsBody?.isDynamic = false
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width/2)
ball.physicsBody?.categoryBitMask = PhysicsCategories.ballCategory
ball.physicsBody?.contactTestBitMask = PhysicsCategories.dangerCategory | PhysicsCategories.goalCategory
ball.physicsBody?.collisionBitMask = PhysicsCategories.none
ball.physicsBody?.isDynamic = true
ball.physicsBody!.affectedByGravity = false
goal.physicsBody = SKPhysicsBody(rectangleOf: goal.size)
goal.physicsBody?.categoryBitMask = PhysicsCategories.goalCategory
goal.physicsBody?.isDynamic = false
setupPhysics()
startGame()
}
func setupPhysics() {
physicsWorld.gravity = CGVector(dx: 0.0, dy: 0.0)
physicsWorld.contactDelegate = self
}
func startGame() {
ball.position = CGPoint(x: 0, y: 550)
}
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
}
}
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
if contactMask == PhysicsCategories.ballCategory | PhysicsCategories.dangerCategory {
print("Contact")
} else if contactMask == PhysicsCategories.ballCategory | PhysicsCategories.goalCategory {
print("goal contact")
}
}
}
As you mentioned, you should use velocity instead of position.
You have to apply the difference of the positions. In order to make it a bit smoother, you should also apply weight to your velocity.
This has not been tested and looks more like pseudo code, but that's what you should do basically.
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let destination = touch.location(in: self)
let position = ball.position
let direction = destination - position // the vector of the difference
let weight = 0.95 // 0.0 to 1.0
ball.velocity = CGVector(direction * weight) // multiply the vector by the weight
}
}
You should do this in a loop that runs every frame and use a flag to see if there's a finger touching the screen, because it doesn't apply velocity when you touch the screen but don't move your finger.

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!

sprite nodes on touch first one only takes physics body

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

How create movement buttons left/right?

Please help. I am a beginner on Swift. I've added sprites for player and left/right buttons. But how can I add an action for every button and apply these actions to the player?
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var player: SKSpriteNode!
var leftMove: SKSpriteNode!
var rightMove: SKSpriteNode!
override func didMoveToView(view: SKView) {
player = SKSpriteNode (imageNamed: "player")
player.position = CGPoint(x:127, y:125)
addChild(player)
leftMove = SKSpriteNode (imageNamed: "leftMove")
leftMove.position = CGPoint(x:80, y:35)
leftMove.size = CGSize (width: 55, height: 55)
addChild(leftMove)
rightMove = SKSpriteNode (imageNamed: "rightMove")
rightMove.position = CGPoint(x:160, y:35)
rightMove.size = CGSize (width: 55, height: 55)
addChild(rightMove)
physicsWorld.contactDelegate = self
}
Give the buttons a unique name like:
leftMove.name = "Left"
rightMove.name = "Right"
Implement the logic in touchesBegan:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
for touch: AnyObject in touches {
let location = touch.locationInNode(self)
let node = self.nodeAtPoint(location)
if (node.name == "Left") {
// Implement your logic for left button touch here:
player.position = CGPoint(x:player.position.x-1, y:player.position.y)
} else if (node.name == "Right") {
// Implement your logic for right button touch here:
player.position = CGPoint(x:player.position.x+1, y:player.position.y)
}
}
}
Welcome to StackOverflow. My recommendation is that for each button that you would like to have actions on, that you subclass SKSpriteNode for those objects. This way you can leverage the touchesBegan:, touchesMoved: and touchesEnded: functions for each of these objects individually. For example:
As promised, here is a more robust version of a subclassed SKSpriteNode. Also, I tested it in one of my projects and I can attest to it working correctly:
import Foundation
import SpriteKit
class SubclassedSKSpriteNode: SKSpriteNode {
init() {
let texture = SKTexture(imageNamed: "whateverImage.png")
super.init(texture: texture, color: UIColor.clearColor(), size: texture.size())
userInteractionEnabled = true
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
let location = (touches.first! ).locationInNode(scene!)
position = scene!.convertPoint(location, toNode: parent!)
print("touchesBegan: \(location)")
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
let location = (touches.first! ).locationInNode(scene!)
position = scene!.convertPoint(location, toNode: parent!)
print("touchesMoved: \(location)")
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let location = (touches.first! ).locationInNode(scene!)
position = scene!.convertPoint(location, toNode: parent!)
print("touchesEnded: \(location)")
}
}
Also, to add this button to your SKScene (or any other SKNode):
let button = SubclassedSKSpriteNode()
button.position = CGPointMake(420, 300)
addChild(button)
HTH!

How to detect GameScene touches from another file using swift

I am currently making a game in sprite kit. In the game, there are random shapes and objects on the ground that you can pick up and rotate and stack on to one another to build up to a target height. Once the target height is reached you move on to the next level. Each object and shape is created in a swift file separate from the GameScene under the SKNode class. I am able to pick the object up and move it around on the screen using the touchesBegan, moved, and ended methods in the node. While I'm holding on to the object I would like to be able to tap and hold the screen with a second finger anywhere on the screen that rotates the object until the finger is let go, so, the first finger grabs and hold the object while the other finger rotates it. The problem is that I have found it almost impossible for the SKNode to detect a touch outside of the actual node. Below is the code I have used for the SKNode. Any advice or suggestions would be greatly appreciated, thank you.
import UIKit
import SpriteKit
class GameObjects: SKNode {
var object: SKSpriteNode
var action: () -> Void
init(objectImage: String, buttonAction: () -> Void ){
object = SKSpriteNode(imageNamed: objectImage)
action = buttonAction
let object1Texture = SKTexture(imageNamed: "object1")
object1Texture.filteringMode = SKTextureFilteringMode.Nearest
let size = CGSize(width: 100, height: 100)
object.physicsBody = SKPhysicsBody(texture: object1Texture, size: size)
object.physicsBody?.dynamic = true
object.physicsBody?.allowsRotation = true
object.physicsBody?.affectedByGravity = true
super.init()
userInteractionEnabled = true
addChild(object)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location: CGPoint = touch.locationInNode(self)
let moveUp = SKAction.moveToY(location.y + 200, duration: 0.05)
object.runAction( moveUp)
}
object.physicsBody?.dynamic = false
object.physicsBody?.affectedByGravity = false
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location: CGPoint = touch.locationInNode(self)
object.physicsBody?.allowsRotation = true
object.physicsBody?.dynamic = true
object.position.x = location.x
object.position.y = location.y + 200
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
object.physicsBody?.dynamic = true
object.physicsBody?.affectedByGravity = true
}
}