Post not yet marked as solved
Coming back to coding after a break I am now trying to use SpriteKit within SwiftUI
I would like to use the full resolution of the iPad (2160 x 1620) for my Game Scene however the code I have renders the scene beyond the bounds of the screen. It's not scaled properly I suppose is what I mean. It seems the display is still in the 1024x768 size and my scene is rendering beyond the viewable area. Sorry if I am over explaining things here!
This is the code in my ContentView
let screenSize: CGRect = UIScreen.main.nativeBounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
print("Screen width = \(screenWidth), screen height = \(screenHeight)")
let scene = GameScene()
scene.size = CGSize(width: screenWidth, height: screenHeight)
scene.scaleMode = .aspectFit
return scene
}
var body: some View {
let screenSize: CGRect = UIScreen.main.nativeBounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
SpriteView(scene: scene)
.frame(width: screenWidth, height: screenHeight)
}
Post not yet marked as solved
I have an SKSpriteNode with an SKAction being run on it:
theGem!.run(premAction, completion: {theGem!.run(repeatAction)})
Can't seem to find out the proper steps to run another action, such as:
theGem.run(endsequence, completion: {theGem.removeAllActions(); theGem.run(stopAction)})
Should I stop the previous action first?
Is there a way to turn the repeat part off so that the first SKAction ends smoothly?
Post not yet marked as solved
Is there any way to make Xcode's live preview work with Sprite Kit Scenes? Here is my code for reference, I've tried a few different methods of constructing a SKScene but the live preview only displayed a blank scene. The sample scene works as expected when deployed to the simulator.
import SwiftUI
import SpriteKit
class GameScene: SKScene {
override func sceneDidLoad() {
print("scene loaded")
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
let shape = SKShapeNode()
shape.path = UIBezierPath(roundedRect: CGRect(x: -128, y: -128, width: 256, height: 256), cornerRadius: 64).cgPath
shape.position = CGPoint(x: frame.midX, y: frame.midY)
shape.fillColor = UIColor.red
shape.strokeColor = UIColor.blue
shape.lineWidth = 10
addChild(shape)
}
}
struct GameView: View {
var scene: SKScene {
let scene = GameScene()
scene.size = CGSize(width: 300, height: 400)
scene.scaleMode = .fill
return scene
}
var body: some View {
SpriteView(scene: scene)
.frame(width: 300, height: 400)
.ignoresSafeArea()
}
}
struct GameView_Previews: PreviewProvider {
static var previews: some View {
GameView()
}
}
When adding a particle emitter in SpriteKit, I want each particle to stay in the same spot instead of moving with the node the particle is coming off of. My node moves, and I want the particle to flow off of the back and float up (as a trail). Not to be stuck dragged behind the node.
Any help?
Im using swift in Xcode.
Post not yet marked as solved
I am trying to use an EnvironmentObject in an init. I am aware that this is not possible because it hasn't been initialised yet.
But what is the solution? I have tried loading the scene.gameCenterManger in .onAppear but that doesn't seem to work.
I want to use @State for my gamescene variable, because SKScene will reset itself when the view does a refresh.
struct GameSceneView: View {
@EnvironmentObject var gameCenterManager:GameCenterManager
@State var scene = GameScene()
init() {
scene.size = CGSize(width: 1000, height: 1800)
scene.scaleMode = .aspectFill
// doing it as below will throw an error.
//scene.gameCenterManager = gameCenterManager
}
var body: some View {
SpriteView(scene: scene )
.environmentObject(gameCenterManager)
.frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
.ignoresSafeArea()
.overlay(ImageOverlay(), alignment: .bottomTrailing)
.onAppear{ scene.gameCenterManager = gameCenterManager }
}
}
Post not yet marked as solved
I deleted the grid on gamescene.sks and i dont know how to get it back. Now my game wont run
Post not yet marked as solved
The newer more powerful iOS devices are signaling memory limits where older devices did not. Has any iOS developer written about or confronted this problem?
With an iOS SpriteKit game in production that demands a lot of memory (1.5GB) on start up, there have been no memory limit crashes in development (Xcode) and no memory crashes on the same devices running the production app available on the AppStore.
Recently, users with iPhone 12, iPhone 12 mini, or other iPhone with 4GB RAM, report crash with error: jetsam per-process-limit, or jetsam mem limit: ActiveHard 2098 MB (fatal)
iPhone 7, rated at 2GB RAM, runs the downloaded production app with no problem and no memory warnings in the log.
iPhone XR, rated at 3GB RAM, runs the app with no problems.
iPhone 12 Pro, rated at 6GB runs the app with no problem.
Post not yet marked as solved
I have the bare bones of an AUv3 plug in. I have used UIHostingController to allow me to add a SwiftUI view. Then from the SwiftUI I have added a SprikeKit scene which I want to use to start building an interface for the AU.
It's a very basic GameScene for now. If I run one instance of it in Logic then it's OK. If I add another instance it crashes with a Thread 1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) error.
This seems to be down to how I declare a SpriteNode variable.
If I declare it within the GameScene as a "let" then it's fine. If I declare it outside the class - (see hashed code) then it will crash with two instances. It would be useful to me later on for this to be a public variable as I want to perform functions on it outside of the class.
Is there a better way to declare the SpriteNode variable to make it stable?
import SpriteKit
//public var ball = SKShapeNode(circleOfRadius: 30)
var ball = SKShapeNode(circleOfRadius: 30)
class GameScene: SKScene {
let ball = SKShapeNode(circleOfRadius: 30)
override func didMove(to view: SKView) {
//physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
ball.position = CGPoint(x: 200, y: 200)
ball.fillColor = .lightGray
self.addChild(ball)
}
Post not yet marked as solved
In my app, I have greyBars and one border bar. The border bar keeps the greyBars from falling off the screen.
Only one greyBar is used at a time. When it is completely filed with colored gems, a new bar is created and brought up from the bottom of the screen, with the code below.
The result I want is that the new bar, the one with all white diamonds pushes up the old bar and the new bar remains on the bottom. You can see by the screenshot that somehow the new bar ended up on top, even though it was coming from the bottom.
I slowed down the duration of the greyBar's movement to see what was going wrong.
While the two greyBars do clash with each other, the new one (the one on the bottom) ends up pushing THROUGH the top bar.
My assumption was that the new greyBar would just push up the old bar(s), and remain on the bottom.
Is there some "solidity" type property that I am missing?
myGreyBar[0].physicsBody?.categoryBitMask = bodyMasks.greyBarMask.rawValue
myGreyBar[0].physicsBody?.contactTestBitMask = bodyMasks.blankMask.rawValue
myGreyBar[0].physicsBody?.collisionBitMask = bodyMasks.greyBarMask.rawValue
myGreyBar[0].isHidden = false;
myGV.gameScene?.addChild(myGreyBar[0])
let moveAction = SKAction.move(to: CGPoint(x:(myGV.safeSceneRect.width/2) - (size.width/2), y: (myGemBase?.size.height)! + (myGV.border?.size.height)! + 200), duration: 10.0)
myGreyBar[0].run(moveAction, completion:{myGreyBar[0].physicsBody?.collisionBitMask = bodyMasks.borderMask.rawValue|bodyMasks.greyBarMask.rawValue})
Post not yet marked as solved
I have a pretty standard Spritekit Scene that loads from a SwiftUI view. All settings are set to landscape only. Scene dimensions are correct.
How can I stop the GameScene from rotating when I go into portrait mode? I didn't have this issue when using regular Swift before. Is this a SwiftUI issue?
Also I have managed to get my Preview window to be in Landscape but when I run Live Preview it returns to portrait.
This is my ContentView code with the SKScene.
struct ContentView: View {
var scene: SKScene {
let scene = GameScene()
scene.size = CGSize(width: 1080, height: 800)
scene.scaleMode = .fill
scene.backgroundColor = .black
return scene
}
var body: some View {
SpriteView(scene: scene)
.frame(width: 1080, height: 800, alignment: .center)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.previewDevice("iPad (8th generation)")
.previewLayout(.fixed(width: 1080, height: 800))
}
}
Post not yet marked as solved
I know it's uncool to ask vague questions here, but what do they call it when you create a world and follow it with a camera in Swift? Like an RPG? Like Doom?
I want to try and learn that now. And more importantly can it be done without using the Xcode scene builder? Can it be done all via code?
Thanks, as always. Without the forum I would never have gotten much farther than "Hello World!"
Post not yet marked as solved
Im getting a overridden error for my player and enemy. I made a enemy file and added this code into my gamescene. My enemy only spawns in if i delete my player movement code
func spawnEnemy() {
let enemy = Enemy(image: SKSpriteNode(imageNamed: "enemy"))
self.addChild(enemy)
}
override func update(_ currentTime: TimeInterval) {
spawnEnemy()
}
Post not yet marked as solved
How can i change my objects gravity without having my player fall with it. I added
physicsWorld.gravity = CGVector(dx: 0, dy: 0)
on my players movement and affectedByGravity on both my object and player. If I change dy to -9.8, my object falls but along with my player
Post not yet marked as solved
I've just updated to XCode 13.0 (13A233), and I noticed that my project behaves differently (on the simulator).
Here is a snippet of the code:
class GameScene: SKScene {
override func didMove(to view: SKView) {
let backgroundSprite = SKSpriteNode(imageNamed: "background")
backgroundSprite.position = CGPoint(x: 512, y: 384)
backgroundSprite.blendMode = .replace
backgroundSprite.zPosition = -1
addChild(backgroundSprite)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
makeSlot(at: CGPoint(x:128, y:0), isGood: true)
makeSlot(at: CGPoint(x:384, y:0), isGood: false)
makeSlot(at: CGPoint(x:640, y:0), isGood: true)
makeSlot(at: CGPoint(x:896, y:0), isGood: false)
}
func makeSlot(at position: CGPoint, isGood: Bool){
let slotSprite: SKSpriteNode
if isGood {
slotSprite = SKSpriteNode(imageNamed: "slotBaseGood")
} else {
slotSprite = SKSpriteNode(imageNamed: "slotBaseBad")
}
slotSprite.position = position
slotSprite.physicsBody = SKPhysicsBody(rectangleOf: slotSprite.size)
slotSprite.physicsBody?.isDynamic = false
addChild(slotSprite)
}
}
The output is:
https://i.stack.imgur.com/QkUhU.png
But, if I change the y coordinate of the CGPoints to be non zero. i.e.:
override func didMove(to view: SKView) {
let backgroundSprite = SKSpriteNode(imageNamed: "background")
backgroundSprite.position = CGPoint(x: 512, y: 384)
backgroundSprite.blendMode = .replace
backgroundSprite.zPosition = -1
addChild(backgroundSprite)
physicsBody = SKPhysicsBody(edgeLoopFrom: frame)
makeSlot(at: CGPoint(x:128, y:30), isGood: true)
makeSlot(at: CGPoint(x:384, y:30), isGood: false)
makeSlot(at: CGPoint(x:640, y:30), isGood: true)
makeSlot(at: CGPoint(x:896, y:30), isGood: false)
}
Then I can see the the expected result (well.. not really).
Output: https://i.stack.imgur.com/DdMX1.png
It is as if there is a bug that cause an extra margin at the bottom of the screen.
Note:
The same code works previously in XCode 12 (I didnt have to add extra 30 points to y coordinate)
If I open the same code that was written in XCode 12 before, then it works ok (i.e. i didnt have to add that extra 30 points). I should also mention that I noticed this behaviour when I tried to redo the project in XCode 13.
Code works OK on actual device (I didnt have to add extra 30 points to y coordinate).
So... based on point 3.. I guess this is an XCode bug? Or have I missed something in the XCode 13 release notes?
Post not yet marked as solved
The SKView.showsFields = true only draws on a portion of the screen - nothing shows on the bottom-left.
This can be easily tested using Apple's default game playground. I only removed the action for the Hello World label and added a radialGravityField into the scene.
Also other fields like electricField do not draw anything on the screen.
Tested in Xcode 11.7 and Xcode 12.5.1. Is this a bug in the recent releases?
override func didMove(to view: SKView) {
// ...
let field = SKFieldNode.radialGravityField()
addChild(field)
}
and
sceneView.showsFields = true
Post not yet marked as solved
Is there a way to force precompilation of SKShader()s?
I am initializing a basic shader in my SKScene properties, but the shader only gets compiled when it is actually attached and rendered to a sprite.
class GameScene: SKScene {
let myShader = SKShader(fileNamed: "myEffect.fsh")
override func update(_ currentTime: TimeInterval) {
if touches.count > 0 {
mySprite.shader = myShader
// this is where the warning triggers for the first time
}
}
}
I know this because the scene pauses for a bit, immediately before the shader is rendered for the first time, and I also get the Metal warning (which seems to also be a known bug in recent releases - https://developer.apple.com/forums/thread/661774):
[Metal Compiler Warning] Warning: Compilation succeeded with:
program_source:3:19: warning: unused variable 's'
constexpr sampler s(coord::normalized,
I was expecting the shader to compile when it is initialized with SKShader(fileNamed:), since Apple docs says:
Compiling a shader and the uniform data associated with it can be expensive. Because of this, you should:
Initialize shader objects when your game launches, not while the game is running.
https://developer.apple.com/documentation/spritekit/skshader
Post not yet marked as solved
SKFieldNode.isExclusive = true doesn't seem to work.
I created a very simple example in the Game Playground, with two intersecting electric fields and a third object placed at the intersection of the fields, with a negative charge.
Each field pulls the object towards its center. The first field (left side) has isExclusive=true, the second field (right side) has isExclusive=false.
So based on the definition, the exclusive field is suppressing any other field in its region of effect, and since the object is in both regions, it should be pulled towards the field that is exclusive.
Instead, the object doesn't move, since both fields are exerting the same forces on it.
The object gets pulled by both fields, thus not moving.
If one field is disabled using isEnabled = false, the object immediately starts to move towards the field that is enabled.
Playground code:
import PlaygroundSupport
import SpriteKit
class GameScene: SKScene {
override func didMove(to view: SKView) {
/*
Configure two intersecting electric fields
*/
let field1 = SKFieldNode.electricField()
field1.region = SKRegion(radius: 190)
field1.position = CGPoint(x: -160, y: 0)
field1.isExclusive = true
addChild(field1)
let field2 = SKFieldNode.electricField()
field2.region = SKRegion(radius: 190)
field2.position = CGPoint(x: 160, y: 0)
field2.isExclusive = false
addChild(field2)
/*
Configure some visuals (shapes and labels) for the fields,
since SKView.showsFields doesn't work.
*/
let field1Visual = SKShapeNode(circleOfRadius: 190)
field1Visual.strokeColor = .yellow
field1Visual.addChild(SKLabelNode(text: "isExclusive=true"))
field1.addChild(field1Visual)
let field2Visual = SKShapeNode(circleOfRadius: 190)
field2Visual.addChild(SKLabelNode(text: "isExclusive=false"))
field2.addChild(field2Visual)
/*
Configure object placed at the intersection of the two electric fields,
with a negative charge, so each field attracts this object.
*/
let object = SKShapeNode(circleOfRadius: 25)
object.strokeColor = .magenta
object.physicsBody = SKPhysicsBody.init(circleOfRadius: 25)
object.physicsBody!.affectedByGravity = false
object.physicsBody!.charge = -0.1 // is attracted
addChild(object)
}
}
let sceneView = SKView(frame: CGRect(x:0 , y:0, width: 640, height: 480))
let scene = GameScene(size: CGSize(width: 1024, height: 768))
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
scene.scaleMode = .aspectFill
sceneView.presentScene(scene)
sceneView.showsFields = true // doesn't work for electricField() and is broken for other fields
PlaygroundSupport.PlaygroundPage.current.liveView = sceneView
A bug report was also submitted on Feedback assistant, FB9661601.
Post not yet marked as solved
let randomNumber = arc4random_uniform(2)
let x: CGFloat = randomNumber == 0 ? 1 : -1
enemy.position = CGPoint(x: (CGFloat(arc4random_uniform(UInt32(UIScreen.main.bounds.width))) * x), y: UIScreen.main.bounds.height)
here is my code for enemy spawn, it works but some of my enemies are spawning outside of my screen. What can i change to make them all spawn inside the border
I have an SkSpriteNode (ball) in a box. Gravity is set to false, otherwise it has an SkPhysicsBody to bounce off of walls.
Is there a method to give the ”ball” an initial push in a specified direction and velocity/strength wise?
Post not yet marked as solved
Is it possible to present a SwiftUI view from a SpriteKit scene? I have various sprites in the game scene. I want a SwiftUI view to pop up when I tap on a SpriteNode in the SKScene.
In the past I have used something like this to present another UI view.
if bloqsLogo.contains(location) {
if instructionsOn == false {
let pop = InstructionsPopUp()
pop.tag = 104
self.view?.addSubview(pop)
instructionsOn = true
} else
if instructionsOn == true {
if let viewWithTag = self.view!.viewWithTag(104) {
viewWithTag.removeFromSuperview()
instructionsOn = false
}else{
print("nah")
}
}
}
How can I do something similar but present a SwiftUI scene rather than a Subview or a UIView?
My SKScene is an instance of another SwiftUI view and presented there. A good part of my GUI is done in SwiftUI. I am basically wanting to code as much of my App as I can in SwiftUI while keeping the physics and sprites in a SKScene. All of which is going rather well besides this!