Spritekit Coordinate System unexpected positioning - swift

I have the classes AttackArea, Player and GameScene.
I want to instantiate a new AttackArea object and place it near the Player, depending on the Players facing. Now I have problems with the right positioning. If I add the AttackArea as a child of GameScene, the positioning works as expected. But If I do that, the AttackArea isn't moving with the Player. Otherwise if I add the AttackArea as a child of the Player, it's moving with the Player. That's exactly what I want. The problem here is that the positioning of the AttackArea is now far away from the Player. This is the code in the Player class:
func attack(){
let attack = AttackArea(color: .red, size: CGSize(width: self.frame.width, height: self.frame.height / 2))
var animation = ""
switch playerFacing{
case .back:
attack.position = CGPoint(x: self.position.x, y: self.position.y + 40)
animation = Constants.Actions.playerAttackBack
case .front:
attack.position = CGPoint(x: self.position.x, y: self.position.y - 40)
animation = Constants.Actions.playerAttackFront
case .left:
attack.position = CGPoint(x: self.position.x - 40, y: self.position.y)
animation = Constants.Actions.playerAttackLeft
case .right:
attack.position = CGPoint(x: self.position.x + 40, y: self.position.y)
animation = Constants.Actions.playerAttackRight
case .none:
break
}
attack.zPosition = self.zPosition + 1
attack.setup()
if animation != ""{
self.run(SKAction(named: animation)!)
}
self.addChild(attack)
}
The first picture shows the situation when the AttackArea is a child of GameScene. The positioning is fine but I want it to be a child of Player.
The second picture shows the positioning when the AttackArea is a child of Player. The red square in the top right corner is the AttackArea and the red circle is the Player.
Why is the AttackArea so far away from the Player in this case? How can I archieve the same result as in the first picture with the only exception, that the AttackArea is child of the Player?

what happens if you change the positioning to
switch playerFacing{
case .back:
attack.position = CGPoint(x: 0, y: 0 + 40)
animation = Constants.Actions.playerAttackBack
case .front:
attack.position = CGPoint(x: 0, y: 0 - 40)
animation = Constants.Actions.playerAttackFront
case .left:
attack.position = CGPoint(x: 0 - 40, y: 0)
animation = Constants.Actions.playerAttackLeft
case .right:
attack.position = CGPoint(x: 0 + 40, y: 0)
animation = Constants.Actions.playerAttackRight
case .none:
break
}
I suspect that your player (for example) might be at pos 500, 500 and you are re-adding those values to the attack position so now it's position is 1000, 1040

Related

I'm trying to create an infinite vertical scrolling background with SpirteKit, however I can't seem to get the code to work

The loop isn't timed correctly and resets too quickly. The looped image is also cut off showing only a fraction of it rather than the full looped background image stitched to the previous one.
I've attempted playing around with the .position, .size, and the SKAction values, but I just can't seem to tweak it to where it works properly.
func scrollingBackground() {
let BGTexture = SKTexture(imageNamed: "Background")
for i in 0 ... 1 {
let background = SKSpriteNode(texture: BGTexture)
background.zPosition = -30
background.anchorPoint = CGPoint(x: 0, y: 0)
background.size = CGSize(width: (frame.size.width), height: (frame.size.height))
background.position = CGPoint(x: 0, y: -BGTexture.size().height + (BGTexture.size().height + (BGTexture.size().height * CGFloat(i))))
addChild(background)
let scrollUp = SKAction.moveBy(x: 0, y: BGTexture.size().height, duration: 20)
let scrollReset = SKAction.moveBy(x: 0, y: -BGTexture.size().height, duration: 0)
let scrollLoop = SKAction.sequence([scrollUp, scrollReset])
let scrollForever = SKAction.repeatForever(scrollLoop)
background.run(scrollForever)
}
I hoping to get a seamless infinite background loop that runs indefinitely rather than this jumpy mess I currently have. I might add that my background image isn't originally sized perfectly to the devices, but I'm wanting to make sure my background fits to all iPhone devices.
Your first BG is at y = 0, Your second BG is at y = height. I am assuming that you are on anchor point 0.5 0.5, which would make height / 2 off screen. Your action moves BG 1 exactly to where it is off screen, then bumps back to 0. Your BG2 starts off screen, continues to move off screen, then when it hits 2 * height, resets to 1 * height, thus never appears on the screen. This is going to give the appearance of a black bar at the bottom, because BG2 is never drawn. Multiply your i by negative height instead, and that should cause the BG2 to appear on the bottom instead.
func scrollingBackground() {
let BGTexture = SKTexture(imageNamed: "Background")
for i in 0 ... 1 {
let background = SKSpriteNode(texture: BGTexture)
background.zPosition = -30
background.anchorPoint = CGPoint(x: 0, y: 0)
background.size = CGSize(width: (frame.size.width), height: (frame.size.height))
background.position = CGPoint(x: 0, y: -BGTexture.size().height + (BGTexture.size().height + (-BGTexture.size().height * CGFloat(i))))
addChild(background)
let scrollUp = SKAction.moveBy(x: 0, y: BGTexture.size().height, duration: 20)
let scrollReset = SKAction.moveBy(x: 0, y: -BGTexture.size().height, duration: 0)
let scrollLoop = SKAction.sequence([scrollUp, scrollReset])
let scrollForever = SKAction.repeatForever(scrollLoop)
background.run(scrollForever)
}

Sprite positioning at wrong points in y axis

so I know this is a dumb question, but maybe it'll help other people like me out too. Basically, I'm making a sprite appear at the top of the screen and then move to the bottom but in a random x position. There's nothing wrong with moving to the random x position, the problem is that it doesn't start out at the top of the screen. Here is my code:
let sprite = SKSpriteNode(imageNamed: "comet")
sprite.size = CGSize(width: 150, height: 100)
sprite.position = CGPoint(x: self.frame.size.width/2, y: 0)
sprite.zPosition = 100
self.addChild(sprite) `
let randomNum = CGPoint(x:Int (arc4random() % 1000), y: 1)
let actionMove = SKAction.moveTo(randomNum, duration: 1)
let actionComet = SKAction(actionMove)
sprite.runAction(actionComet)
Any help is appreciated.
You are placing your sprite at location (0,0) which is left bottom of the screen. If you want to place the sprite at the top use:
sprite.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height + sprite.size.height / 2.0)

SKSpriteNode animation to appear bottom-up

According to the following code, i am displaying a mountain (hill) in the scene at x = 400 and y = self.frame.height / 2
However, I want the hill to appear from bottom-up (from below the scene) like an animation. How can I code this ?
let hill = SKSpriteNode(imageNamed: "hill")
hill.position = CGPoint(x: 400, y: self.frame.height / 2 )
hill.setScale(1)
hill.physicsBody = SKPhysicsBody(rectangleOfSize: hill.size)
hill.physicsBody?.categoryBitMask = 1
hill.physicsBody?.collisionBitMask = 2
self.addChild(hill)
To create an animation that makes the sprite slide up from "under" the scene, do this:
Set its initial position to below the scene:
hill.position = CGPoint(x: 400, y: self.frame.height / CGFloat(2) - self.frame.height)
Note: - self.frame.height is used to place the node 1 full frame height below the desired location
Then start an action that moves it up to its desired position in didMoveToView, or wherever you want the animation to start:
let moveUpAnimation = SKAction.move(to: CGPoint(x: 400, y: self.frame.height / CGFloat(2)), duration: 0.75)
hill.run(moveUpAnimation)
This example creates an action that takes 0.75 seconds to move the sprite up one full frame height. You can set its initial position to anywhere below the visible scene to create this effect, and change the duration to any desired speed.

SpriteKit: How to spawn object in exact place?

I'm in the middle of making a simple game in XCode 7, using sprite kit. I currently have a square in the middle of the scene and I have set up swipe gestures which make smaller squares "shoot" out of the left, right, top of bottom of the square, depending on the way of the swipe gesture. They go in a straight direction and I would like other random "Enemy" squares to come in the opposite way, again in the same line of path as the squares that are shot out so they can collide... Any ideas on how to do this?
Here's the basic idea, same for the right, up and down:
func swipedLeft(){
print("SwipedLeft")
let SmallSquare1 = SKSpriteNode(imageNamed: "Square")
SmallSquare1.position = MainSquare.position
SmallSquare1.size = CGSize(width: 30, height: 30)
SmallSquare1.physicsBody = SKPhysicsBody(circleOfRadius: SmallSquare1.size.width / 2)
SmallSquare1.physicsBody?.affectedByGravity = false
self.addChild(SmallSquare1)
let moveLeft = SKAction.moveByX(-frame.size.width, y: 0, duration: 2)
SmallSquare1.runAction(moveLeft)
Here's the Enemy function I'm stuck on...
func Enemies(){
let Enemy = SKSpriteNode(imageNamed: "Square")
Enemy.size = CGSize(width: 20, height: 20)
Enemy.color = UIColor(red: 0.9, green: 0.1, blue: 0.1, alpha: 1.0)
Enemy.colorBlendFactor = 1.0
}
For the one on the left:
Enemy.position = CGPoint(x: (any X position), y: MainSquare.position.y)
And do the same for the right side.
And for above and below just do the MainSquare.position.x as the x position

How can I make the player not able to go through certain boundaries? (off-screen)

Hey so I was watching Ray Wenderlich's tutorial on How to Make a Game Like Mega Jump! and tried to create a similar project on my own. So during the tutorial you set the player to be able to go off the screen whenever you tilt the device.
override func didSimulatePhysics() {
player.physicsBody?.velocity = CGVector(dx: xAcceleration * 400.0, dy: player.physicsBody!.velocity.dy)
if player.position.x < -20.0 {
player.position = CGPoint(x: self.size.width + 20.0, y: player.position.y)
} else if (player.position.x > self.size.width + 20.0) {
player.position = CGPoint(x: -20.0, y: player.position.y)
}
return;
}
This is the code I have which makes the player go off the screen. How can I do this but for the player NOT being able to go off the screen? For example if you tilt your device all the way to the right make the player to stay on the right side until you move it the other way! Thank you in advance.
Currently you check if the player is out of screen (more then 20px) and then set his position to the other side, 20px out of the screen.
But you want to stop the player at 0px and your screen width. You can do it like this:
if player.position.x <= 0.0 {
player.position = CGPoint(x: 0.0, y: player.position.y)
} else if (player.position.x >= self.size.width) {
player.position = CGPoint(x: self.size.width, y: player.position.y)
}
This just set's the position of the player to 0.0 if he's moving out to the left, or your screen width, if he's moving out to the right.
The current code "loops around" so moving all the way to the left means you end up on the right.
Just change the coordinates in the if blocks to pin to the edges. Something like this:
if player.position.x < -20.0 {
player.position = CGPoint(x: -20.0, y: player.position.y)
} else if (player.position.x > self.size.width + 20.0) {
player.position = CGPoint(x: self.size.width + 20.0, y: player.position.y)
}
Notice that if the player is beyond the left edge (x < -20) then you just leave the x-position at -20. Similar thing on the right edge.
You'll have to try this out to see how it works with the physics and acceleration but that should be the general idea.