My issue is similar to this questions (physics body not inline with shape?) except setting the center doesn't help. I've played around with it a bunch but I can't get the physics body to stay wrapped about the circle.
First issue in the first video.
Similar/new problem in second video
Here's my code for set up:
let sprite = SKSpriteNode(imageNamed: "smileyEmoji")
sprite.size = CGSize(width: 45, height: 45)
sprite.name = "player"
sprite.zPosition = 3
player.addChild(sprite)
player.position = CGPoint(x:85, y:140)
player.physicsBody?.isDynamic = false
player.physicsBody?.allowsRotation = true
player.physicsBody?.restitution = 0.7
player.physicsBody?.friction = 0.0
player.physicsBody?.angularDamping = 0.0
player.physicsBody?.linearDamping = 0.0
player.physicsBody?.usesPreciseCollisionDetection = true
player.physicsBody?.categoryBitMask = PhysicsCategory.CollisionCategoryPlayer
player.physicsBody?.collisionBitMask = PhysicsCategory.CollisionCategoryPlatform | PhysicsCategory.CollisionCategoryPoint
player.physicsBody?.contactTestBitMask = PhysicsCategory.CollisionCategoryPoint | PhysicsCategory.CollisionCategoryDevil
After springing:
player.physicsBody = SKPhysicsBody(circleOfRadius: (self.player.childNode(withName: "player") as! SKSpriteNode).size.width/2, center: CGPoint(x: 0, y: 0.0))
player.physicsBody?.isDynamic = true
Related
It's my very first post in coding forum - it means i'm REEAAAAALLLY stuck (I've searched everywhere and tested many options).
Creating a simple bouncing ball on my ipad screen, coding the app using SpriteKit.
The below code prevent the ball to move at all BUT when i remove the SKPhysicsBody created out the frame.edge : the ball falls.
I've got the feeling that the self.physicsBody is ultimately made as a volume despite I ask it to be made from an edge...
Can you please help ?
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0,dy: -6)
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame) // ball's cage
self.physicsBody?.friction = 0;
let fbound = SKShapeNode(rect: self.frame)
fbound.lineWidth = 1
fbound.strokeColor = .red
addChild(fbound)
let path = CGMutablePath()
path.addArc(center: CGPoint(x: view.bounds.width / 2, y: view.bounds.height / 2),
radius: 15,
startAngle: 0,
endAngle: CGFloat.pi * 2,
clockwise: true)
let ball = SKShapeNode(path: path)
ball.lineWidth = 1
ball.fillColor = .red
ball.strokeColor = .black
ball.glowWidth = 0.5
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.frame.size.width/2)
ball.physicsBody?.friction = 0
ball.physicsBody?.restitution = 1
ball.physicsBody?.mass = 0.6
ball.physicsBody?.linearDamping = 0
ball.physicsBody?.allowsRotation = false
ball.physicsBody?.isDynamic = true
addChild(ball)
}
Please let me know if you need more details
Thanks a mil in advance
Rgds
MainPlayer is the main ball in the center, and I want the blue enemy nodes to spawn randomly on each side, but they are all appearing in the top right. I am pretty sure this code is correct, and I cannot get it to work. It seems like they are spawning in the right place, but it is just scaled to the top right for some reason.
func Enemies() {
let xPos = randomBetweenNumbers(firstNum: 0, secondNum: frame.width )
let Enemy = SKSpriteNode(imageNamed: "Ball")
Enemy.zPosition = -1.0
Enemy.size = CGSize(width: 20.0, height: 20.0)
Enemy.physicsBody?.categoryBitMask = PhysicsCategory.Enemy
Enemy.physicsBody?.contactTestBitMask = PhysicsCategory.Smallball | PhysicsCategory.MainBall
Enemy.physicsBody?.collisionBitMask = PhysicsCategory.Smallball | PhysicsCategory.MainBall
let randomNumber = arc4random() % 4 + 1
switch randomNumber {
case 0:
Enemy.position.x = 0
var positionY = arc4random_uniform(UInt32(frame.size.height))
Enemy.position.y = CGFloat(positionY)
self.addChild(Enemy)
break
case 1:
Enemy.position.y = 0
var positionX = arc4random_uniform(UInt32(frame.size.width))
Enemy.position.x = CGFloat(positionX)
self.addChild(Enemy)
break
case 2:
Enemy.position.y = frame.size.height
var positionX = arc4random_uniform(UInt32(frame.size.width))
Enemy.position.x = CGFloat(positionX)
self.addChild(Enemy)
break
case 3:
Enemy.position.x = frame.size.width
var positionY = arc4random_uniform(UInt32(frame.size.height))
Enemy.position.y = CGFloat(positionY)
self.addChild(Enemy)
break
default:
break
}
Enemy.position = CGPoint(x: CGFloat(xPos), y: self.frame.size.height / 2)
Enemy.physicsBody = SKPhysicsBody(circleOfRadius: 7)
Enemy.physicsBody?.affectedByGravity = false
Enemy.physicsBody?.categoryBitMask = 0
Enemy.physicsBody?.contactTestBitMask = 1
addChild(Enemy)
Enemy.run(SKAction.move(to: MainPlayer.position, duration: 3))
}
This is the result of my code, and obviously, I just let it spawn instead of move to the ball because I wanted to show the weird spawning locations.
try this:
let Enemy = SKSpriteNode(imageNamed: "Ball")
Enemy.zPosition = -1.0
Enemy.size = CGSize(width: 20.0, height: 20.0)
Enemy.physicsBody?.categoryBitMask = PhysicsCategory.Enemy
Enemy.physicsBody?.contactTestBitMask = PhysicsCategory.Smallball | PhysicsCategory.MainBall
Enemy.physicsBody?.collisionBitMask = PhysicsCategory.Smallball | PhysicsCategory.MainBall
Enemy.physicsBody?.affectedByGravity = false
Enemy.physicsBody?.isDynamic = true
Remove the code after break except Enemy.run(SKAction.move(to: MainPlayer.position, duration: 3))
Also, try removing the +1 after arc4random
So I am using 3 SKSpriteNode's in my application. floorSprite, leftWall and rightWall.
This is the code I am currently using:
let floorSprite = SKSpriteNode()//(imageNamed: "floor")
floorSprite.alpha = 0.0
floorSprite.anchorPoint = CGPoint(x: 0.5, y: CGPoint.zero.y)
floorSprite.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: self.frame.size.width, height: floorSprite.size.height + 12))
floorSprite.physicsBody?.isDynamic = false
floorSprite.physicsBody?.restitution = 0.4
floorSprite.position = CGPoint(x: self.frame.minX, y: self.frame.minY + (floorSprite.size.height / 2))
floorSprite.physicsBody?.contactTestBitMask = 0x1 << 1
floorSprite.physicsBody?.collisionBitMask = 0x1 << 1
floorSprite.zPosition = 4
floorSprite.aspectFillToSize(self.frame.size)
self.addChild(floorSprite)
self.floorSprite = floorSprite
let leftwall = SKSpriteNode()
leftwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
leftwall.physicsBody?.collisionBitMask = 0x1 << 1
leftwall.physicsBody?.isDynamic = false
leftwall.position = CGPoint(x: 0 , y: self.frame.size.height / 2.0)
leftwall.zPosition = 4
leftwall.physicsBody?.restitution = 1.0
self.addChild(leftwall)
let rightwall = SKSpriteNode()
rightwall.physicsBody = SKPhysicsBody(rectangleOf: CGSize(width: 0.1, height: self.frame.size.height*2))
rightwall.physicsBody?.collisionBitMask = 0x1 << 1
rightwall.physicsBody?.isDynamic = false
rightwall.physicsBody?.restitution = 1.0
rightwall.position = CGPoint(x: self.frame.size.width , y: self.frame.size.height / 2.0)
rightwall.zPosition = 4
self.addChild(rightwall)
Here is a screenshot of the issue I have. You can see the light blue lines that shows. If I remove the self.addChild line, the Sprite is not there, and the light blue color gone.
CLICK HERE FOR IMAGE.
Any ideas what might be wrong here? I have tried adding leftWall.isHidden = true and leftWall.alpha = 0.0 but that has no effect...
This looks like you have SKScene.showPhysics on.. turn this off in your appdelegate (or didmovetoview) or wherever you turned it on, and the lines should go away.
These are caused by your physics bodies :)
I'm trying to create a scenario where there's a radial gravity field. In this scene, there's also an object built by two physics bodies with a different mass.
When I run this code, the radial gravity field is created correctly and the body goes to gravityCenter.
I'm expecting that the body rotates too because the head is heavier than the tail but this doesn't happend.
Why?
class GameScene: SKScene {
let object = SKSpriteNode(imageNamed: "myobj")
let myCategory : UInt32 = 0x1 << 0
override func didMove(to view: SKView) {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
let gravityCenter = SKFieldNode.radialGravityField()
gravityCenter.isEnabled = true
gravityCenter.position = CGPoint(x: size.width, y: size.height * 0.5)
gravityCenter.strength = 0.5
addChild(gravityCenter)
object.position = CGPoint(x: size.width * 0.1, y: size.height * 0.9)
object.scale(to: CGSize(width: 100, height: 25))
let head = SKPhysicsBody(circleOfRadius: object.size.width/5, center: CGPoint(x: object.size.width/2, y: 0))
let tail = SKPhysicsBody(circleOfRadius: object.size.width/50, center: CGPoint(x: -object.size.width/2, y: 0))
head.mass = 500
head.categoryBitMask = myCategory
head.allowsRotation = true
head.isDynamic = true
head.angularDamping = 0
head.affectedByGravity = true
tail.mass = 2
tail.categoryBitMask = myCategory
tail.allowsRotation = true
tail.isDynamic = true
tail.angularDamping = 0
tail.affectedByGravity = true
object.physicsBody = SKPhysicsBody(bodies: [head, tail])
object.physicsBody?.categoryBitMask = myCategory
object.physicsBody?.allowsRotation = true
object.physicsBody?.isDynamic = true
object.physicsBody?.angularDamping = 0
object.physicsBody?.affectedByGravity = true
addChild(object)
}
}
Well, from a physics standpoint SpriteKit is behaving correctly. If you think about it, more mass does mean more gravitational force, but it also means more inertia, which exactly cancels out the increased force. Perhaps introduce a little bit of linearDamping into the tail? That would get the body to rotate by making the head drag the tail a little bit.
I just created a very basic scene in SpriteKit and first problem just appeared.
When two SKShapeNode get in contact, the player node is overlapping the ground node, I can't see why.
Here is my code and a screenshot:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var contentCreated = false
var player: SKShapeNode?
override func didMoveToView(view: SKView) {
if !contentCreated {
createSceneContents()
contentCreated = true
}
}
func createSceneContents() {
self.backgroundColor = SKColor(white: 1.0, alpha: 1.0)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsWorld.gravity = CGVectorMake(0, -10)
self.physicsWorld.contactDelegate = self
let groundCategory: UInt32 = 0x1 << 0
let playerCategory: UInt32 = 0x1 << 0
let ground = SKShapeNode(rect: CGRectMake(0, 0, self.frame.width, 50))
ground.fillColor = UIColor.blueColor()
ground.lineWidth = 0
ground.position = CGPoint(x: 0, y: 0)
ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.frame.size)
ground.physicsBody?.dynamic = false
ground.physicsBody?.categoryBitMask = groundCategory
ground.physicsBody?.collisionBitMask = groundCategory
ground.physicsBody?.contactTestBitMask = groundCategory
self.addChild(ground)
player = SKShapeNode(rect: CGRectMake(0, 0, 30, 30))
player?.fillColor = UIColor.blackColor()
player?.lineWidth = 0
player?.position = CGPoint(x: 20, y: 400)
player?.physicsBody = SKPhysicsBody(rectangleOfSize: player!.frame.size)
player?.physicsBody?.mass = 1.0
player?.physicsBody?.categoryBitMask = playerCategory
player?.physicsBody?.collisionBitMask = playerCategory
player?.physicsBody?.contactTestBitMask = playerCategory
self.addChild(player!)
}
}
Thanks.
You might want to have a different bitmask for your ground and player :
let groundCategory: UInt32 = 0x1
let playerCategory: UInt32 = 0x1 << 1
Then you might also want to set the collision / contact bitmask differently :
ground.physicsBody?.categoryBitMask = groundCategory
ground.physicsBody?.collisionBitMask = playerCategory
ground.physicsBody?.contactTestBitMask = playerCategory
player?.physicsBody?.categoryBitMask = playerCategory
player?.physicsBody?.collisionBitMask = groundCategory
player?.physicsBody?.contactTestBitMask = groundCategory
Even so, you'll have something like you already have. However if you turn on the showPhysics (as suggested by #Skoua) :
You can see that the physics body is attached to the bottom left anchor point.
Here is how to fix that :
func createSceneContents() {
self.backgroundColor = SKColor(white: 1.0, alpha: 1.0)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsWorld.gravity = CGVectorMake(0, -10)
self.physicsWorld.contactDelegate = self
let groundCategory: UInt32 = 0x1
let playerCategory: UInt32 = 0x1 << 1
let ground = SKShapeNode(rectOfSize: CGSize(width: self.frame.width, height: 50)) // HERE
ground.fillColor = UIColor.blueColor()
ground.lineWidth = 0
ground.position = CGPoint(x: ground.frame.size.width/2, y: ground.frame.size.height/2) // HERE
ground.physicsBody = SKPhysicsBody(rectangleOfSize: ground.frame.size)
ground.physicsBody?.dynamic = false
ground.physicsBody?.categoryBitMask = groundCategory
ground.physicsBody?.collisionBitMask = playerCategory
ground.physicsBody?.contactTestBitMask = playerCategory
self.addChild(ground)
player = SKShapeNode(rectOfSize: CGSize(width: 30, height: 30)) // HERE
player?.fillColor = UIColor.blackColor()
player?.lineWidth = 0
player?.position = CGPoint(x: 20, y: 400)
player?.physicsBody = SKPhysicsBody(rectangleOfSize: player!.frame.size)
player?.physicsBody?.mass = 1.0
player?.physicsBody?.categoryBitMask = playerCategory
player?.physicsBody?.collisionBitMask = groundCategory
player?.physicsBody?.contactTestBitMask = groundCategory
self.addChild(player!)
}
Don't forget, when placing your node, that the default anchor point is the bottom left of the scene.