I have a player in the center of the screen, which I'd like to be the "source" of the light, so every other sprite, such as flying enemies, are casting a shadow.
I have this code:
light.categoryBitMask = 1
light.falloff = 1
light.shadowColor = UIColor.blackColor()
light.position = CGPoint(x: size.width / 2, y: size.height / 2)
addChild(light)
I'm totally new to Swift, never had any experience with SpriteKit, so I figured out that I should add this to every Sprite:
enemyOne.shadowCastBitMask = 1
What I get is quite interesting. The screen flickers everytime an enemy sprite is being spawned. But other than that, and a really small light in the center of the screen, where my player is, I'm not getting any shadows.
To make my plan more clear, I'd like to make it look like this:
This is what it looks like, as requested:
Related
I have a spotlight, created with the code beneath, casting shadows on all of my nodes:
spotLight.type = SCNLightTypeSpot
spotLight.spotInnerAngle = 50.0
spotLight.spotOuterAngle = 150.0
spotLight.castsShadow = true
spotLight.shadowMode = SCNShadowMode.Deferred
spotlightNode.light = spotLight
spotlightNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(-90), y: 0, z: 0)
spotlightNode.position = levelData.coordinatesForGridPosition(column: 0, row: playerGridRow)
spotlightNode.position.y = 1.5
rootNode.addChildNode(spotlightNode)
The scene is moving along the z axis, and the camera has an infinite animation that makes it move:
let moveAction = SCNAction.moveByX(0.0, y: 0.0, z: CGFloat(-GameVariables.segmentSize / 2), duration: 2.0)
cameraContainerNode.runAction(SCNAction.repeatActionForever(moveAction))
As the camera moves though, the light doesn't, so after a while, the whole scene is dark. I want to move the light with the camera, however if I apply to the light node the same moving animation, all the shadows start to flicker. I tried to change the SCNShadowMode to Forward and the light type to Directional, but the flickering is still there. With directional, I actually loose most of my shadows. If I create a new light node later on, it will seem that I have two "suns", which of course is impossible. The final aim is simply to have an infinite light that shines parallel to the scene from the left, casting all the shadows to the right. Any ideas?
Build a node tree to hold both spotlight and camera.
Create, say, cameraRigNode as an SCNNode with no geometry. Create cameraContainerNode and spotlightNode the same way you are now. But make them children of cameraRigNode, not the scene's root node.
Apply moveAction to cameraRigNode. Both the camera and the light will now move together.
Very new to Sprite Kit and i'm doing some reading now, but wanted to ask about something that I haven't found the best answer to yet.
I'm doing a tutorial with some code that creates a background, and then adds a label to show a score. I started changing the label code to position it on the top-left corner of the screen.
Here is the code (with my edits to the label, gameLabel):
let screenSize = UIScreen.mainScreen().bounds
let screenWidth = screenSize.width
let screenHeight = screenSize.height
let background = SKSpriteNode(imageNamed: "background")
background.position = CGPoint(x: screenWidth / 10, y: (screenHeight / 15) - 100)
background.blendMode = .Replace
background.zPosition = -1
addChild(background)
gameScore = SKLabelNode(fontNamed: "Chalkduster")
gameScore.text = "Score: 0"
gameScore.position = CGPoint(x: screenWidth / 10, y: (screenHeight / 15) - 100)
gameScore.horizontalAlignmentMode = .Left
gameScore.verticalAlignmentMode = .Top
gameScore.fontSize = 48
addChild(gameScore)
So the label is not displaying in any case, and my assumption is this:
Because i'm adding the background first, the label is getting added within the confines of the background, therefore it needs to be positioned differently, perhaps using the label size instead of the screen size?
My questions:
How can I get the label to always appear in the top left?
The author chose a hard-coded CGPoint for this background image and then said it has to be on an iPad, but i'd like to do it for iPhone 6/plus in landscape as well as iPad. Is there a way I can just make it work on both devices without having to specify a CGPoint like that? Can't it just scale and work regardless?
Thanks and apologies if these are basic questions - i'm going to do my best to continue reading on the subject..
Your question has a simple answer to it. You have forgotten and missed out somethings in your code, and I can show you these things.
In your code you set the background ZPosition to -1, the smallest number will always appear at the back. So if you set the SKLabelNode to a bigger zPosition it will always appear at the front, as maybe there may be a problem with rendering, as I have also experience like these, I fix it this way:
Before you add the LabelNode set it's property to this:
gamescore.zPosition = 0
0, In this case could just be anything bigger than the backgrounds(or the node that you want to appear at the back). So this just tells the compiler that you want the LabelNode to appear at the front, or in front of the Background.
If you want to make a universal app or game, with SpriteKit you will need to add some extra code to your game or app. Since I think that it is better to give you a good tutorial to show you instead of showing you some basics, I will give you a good link on how to do this:
SpriteKit: how to make a universal app
I hope this helps, and don't worry this took me some time to figure out my self.
I am making a platforming game with SpriteKit. I want to achieve the effect that only the area around the player is lit and everything else fades into darkness. Imagine something like a fake light source or a strong vignette. For testing purpose I created the following code:
let effect = SKEffectNode()
effect.zPosition = 100
effect.position = CGPoint(x: 0, y: 0)
effect.shouldRasterize = false
effect.blendMode = SKBlendMode.Multiply
let gray = SKSpriteNode()
gray.color = SKColor.grayColor()
gray.size = self.frame.size
gray.blendMode = SKBlendMode.Multiply
gray.position = CGPoint(x: 0, y: 0)
let shine = SKSpriteNode(imageNamed: "Shine")
shine.position = CGPoint(x: 0, y: 0)
shine.blendMode = SKBlendMode.Screen
shine.setScale(3.0)
effect.addChild(gray)
effect.addChild(shine)
self.world.addChild(effect)
This works as desired but has a somewhat significant impact on the frame rate. Considering that there might be additional effects like these from e. g. torches or other light sources on the map, I expect the frame rate to drop even more.
Next, I wanted to make the light flicker, so I assigned a random alpha value to the shine sprite in the update function. This really killed the frame rate, letting it drop instantly to about 4 frames.
I have read about SKEffectNodes and their heavy impact on the frame rate. Is there any other way to achieve this sort of fullscreen alpha blending, that is reasonably fast, even with multiple "lights"?
Any advice is truly appreciated.
Could this be solved with a SKLightNode perhaps?
https://developer.apple.com/library/prerelease/ios/documentation/SpriteKit/Reference/SKLightNode_Ref/index.html
Here's an article about how to use the SKLightNode:
http://www.ymc.ch/en/playing-with-ios-8-sprite-kit-and-sklightnode
Hope that's of any usage to you
I want to add a Health Bar (a progressing Bar) in my Scene.
It's a rectangle bar filled with a color, on the upper left in the Scene, and every second the bar decreases (the filled color). After 2 Objects (SKSpriteNode's) hit each other, it gives you + 5 seconds time.
Thanks to LearnCocos2D and CloakedEddy, I know that I can make the Bar by using simply SKSpriteNode with Color or SKCropNode instead of SKShapeNode.
How should I implement it now at best to decrease itself every second smoothly?
My Code:
....
var progressValue = 200
....
HealthBar = SKSpriteNode(color:SKColor .yellowColor(), size: CGSize(width: progressValue, height: 30))
HealthBar.position = CGPointMake(self.frame.size.width / 3, self.frame.size.height / 1.05)
HealthBar.anchorPoint = CGPointMake(0.0, 0.5)
HealthBar.zPosition = 4
self.addChild(HealthBar)
What you could do is have a SKSpriteNode be the health bar. Then you have a SKSpriteNode as a frame over the first node. You have an action SKAction.repeatForever(SKAction.sequence([SKAction.moveByX(moveAmount, y: 0, duration: 0.5), SKAction.waitForDuration(0.5)])) and make the health bar (not the frame) run that action. What that will do is move the health bar off the screen, making it look like its going down.
About the collision problem, look at this tutorial. If that doesn't help, maybe you could find others. I want to help with this one, but collision detection is fairly in-depth even with SpriteKit. I hope this helped. Good Luck!
I'm developing a game on Iphone and Ipad like a space invaders.
Balloons to destroy are falling from the top of the screen in a straight line.
Here my codes to add them :
func addBalloonv(){
var balloonv:SKSpriteNode = SKSpriteNode (imageNamed: "ballonvert.png")
balloonv.physicsBody = SKPhysicsBody (circleOfRadius: balloonv.size.width/2)
balloonv.physicsBody.dynamic = true
balloonv.physicsBody.categoryBitMask = balloonCategory | greenCategory
balloonv.physicsBody.contactTestBitMask = flechetteCategory
balloonv.physicsBody.collisionBitMask = balloonCategory
balloonv.physicsBody.mass = 1
balloonv.physicsBody.restitution = 1
balloonv.physicsBody.allowsRotation = true
let minX = balloonv.size.width/2
let maxX = self.frame.size.width - balloonv.size.width/2
let rangeX = maxX - minX
let position:CGFloat = CGFloat(arc4random()) % CGFloat(rangeX) + CGFloat(minX)
balloonv.position = CGPointMake(position, self.frame.size.height+balloonv.size.height)
self.addChild(balloonv)
I have one func by balloon color.
So for the moment they move in straight line and I'm looking for random movements (with turbulences like balloon in air) from the top and both sides.
How can I do that?
Thank you very much !!
This is exactly what the new Physics Fields feature in SpriteKit (as of iOS 8 / OS X Yosemite) is for. These let you apply different kinds of forces to all physics bodies in region, like gravity, drag, and turbulence. See the SKFieldNode class docs for details.
Fields are a kind of node, so to get what you're after, you'd add one noise (or turbulence) field to your scene, covering the area that the balloons fall through, and it'll perturb the path of each balloon that passes. The simplest way to do it goes something like this:
let field = SKFieldNode.noiseFieldWithSmoothness(0.5, animationSpeed: 0.1)
scene.addChild(field)
You'll want to tweak the smoothness, animation speed, and field.strength till you get just the level of noise you want. You might also look into whether you want just a noise field, which applies random forces in random directions, or a turbulence field, which does the same thing, but with forces that get stronger when bodies are moving faster.
The above code gets you a field whose region of effect is infinite. You might want to limit it to a specific area (for example, so it doesn't keep knocking your balloons around after they land). I did this to make a field that covers only the top 3/4 of a 300x200 scene:
field.region = SKRegion(size: CGSize(width: 300, height: 100))
field.position = CGPoint(x: 150, y: 150)