I'm trying to paint the stroke color in black, but it doesn't appear any line...
This is how it's displayed in the iOS simulator:
BUT, if I run the same code in the Xcode playground, the circle is perfect
My scene code:
import SpriteKit
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.backgroundColor = UIColor.whiteColor()
let midcir = self.mainCircle()
self.addChild(midcir)
}
func mainCircle()->SKSpriteNode{
let node = SKSpriteNode()
node.anchorPoint=CGPoint(x: 0.5, y: 0.5)
let outsideNode = SKShapeNode(circleOfRadius: 127.5)
let insideNode = SKShapeNode(circleOfRadius: 1)
outsideNode.strokeColor = UIColor.blackColor()
outsideNode.fillColor = UIColor.blueColor()
outsideNode.lineWidth = 5
insideNode.strokeColor = UIColor.clearColor()
insideNode.fillColor = UIColor.clearColor()
node.addChild(outsideNode)
node.addChild(insideNode)
node.position = CGPoint(x: CGRectGetMidX(self.frame), y: CGRectGetMidY(self.frame))
return node
}
}
And the playground code, it's for OS X for live view incompatibilities (live view):
It only changes the UIColor for NSColor
import XCPlayground
import Cocoa
import SpriteKit
var myView = SKView(frame: NSRect(x: 0, y: 0, width: 400, height: 400))
var myScene = SKScene(size: CGSize(width: 400, height: 400))
myScene.backgroundColor = NSColor.whiteColor()
myView.presentScene(myScene)
func maincircle()->SKSpriteNode{
let node = SKSpriteNode()
node.anchorPoint=CGPoint(x: 0.5, y: 0.5)
let outsideNode = SKShapeNode(circleOfRadius: 127.5)
let insideNode = SKShapeNode(circleOfRadius: 1)
outsideNode.strokeColor = NSColor.blackColor()
outsideNode.fillColor = NSColor.blueColor()
outsideNode.lineWidth = 5
insideNode.strokeColor = NSColor.clearColor()
insideNode.fillColor = NSColor.clearColor()
node.addChild(insideNode)
node.addChild(outsideNode)
node.position = CGPoint(x: 200, y: 200)
return node
}
let node = maincircle()
myScene.addChild(node)
XCPShowView("MainCir", myView)
I don't know that is happening, I'll post the answer if I find it. Thank you!
Related
I'm using Xcode 11.4.1 and Swift 5.2.2, and I am trying cast a shadow using an SKLightNode onto a circular SKSpriteNode.
However, the shadow is cast over the rectangular frame of the SpriteNode rather than the circle image png that I am using.
This is the desired effect
This is what happens
In the first image, I am using a 611x611px circle png while in the second I am using a 612x612 png. I have found that this "corner shadow" happens only when using specific image dimensions to create the SpriteNode.
Specifically, through my testing, square images with size <688px and >601px display no corner shadow, except sizes exactly 612 and 608. I am testing this in a playground but the same problem occurs in a full xcodeproj.
What have I done wrong here? I doubt my code is the issue but here it is:
import PlaygroundSupport
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let background = SKSpriteNode(color: UIColor.blue, size: frame.size)
background.zPosition = 0
background.position = CGPoint(x: frame.midX, y: frame.midY)
background.lightingBitMask = 1
addChild(background)
let light = SKLightNode()
light.zPosition = 100
light.categoryBitMask = 1
light.falloff = 0.5
light.lightColor = UIColor.white
light.position = CGPoint(x: frame.midX, y: frame.midY)
addChild(light)
let sprite = SKSpriteNode(imageNamed: "612.png")
sprite.color = UIColor.yellow
sprite.colorBlendFactor = 1
sprite.zPosition = 3
sprite.position = CGPoint(x: frame.midX, y: frame.midY + 100)
sprite.size = CGSize(width: 100, height: 100)
sprite.physicsBody = SKPhysicsBody(circleOfRadius: 50)
sprite.physicsBody?.categoryBitMask = 2
sprite.shadowCastBitMask = 1
sprite.lightingBitMask = 1
sprite.physicsBody?.isDynamic = false
addChild(sprite)
}
}
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
let scene = GameScene()
scene.scaleMode = .aspectFill
scene.size = sceneView.frame.size
sceneView.presentScene(scene)
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
I'm new to swift 5.
I printed out the self.size.width in GameScene and the result is 677.0
I printed out the self.size.width from another class - lets say Ground and the result is 4002.0
I'm confused, please help.
Thanks a lot.
GameScene.swift:
import SpriteKit
class GameScene: SKScene {
let cam = SKCameraNode()
let bee = SKSpriteNode()
let ground = Ground()
override func didMove(to view: SKView) {
self.anchorPoint = .zero
//self.backgroundColor = UIColor(red: 0.4, green: 0.6, blue: 0.95, alpha: 1.0)
self.camera = cam
self.addingTheFlyingBee()
self.addBackground()
let bee2 = Bee()
bee2.position = CGPoint(x: 325, y: 325)
self.addChild(bee2)
let bee3 = Bee()
bee3.position = CGPoint(x: 200, y: 325)
self.addChild(bee3)
ground.position = CGPoint(x: -self.size.width * 2, y: 0)
ground.size = CGSize(width: self.size.width * 6, height: 0)
ground.createChildren()
self.addChild(ground)
}
override func didSimulatePhysics() {
self.camera!.position = bee.position
}
func addBackground() {
let bg = SKSpriteNode(imageNamed: "background-menu")
bg.position = CGPoint(x: 220, y: 220)
bg.zPosition = -1
self.addChild(bg)
}
func addingTheFlyingBee() {
bee.position = CGPoint(x: 250, y: 250)
bee.size = CGSize(width: 38, height: 34)
self.addChild(bee)
let beeAtlas = SKTextureAtlas(named: "Enemies")
let beeFrames : [SKTexture] = [
beeAtlas.textureNamed("bee"),
beeAtlas.textureNamed("bee-fly")
]
let flyAction = SKAction.animate(with: beeFrames, timePerFrame: 0.14)
let beeAction = SKAction.repeatForever(flyAction)
bee.run(beeAction)
let pathLeft = SKAction.moveBy(x: -200, y: -10, duration: 2)
let pathRight = SKAction.moveBy(x: 200, y: 10, duration: 2)
let flipTextureNegative = SKAction.scaleX(to: -1, duration: 0)
let flipTexturePositive = SKAction.scaleX(to: 1, duration: 0)
let flightOfTheBee = SKAction.sequence([ pathLeft, flipTextureNegative, pathRight, flipTexturePositive])
let neverEndingFlight = SKAction.repeatForever(flightOfTheBee)
bee.run(neverEndingFlight)
}
Ground.swift:
import Foundation
import SpriteKit
class Ground: SKSpriteNode, GameSprite {
var textureAtlas: SKTextureAtlas = SKTextureAtlas(named: "Environment")
var initialSize = CGSize.zero
func createChildren() {
self.anchorPoint = CGPoint(x: 0, y: 1)
let texture = textureAtlas.textureNamed("ground")
var tileCount: CGFloat = 0
let tileSize = CGSize(width: 35, height: 300)
while tileCount * tileSize.width < self.size.width {
let tileNode = SKSpriteNode(texture: texture)
tileNode.size = tileSize
tileNode.position.x = tileCount * tileSize.width
tileNode.anchorPoint = CGPoint(x: 0, y: 1)
self.addChild(tileNode)
tileCount += 1
}
}
func onTap() {}
}
I don't really understand the question. Since your scene width is 677.0px and your ground
width should be 6 * scene width so 4062px.
Is your question "Why is ground node width 4002px instead of 4062px?" or "What is the difference between those properties?"
If you question is the second one then this should be an answer:
SKScene.size.width will return width of the current scene while SKSpriteNode.size.width will return width of the target node in your case "ground" node.
self.size.width will return width of the current class you're editing.
So in GameScene.swift file if you call self.size.width inside a class GameScene: SKScene it will return GameScene width.
In Ground.swift file calling self.size.width inside a class Ground: SKSpriteNode, GameSprite will return Ground width.
I hope this answers your question.
I'm currently trying to get along with the collision handling in Xcode 11 (iOS 13).
My problem is that not even Apple's example code seems to work for me.
(https://developer.apple.com/documentation/spritekit/skphysicsbody/about_collisions_and_contacts)
Example code from Apple:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
let ballRadius: CGFloat = 20
let redBall = SKShapeNode(circleOfRadius: ballRadius)
redBall.fillColor = .red
redBall.position = CGPoint(x: 280, y: 320)
redBall.physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)
let blueBall = SKShapeNode(circleOfRadius: ballRadius)
blueBall.fillColor = .blue
blueBall.position = CGPoint(x: 360, y: 320)
blueBall.physicsBody = SKPhysicsBody(circleOfRadius: ballRadius)
var splinePoints = [CGPoint(x: 0, y: 300),
CGPoint(x: 100, y: 50),
CGPoint(x: 400, y: 110),
CGPoint(x: 640, y: 20)]
let ground = SKShapeNode(splinePoints: &splinePoints,
count: splinePoints.count)
ground.physicsBody = SKPhysicsBody(edgeChainFrom: ground.path!)
ground.physicsBody?.restitution = 0.75
redBall.physicsBody?.collisionBitMask = 0b0001
blueBall.physicsBody?.collisionBitMask = 0b0010
ground.physicsBody?.categoryBitMask = 0b0001
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
When i run the code, both balls collide with the curve.
Is there something I did wrong or is there an updated functionality within SpriteKit I don't know about?
Thanks for your help!
I created a new Xcode project and pasted the code from the question and it eventually worked.
I don't know which of the project files was causing the issue.
Thanks for the help!
When the blue square falls down on the red one a gap will remain. But when I make the blue square fall from a lower position there is no gap. Also when I give the blue square a higher mass the gap (on the ground) under the red square disappears and when the mass is too high the red square is gone.
I also made the squares smaller because the amount of pixels didn't equal the pixels of the png file which led to an even bigger gap. And when I set "showsPhysics" to true there is also a gap to see and even bigger when the squares are not scaled down.
Gap between SKSpriteNodes (picture)
//: Playground - noun: a place where people can play
import UIKit
import SpriteKit
import PlaygroundSupport
class Scene: SKScene {
var square = SKSpriteNode(texture: SKTexture(imageNamed: "red"), size: SKTexture(imageNamed: "red").size())
var square2 = SKSpriteNode(texture: SKTexture(imageNamed: "blue"), size: SKTexture(imageNamed: "blue").size())
var label = SKLabelNode(fontNamed: "Chalkduster")
override func didMove(to view: SKView) {
self.addChild(square)
self.addChild(square2)
self.addChild(label)
}
override func didChangeSize(_ oldSize: CGSize) {
// Add Scene Physics
self.physicsBody?.usesPreciseCollisionDetection = true
self.physicsBody = SKPhysicsBody(edgeLoopFrom: CGRect(x: -1, y: -1, width: self.size.width + 2, height: self.size.height + 2))
self.backgroundColor = UIColor.white
self.physicsBody?.usesPreciseCollisionDetection = true
//Add square
square.texture?.usesMipmaps = true
square.zPosition = 11
square.physicsBody = SKPhysicsBody(rectangleOf: square.size)
square.physicsBody?.usesPreciseCollisionDetection = true
square.physicsBody?.mass = 0.1
square.physicsBody?.allowsRotation = false
square.physicsBody?.usesPreciseCollisionDetection = true
square.setScale(0.25)
square.position = CGPoint(x: self.frame.width / 2, y: self.square.size.height)
square.name = "square"
//Add square2
square2.texture?.usesMipmaps = true
square2.zPosition = 11
square2.physicsBody = SKPhysicsBody(rectangleOf: square2.size)
square2.physicsBody?.usesPreciseCollisionDetection = true
square2.physicsBody?.mass = 0.1
square2.physicsBody?.allowsRotation = false
square2.physicsBody?.usesPreciseCollisionDetection = true
square2.setScale(0.25)
square2.position = CGPoint(x: self.frame.width / 2, y: self.square.size.height * 6)
square2.name = "square2"
//Add label
label.fontSize = 30
label.text = "w: \(self.frame.size.width) h: \(self.frame.size.height)"
label.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height - 30)
label.fontColor = UIColor.black
label.zPosition = 100
}
}
class ViewController: UIViewController {
let scene = Scene()
var viewSize = CGSize(width: 0, height: 0)
override func loadView() {
self.view = SKView()
}
override func viewDidLoad() {
super.viewDidLoad()
if let view = self.view as! SKView? {
view.frame = CGRect(origin: CGPoint(x: -1, y: -1), size: viewSize)
view.presentScene(scene)
view.showsPhysics = false
view.showsFPS = true
view.showsNodeCount = true
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
scene.size = CGSize(width: self.view.frame.size.width, height: self.view.frame.size.height)
}
}
PlaygroundPage.current.liveView = ViewController()
As proof from the print commands, there is no actual gap between the sprite nodes, and with second proof from a super-zoomed-in-screenshot:
The playground you provided does not replicate an issue, which makes me wonder... what is going on with your project?
pg #2:
The scene's width and height has to be multiplied by 2. So the scene has to be 4 times bigger than the ViewControllers view. It's also like that in the game template that Apple provides for Spritekit.
scene.size = CGSize(width: self.view.frame.size.width * 2, height: self.view.frame.size.height * 2)
https://github.com/simon2204/Playground
I'm beginner in Spritekit and I try to make background move vertically
I did know how
this what in the controller
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let scene = GameScene(size: view.bounds.size)
let skView = view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
skView.ignoresSiblingOrder = true
scene.scaleMode = .resizeFill
skView.presentScene(scene)
}
and this the scene
class GameScene: SKScene {
var background = SKSpriteNode()
override func didMove(to view: SKView) {
let backgroundTexture = SKTexture(imageNamed: "bbbgg.png")
let shiftBackground = SKAction.moveBy(x: 0, y: -backgroundTexture.size().height, duration: 5)
let replaceBackground = SKAction.moveBy(x: 0, y:backgroundTexture.size().height, duration: 0)
let movingAndReplacingBackground = SKAction.repeatForever(SKAction.sequence([shiftBackground,replaceBackground]))
for i in 1...3{
background=SKSpriteNode(texture:backgroundTexture)
background.position = CGPoint(x: 0, y: 0)
background.size.height = self.frame.height
background.run(movingAndReplacingBackground)
self.addChild(background)
}
}
}
the problem is the background move horizontally and after it arrives to the end of screen disappear, then begins move from the beginning of the screen again
I want it work vertically without disappearing
The background move horizontally because declarations of moveBy (shiftBackground, replaceBackground) works on the x axe (horizontally). You need to work on the y axe (vertically).
let shiftBackground = SKAction.moveBy(x: 0, y: -backgroundTexture.size().height, duration: 5)
let replaceBackground = SKAction.moveBy(x: 0, y: backgroundTexture.size().height, duration: 0)
At the first line, the background move from it position to it position - it height. At the second line, it return to it first position (I think moveBy is relative).
_
The background move again because you use the function SKAction.repeatForever (movingAndReplacingBackground). I think you can remove it.
let movingAndReplacingBackground = SKAction.sequence([shiftBackground,replaceBackground])
Edit :
I forget the loop.
In the loop, you give to the background an initial position.
background.position = CGPoint(x: backgroundTexture.size().width/2 + (backgroundTexture.size().width * CGFloat(i)), y: self.frame.midY)
Try to replace it by 0, middle if you want an immediately visible background
background.position = CGPoint(x: 0, y: self.frame.midY)
Or -height, 0 if you want the background appear by the top of the screen. In this case you need to replace shiftBackground and replaceBackground
background.position = CGPoint(x: -backgroundTexture.size().height, y: 0)
and
let shiftBackground = SKAction.moveBy(x: 0, y: backgroundTexture.size().height, duration: 5)
let replaceBackground = SKAction.moveBy(x: 0, y: 0, duration: 0)
I'm not sure, but I think, if you want only one mouvement, you can remove th sequence :
class GameScene: SKScene {
var background = SKSpriteNode()
override func didMove(to view: SKView) {
let backgroundTexture = SKTexture(imageNamed: "bbbgg.png")
let scrollByTopBackground = SKAction.moveBy(x: O, y: backgroundTexture.size().height, duration: 5)
background = SKSpriteNode(texture:backgroundTexture)
background.position = CGPoint(x: -backgroundTexture.size().height, y: self.frame.midY)
background.size.height = self.frame.height
background.run(scrollByTopBackground)
self.addChild(background)
}
}
Edit to answer you, try this...
class GameScene: SKScene {
var background = SKSpriteNode()
override func didMove(to view: SKView) {
let backgroundTexture = SKTexture(imageNamed: "bbbgg.png")
let shiftBackground = SKAction.moveBy(x: 0, y: -backgroundTexture.size().height, duration: 5)
let replaceBackground = SKAction.moveBy(x: 0, y:backgroundTexture.size().height, duration: 0)
let movingAndReplacingBackground = SKAction.repeatForever(SKAction.sequence([shiftBackground,replaceBackground]))
for i in 0...2 {
background=SKSpriteNode(texture:backgroundTexture)
background.position = CGPoint(x: 0, y: self.frame.midY + (backgroundTexture.size().height * CGFloat(i)))
background.size.height = self.frame.height
background.run(movingAndReplacingBackground)
self.addChild(background)
}
}