I have a main player node and enemies coming down randomly, but parts of them are outside the frame, I want to make it so they (and the player) are not able to get out of frame, left and right borders. How can I achieve that?
Thank you for your time and effort :)
Here's my enemy line, not sure how this can help but here it is so I don't get reported for being 'too broad'
func launchEnemy() {
let randomX = arc4random_uniform( UInt32(screenWidth))
EnemyMissile.position = CGPoint( x: CGFloat(randomX) - (screenWidth / 2), y: screenHeight + 50)
let action = SKAction.move(by: CGVector(dx: 0, dy: -400 + speedScore), duration: 5.0)
EnemyMissile.run(SKAction.repeatForever(action))
increaseSpeed()
self.run(action, withKey:"LaunchEnemyAction")
}
Here's my EnemyClass
import Foundation
import SpriteKit
class EnemyClass: SKNode {
var EnemyNode:SKSpriteNode = SKSpriteNode()
var hitsToKill:Int = 2
var hitCount:Int = 0
var damagePoints: Int = 2
//var missileAnimation:SKAction?
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) had not been implemented")
}
override init () {
super.init()
}
func createEnemy ( _ theImage:String) {
EnemyNode = SKSpriteNode(imageNamed: theImage)
self.addChild(EnemyNode)
let body:SKPhysicsBody = SKPhysicsBody(circleOfRadius: EnemyNode.size.width / 2.25, center:CGPoint(x: 0,y: 0))
body.isDynamic = true
body.affectedByGravity = false
body.allowsRotation = false
body.categoryBitMask = BodyType.enemy.rawValue
body.contactTestBitMask = BodyType.bullet.rawValue | BodyType.player.rawValue
self.physicsBody = body
self.name = "EnemyClass"
}
func destroy() {
self.removeFromParent()
self.name = "removeNode"
}
func hit() -> Bool {
hitCount += 1
if ( hitCount == hitsToKill) {
destroy()
return true
} else {
damagePoints = 4
EnemyNode.removeAction(forKey: "animation")
return false
}
}
}
Basically you have 2 issues:
You have a few options for setting boundaries, one being a physicsBody, another being keepInBounds()
method or such. Below I should a simple keep in bounds method:
class GameScene: SKScene {
func spawnEnemy() {
let offset = CGFloat(5) // pixels, so enemy will have some spacing between borders.
let enemy = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 100))
enemy.name = "enemy"
addChild(enemy)
var randomX = CGFloat(arc4random_uniform(UInt32(self.size.width))) // This is not a perfect rando algo.
// Because our random x was from 0 through screenwidth, but .position works
// on -halfWidth through +halfWidth
randomX -= (self.frame.size.width / 2)
// Because spawning on the border will mean that the enemy is HALF out of view:
/*
right border: |
enemy @ frame.maxX: x
- offset: x|
- size.w/2 x |
*/
if randomX > self.frame.maxX - offset - (enemy.size.width / 2) {
randomX = self.frame.maxX - offset - (enemy.size.width / 2)
}
else if randomX < self.frame.minX + offset + (enemy.size.width / 2) {
randomX = self.frame.minX + offset + (enemy.size.width / 2)
}
enemy.position.x = randomX
}
func keepEnemyInBounds() {
// A better way to do this would be to have a dictionary of enemies:
for node in self.children {
guard node.name == "enemy" else { continue }
let enemy = node as! SKSpriteNode
if enemy.position.x > frame.maxX - (enemy.size.width / 2) {
enemy.position.x = frame.maxX - (enemy.size.width / 2)
}
else if enemy.position.x < frame.minX + (enemy.size.width / 2) {
enemy.position.x = frame.minX + (enemy.size.width / 2)
}
}
}
override func update(_ currentTime: TimeInterval) {
spawnEnemy()
}
override func didFinishUpdate() {
keepEnemyInBounds()
}
}