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

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.

Related

Spritekit Coordinate System unexpected positioning

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

How to have endless scrolling ground at an angle with Swift and Spritekit?

I am trying to implement an endless scrolling ground with Swift and Spritekit. I managed to get the scrolling ground to work if the ground is a flat surface. But I want the ground to be on a decline like it is going down a hill. How can I do this? Here is the code I currently have:
func createGround() {
for i in 0...2 {
let grounds = SKSpriteNode(color: UIColor.white, size: CGSize(width: 600, height: 200))
grounds.name = "Ground"
grounds.anchorPoint = CGPoint(x: 0.5,y: 0.5)
grounds.position = CGPoint(x: CGFloat(i) * grounds.size.width, y: -300)
self.addChild(grounds)
}
}
func moveGround() {
self.enumerateChildNodes(withName: "Ground", using: ({
(node, error) in
node.position.x -= 6
node.position.y += 1
if node.position.x < -((self.scene?.size.width)!) {
node.position.x += (self.scene?.size.width)! * 3
node.position.y =
-400
}
}))
}
This creates the ground and scrolls them through the screen at an angle, but the ground nodes do not line up with each other. I imagine I will need some trigonometric function to make them line up? Here is what is currently looks like:
The white rectangles are my ground nodes. The grey is just a placeholder ground node which is not moving and I plan on deleting once I get the scrolling ground working.

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)

Playable Game Area in Swift 3.0

I'm creating a mario clone for mac to help me learn swift programming. An issue I have come across is setting a playable game area. As of now, the 2 backgrounds I have ("background" and "level") will move when the left or right keys are pressed but grey areas at the sides will become visible. I want to be able to make the backgrounds move, but set an area at which they will stop moving.
import SpriteKit
class GameScene: SKScene {
let player = SKSpriteNode(imageNamed: "mario")
let background = SKSpriteNode(imageNamed: "background")
let level = SKSpriteNode(imageNamed: "level")
override func didMove(to view: SKView) {
/* Setup your scene here */
//self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
level.size = self.size
level.position = CGPoint(x: self.size.width/2, y: self.size.height/2)
level.zPosition = 1
self.addChild(level)
background.size = self.size
background.position = CGPoint(x: level.size.width + 511, y: self.size.height/2)
background.zPosition = 0
self.addChild(background)
player.setScale(0.23)
player.position = CGPoint(x: self.size.width/8, y: 120)
player.zPosition = 2
self.addChild(player)
}
override func keyDown(with theEvent: NSEvent) {
let keyCode = theEvent.keyCode
//Moving Right
if keyCode == 124 {
level.run(SKAction.sequence([SKAction.moveBy(x: -20, y: 0, duration: 0.2)]))
background.run(SKAction.sequence([SKAction.moveBy(x: -20, y: 0, duration: 0.2)]))
player.xScale = 0.23
}
//Moving Left
if keyCode == 123 {
background.run(SKAction.sequence([SKAction.moveBy(x: 20, y: 0, duration: 0.2)]))
level.run(SKAction.sequence([SKAction.moveBy(x: 20, y: 0, duration: 0.2)]))
player.xScale = -0.23
}
//Jump
if keyCode == 126{
player.run(SKAction.sequence([SKAction.moveTo(y: 250, duration: 0.15),SKAction.moveTo(y: 120, duration: 0.2)]))
}
}
}
I'm sure there is a much better, more clever solution, but off the top of my head you could add:
let LEFTBOUND: Int = //Insert the left limit here.
let RIGHTBOUND: Int = //Insert the right limit here.
Inside func keyDown(), in the moving right/left if-statements, nest these:
if level.position.x < RIGHTBOUND:
//Move level so long as it is less than the RIGHTBOUND value.
//TODO: set the level.position to RIGHTBOUND so it doesn't keep updating with new values while keyDown is true.
if level.position.x > LEFTBOUND:
//Move level so long as it is greater than the LEFTBOUND value.
//TODO: set the level.position to LEFTBOUND so it doesn't keep updating with new values while the keyDown is true.
//Repeat theses steps for background.position.x
You should also restrict the player movement so the player doesn't run out of the level unrecoverably.

How to fix some physics bodies behavior, when some bodies go off the physics edges?

I am working with a game, which has a physics world. I create physics box around the whole scene for prevent the sprites go off the screen. But the issue is, when i add too many bodies to the scene, some of them go off this physics box.
This is the physics box around the scene:
homeArea.size = CGSizeMake(self.frame.size.width, self.frame.size.height)
homeArea.position = CGPointMake(self.frame.size.width / 2.0, self.frame.size.height / 2.0)
homeLayer.addChild(homeArea)
homeArea.physicsBody = SKPhysicsBody(edgeLoopFromRect: CGRectMake(-homeArea.frame.width / 2.0, -homeArea.frame.height / 2.0, homeArea.frame.size.width, homeArea.frame.size.height))
This is these too many bodies:
func addSprites() {
for i in 0...20 {
for j in 0...20 {
let shape = SKShapeNode(rect: CGRectMake(-5.0, -5.0, 10.0, 10.0))
shape.fillColor = SKColor.redColor()
shape.position = CGPointMake(self.frame.size.width - (shape.frame.size.width * CGFloat(i)), 0.0 + (shape.frame.size.height * CGFloat(j)))
shape.physicsBody = SKPhysicsBody(rectangleOfSize: shape.frame.size)
shape.physicsBody?.dynamic = true
addChild(shape)
}
}
}
And i create a cannon shooting to these bodies. There i want to create something like splash from cannon's bullet. I shoot to this wall from sprites, and notice from nodes count, that because of my bullet, some sprites go off the screen. I added the method usesPreciseCollisionDetection. But it's all the same.