I am working on an app where there should be a red circle on the screen. At first when I tested with only one scene, the circle appeared circular just fine. However, I have added in another scene and now the circle appears like this:
The circle appears to be much longer in the x direction.
Here is the code I use to make the circle (All of this in an skscene):
let ball = Ball(circleOfRadius: 500)//ball is a subclass of SKShapeNode
ball.setScale((self.frame.height / 6) / 1000)
ball.position = CGPointMake(self.frame.width / 4, self.frame.height / 2)
ball.fillColor = UIColor.redColor()
ball.strokeColor = UIColor.clearColor()
self.addChild(ball)
Here is the code I use to transition to the scene with the ball (A different skscene):
func transitionToGame(){
let reveal = SKTransition.crossFadeWithDuration(1.0)
let gameOverScene = GameScene(size: self.size)
self.view?.presentScene(gameOverScene, transition: reveal)
}
Any ideas on why the ball would no longer appear as a circle? I a worried this is also going to throw off other nodes I attempt to add, and possible means the coordinate system is incorrect. I am happy to hear any ideas. Thank you!
"All of this in an skview" are you sure you aren't doing that in a SKScene?
If the ball is indeed getting added directly to the scene I would look at the scene.scaleMode in your View Controller. Most of the time people set it to scene.scaleMode = .AspectFill but when you create a new scene you aren't setting the scaleMode. This might be as easy as making sure both scenes have the same scaleMode.
I am guessing this will fix your issue.
func transitionToGame(){
let reveal = SKTransition.crossFadeWithDuration(1.0)
let gameOverScene = GameScene(size: self.size)
gameOverScene.scaleMode = scene.scaleMode
self.view?.presentScene(gameOverScene, transition: reveal)
}
Hopefully that helps.
Related
I'm Trying to make a Start Scene Where you press a "Start" Button, and it goes to the main game scene. Here's the code:
if startBTN.containsPoint(location) {
let gameSceneTemp = GameScene(fileNamed: "GameScene")
self.scene?.view?.presentScene(gameSceneTemp, transition: SKTransition.fadeWithDuration(0.01))
}
But for some reason, whenever the scene loads up, it displays a squished-like scene in the GameScene. Can anyone help solve this problem by displaying a normal size (portarit) scene? Here's the Screen shots between the expected and actual scene:
The Expected Scene
The Actual Scene (The Problem)
It turns out, I didn't set the scene mode. I looked this problem up and I finally found the solution. Here's the code:
if startBTN.containsPoint(location) {
var gameScene = GameScene(size: self.size)
var transition = SKTransition.fadeWithDuration(0.8)
gameScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view?.presentScene(gameScene, transition: transition)
}
I had put the gamescene file and transition, but didn't add the scalemode to it.
Main menu looks like this.
When i press start code below changes the scene.
let newScene = LevelScene(size: self.scene!.size)
let transition = SKTransition.revealWithDirection(SKTransitionDirection.Up, duration: 1)
newScene.scaleMode = SKSceneScaleMode.AspectFill
self.scene!.view!.presentScene(newScene, transition: nil)
And after I return to the main menu it looks like this
or this
So, as you can see, sprites just disappears. I can't come up with a reason for this to happen.
Are you doing,
self.addChild(...)
self.addChild(...)
in your didMoveToView method?
Another possible problem might be that you are setting the zPosition of the node to less than your background, and / or other nodes.
I had the same problem with sprites disappearing and after changing the zPositions of all my sprites and background I still wasn't able to solve it.
I ended up just redeclaring the scene inside my restartButton:
var scene = SKScene(fileNamed: "GameScene")
scene?.scaleMode = .aspectFill
view!.presentScene(scene)
And that worked for me.
I'm using standard full screen SpriteKit view from the boilerplate code (new game iOS project), and when I use
scene.scaleMode = .AspectFit
to make sure that scene fits, remaining (letterboxed) area is colored in black.
I've tried these options to change the color:
let skView = self.view as SKView
// was hoping this one would work
skView.backgroundColor = UIColor.redColor()
// didn't expect this would work, since scene is scaled anyways
scene.backgroundColor = SKColor.redColor()
Also tried to change SKView background color in storyboard editor to another color, but no luck.
Any tips on where to look to change the color of the letterboxed area?
I think the should be a way to set the colour or place sprites in the ears of the letterhead... but it seems that there isn't. Also, I disagree with LearnCocos2D. There's nothing wrong with AspectFit. It has its use.
What I've done is use AspectFit but also calculate the size of the scene based on screen size. This isn't that helpful for an OSX game but it'll work fine for iOS.
func createScene() -> GameScene {
let screenSize = UIScreen.mainScreen().bounds.size
var size:CGSize = CGSizeZero
size.height = Constants.sceneHeight
size.width = screenSize.width * (size.height / screenSize.height);
return GameScene(size: size)
}
override func viewDidLoad() {
super.viewDidLoad()
let scene = self.createScene()
// Configure the view.
let skView = self.view as SKView
skView.showsFPS = false
skView.showsNodeCount = false
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFit
skView.presentScene(scene)
}
After a scene is rendered, its contents are copied into the presenting view. If the view and the scene are the same size, then the content can be directly copied into the view. If the two differ, then the scene is scaled to fit in the view. The scaleMode property determines how the content is scaled.
The letterboxing is create IN the view so there is no way around it. That said there is often the need for an .aspectFit setting if you want to use a specific scene size and universal coordinate system. If that is your case, the following should help.
You need to figure out how much a standard .aspectFit would need in padding to remove the letter boxing from your current device and add that to your scene. You finish with a scene that is lighter a little bigger or a little wider then your original sizes but the scene has at least the same size as your original scene size. You can then move the anchorPoint to the original (0, 0) coordinates or the (0.5, 0.5) one depending on what coordinate system you want to use for your game.
The code for this is convoluted and could change in time. If you want a quick fix, I created a Framework exactly for that purpose. It's small but portable :)
https://github.com/Tokuriku/tokuriku-framework-stash
Just:
Download the ZIP file for the Repository
Open the "SceneSizer" sub-folder
Drag the SceneSizer.framework "lego block" in your project
Make sure that the Framework in Embedded and not just Linked
Import the Framework somewhere in your code import SceneSizer
And you're done, you can now call the sizer Class with:
SceneSizer.calculateSceneSize(#initialSize: CGSize, desiredWidth: CGFloat, desiredHeight: CGFloat) -> CGSize
Documentation is in the folder for a clean and full use with a standard scene. Hope this helps!
I am following a tutorial on SpriteKit and when I add my background image to the scene, the image does not fill up the entire scene (has margins).
The project is a universal project, and I am using size classes (same effect when I turn it off).
I am new to Swift and SpriteKit, so maybe I am missing something. Here is my code (from a brand new project):
override func didMoveToView(view: SKView) {
/* Setup your scene here */
self.anchorPoint = CGPointMake(0.5, 0.5)
let background = SKSpriteNode(imageNamed: "Background")
background.position = CGPointMake(0, 0)
background.size = CGSizeMake(self.view.bounds.size.width, self.view.bounds.size.height)
self.addChild(background)
}
And here is a screenshot:
I added the position and size code just to be sure. Also, frame.size is showing (1024, 768) but bounds.size shows the proper (640, 1136). Any help will be greatly appreciated!
You will find that in your ViewController.swift, the current scale mode is .AspectFill which is sometimes perfectly find to use but in your case, you need to change that to
scene.scaleMode = .ResizeFill
which will make sure that the size fits perfectly into any size screen. You then use self.view.frame.size instead of self.view.bounds.size and you are good to go! Ask if you need any more information, though the documentation explains the scaleModes quite well:
https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKScene_Ref/index.html#//apple_ref/c/econst/SKSceneScaleModeFill
I created a SKView which presents an SKScene subclass like this:
SKView *skv = [[SKView alloc] initWithFrame:self.view.bounds];
[self.view addSubview:skv];
self.skScene = [[TestScene alloc] initWithSize:v.bounds.size];
[skv presentScene:_skScene];
Then to see coordinate system origin, I add a small 10x10 colored square to the scene.
SKSpriteNode *ori = [SKSpriteNode spriteNodeWithColor:[UIColor greenColor] size:CGSizeMake(10,10)];
[self addChild:ori];
You can see green square in lower left corner:
From what I thought, SpriteKit coordinate system is such that origin is always in center. But in the scene the origin is in lower left corner. When I add a child node to {0,0} it appears in lower left corner as well.
When I add a SKSpriteNode and position it {0,0} in the scene, it appears in lower left corner. But it is centered around scene origin in lower left corner (clipped off half to left, and half to bottom).
But now it gets more confusing. When I add a SKSpriteNode to another SKSpriteNode, the sub-sprite is CENTERED in the parent.
So does it mean the Scene coordinate system works different than the sprite coordinate system?
Recap:
When I position a sprite in scene at {0,0}, it appears in bottom
left, clipped off 50% (centered around origin).
When I position a sprite in a sprite at {0,0}, it appears centered in the sprite.
Is my Scene configured wrong or is this the way it works?
This is the way it works. All OpenGL views (the 2D ones at least) have their origin at the lower left corner.
The position of your sprites is correct too. Both are located at 0,0 by default. The texture of the sprites is drawn relative to the node position based on the anchorPoint factor. It's default value of 0.5, 0.5 places the texture centered on the node's position.
You can change the anchorPoint of the scene to 0.5,0.5 which will move the sprites to the center of the scene. You can also change the sprite's anchorPoint though that isn't recommended since it affects things like rotation, scale, collision detection and child node position.
you can add this code to GameViewController.swift :
override func viewDidLoad() {
super.viewDidLoad()
// Detect the screensize
var sizeRect = UIScreen.mainScreen().applicationFrame
var width = sizeRect.size.width * UIScreen.mainScreen().scale
var height = sizeRect.size.height * UIScreen.mainScreen().scale
// Scene should be shown in fullscreen mode
let scene = GameScene(size: CGSizeMake(width, height))
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
What I did was to set the size of the SKScene you want to show to the bounds.size of the Viewcontroller you want to show the scene from. Something like this:
if let scene = GameScene(fileNamed:"GameScene") {
// Configure the view.
let skView = self.view as! SKView
skView.showsFPS = true
skView.showsNodeCount = true
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = true
scene.size = skView.bounds.size
/* Set the scale mode to scale to fit the window */
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
I hope this worked for you as well, if I made any mistakes here, please let me know as well :)