Moving Eight Nodes Across the Screen (At Random Starting Positions/Intervals)? - ios

I’ve created 8 paddles in gamescene.sks. I know how to control them manually but in this case, I want them all to begin automatically oscillating back and forth in their respective ‘lanes’ (meaning they won’t collide with one another) once a button is pressed (I haven’t created the button because idk if that should come before or the paddles function correctly).
I’m not asking for code but I just need a general idea of the commands that I need to implement in order to move a single paddle (positioned randomly) back and forth linearly when a button is pressed. I’m sure I can figure everything else out from there.
Thanks in Advance!!!
START button pressed → 8 paddles (placed randomly in their respective lanes) begin oscillating back and forth (out of sync with one another)
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var squareRight = SKSpriteNode()
var squareLeft = SKSpriteNode()
var paddleL1 = SKSpriteNode()
var paddleL2 = SKSpriteNode()
var paddleL3 = SKSpriteNode()
var paddleL4 = SKSpriteNode()
var paddleR1 = SKSpriteNode()
var paddleR2 = SKSpriteNode()
var paddleR3 = SKSpriteNode()
var paddleR4 = SKSpriteNode()
override func didMove(to view: SKView) {
squareRight = self.childNode(withName: "squareRight") as! SKSpriteNode
squareLeft = self.childNode(withName: "squareLeft") as! SKSpriteNode
paddleL1 = self.childNode(withName: "paddleL1") as! SKSpriteNode
paddleL2 = self.childNode(withName: "paddleL2") as! SKSpriteNode
paddleL3 = self.childNode(withName: "paddleL3") as! SKSpriteNode
paddleL4 = self.childNode(withName: "paddleL4") as! SKSpriteNode
paddleR1 = self.childNode(withName: "paddleR1") as! SKSpriteNode
paddleR2 = self.childNode(withName: "paddleR2") as! SKSpriteNode
paddleR3 = self.childNode(withName: "paddleR3") as! SKSpriteNode
paddleR4 = self.childNode(withName: "paddleR4") as! SKSpriteNode
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}

As a general set of guidelines, I would:
Create a PaddleDirection enum with values of stationary,
movingRight and movingLeft
Subclass SKSpriteNode to create a PaddleNode
Add a property var currentDirection = PaddleDirection.stationary to your PaddleNode.
Make sure all your paddles are PaddleNodes and not SKSpriteNodes
When the start button is pressed, enumerate through all the
PaddleNodes and set their currentDirection properties to movingRight (or left, or randomly select one or the other)
In update() enumerate over all the paddles and adjust their
position according to whether they are moving left or right.
When each paddle reaches the limit of its movement, change its
direction from left to right or vice-versa.

Related

SpriteKit not detecting physics bodies when using alpha mask but does when using bounding circle

I am pretty new to SpriteKit so I may be missing something quite obvious.
I am attempting to create an interactive map of the US. I have loaded PNG images for each state and placed a couple of them into the main SKScene using the scene editor.
My goal is wanting to detect when each state is tapped by the user. I initially wrote some code that would find the nodes within a touch location however, this meant that the user could tap the frame and it would be counted as a valid tap. I only want to register touches that happen within the state texture and not the frame. Reading online it was suggested to use SKPhysicsBody to register when a tap takes place. So I changed my code to the following.
class GameScene: SKScene {
override func didMove(to view: SKView) {}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let location: CGPoint = self.convertPoint(fromView: touch.location(in: self.view))
let body = self.physicsWorld.body(at: location)
if let state = body?.node, let name = state.name {
state.run(SKAction.run({
var sprite = self.childNode(withName: name) as! SKSpriteNode
sprite.color = UIColor.random()
sprite.colorBlendFactor = 1
}))
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
Now, if I choose the Bounding circle body type everything works as expected (shown above in the screenshot). When I click within the boudning circle it runs the SKAction otherwise it does nothing. However, when I change the body type to Alpha mask (the body type I want) it suddenly stops detecting the state. In fact, it returns the SKPhysicsBody for the MainScene entity.
Any advice on how to fix this would be greatly appreciated.
Thanks.
i can reproduce this behavior (bug?) when using the scene editor. however it goes away if you skip the sks file and initialize your sprites in code. (i acknowledge that setting locations for 50 states is more tedious this way.)
class GameScene: SKScene {
let ok = SKSpriteNode(imageNamed: "ok")
let nm = SKSpriteNode(imageNamed: "nm")
let tx = SKSpriteNode(imageNamed: "tx")
override func didMove(to view: SKView) {
tx.name = "Texas"
nm.name = "New Mexico"
ok.name = "Oklahoma"
//set up physics bodies w/ alpha mask
tx.physicsBody = SKPhysicsBody(texture: tx.texture!, size: tx.texture!.size())
tx.physicsBody?.affectedByGravity = false
nm.physicsBody = SKPhysicsBody(texture: nm.texture!, size: nm.texture!.size())
nm.physicsBody?.affectedByGravity = false
ok.physicsBody = SKPhysicsBody(texture: ok.texture!, size: ok.texture!.size())
ok.physicsBody?.affectedByGravity = false
//then position your sprites and add them as children
}
}

Sprite-Kit: Staying Inside Borders Created with Tile Editor

I'm testing the possibility of the tile editor that comes with Xcode 8 (8.2.2). And I've created a PacMan-like map as shown above. There's a game character at the top-left corner in a rectangle. I wonder if there's an easy way of making the game character staying inside the blue borders? So far, I've set a (red) wall to the left like the following through the scene editor. And I have the following lines of code.
struct PhysicsCategory {
static let None: UInt32 = 0
static let Player: UInt32 = 0b1 // 1
static let Edge: UInt32 = 0b10 // 2
static let Wall: UInt32 = 0b100 // 4
}
class GameScene: SKScene {
// MARK: - Variables
var background: SKTileMapNode! // background
var player: SKNode! // player
// MARK: - DidMove
override func didMove(to view: SKView) {
setupNodes()
}
func setupNodes() {
background = self.childNode(withName: "World") as! SKTileMapNode
background.physicsBody = SKPhysicsBody(edgeLoopFrom: background.frame)
background.physicsBody?.categoryBitMask = PhysicsCategory.Edge
let wall = self.childNode(withName: "Wall")
wall?.physicsBody = SKPhysicsBody(rectangleOf: (wall?.frame.size)!)
wall?.physicsBody?.isDynamic = false
wall?.physicsBody?.categoryBitMask = PhysicsCategory.Wall
player = self.childNode(withName: "Player")
player.physicsBody = SKPhysicsBody(circleOfRadius: 32)
player.physicsBody?.categoryBitMask = PhysicsCategory.Player
player.physicsBody?.collisionBitMask = 4
player.physicsBody?.allowsRotation = false
}
}
The user will get to control the player position with CoreMotion. For now, the game character does respect the left edge. But if the map gets complicated, I could end up placing a lot of walls here and there. And that kind of kills the fun as it could be time-consuming. So, again, is there a simplier way of making the game character collide the map borders?
Take a look at GameplayKit's pathfinding classes, specifically GKGridGraph and GKGridGraphNode which allow you to specify a graph that only has these kind of rectilinear paths.
There is a good tutorial from Apple here: https://developer.apple.com/library/content/documentation/General/Conceptual/GameplayKit_Guide/Pathfinding.html
And a demo app here: https://developer.apple.com/library/content/samplecode/Pathfinder_GameplayKit/Introduction/Intro.html#//apple_ref/doc/uid/TP40016461

Q: Spritekit SKPhysics

How can I slide paddles from left to right individually and have the paddle the character jumped on stop while the rest keep sliding? how do I make 4 paddles slowly move to left and right back and forth at the same speed. Please and thank you.
In this code I am trying to make an SKPhysics body for all of them and I don't know how.
override func didMove(to view: SKView) {
background = self.childNode(withName: "background") as! SKSpriteNode
jellyghost = self.childNode(withName: "jellyghost") as! SKSpriteNode
paddle1 = self.childNode(withName: "paddle1") as! SKSpriteNode
paddle2 = self.childNode(withName: "paddle2") as! SKSpriteNode
paddle3 = self.childNode(withName: "paddle3") as! SKSpriteNode
paddle4 = self.childNode(withName: "paddle4") as! SKSpriteNode
jellyghost.physicsBody = SKPhysicsBody()
paddle1.physicsBody = SKPhysicsBody()
paddle2.physicsBody = SKPhysicsBody()
paddle3.physicsBody = SKPhysicsBody()
paddle4.physicsBody = SKPhysicsBody()
}
I am trying to make a SKPhysics body above and I don't how to do that.
and in the code below, I am trying to have each of the 4 paddles move on their own from left to right at the same speed without them moving to the touch and things are not working out for me. right now
override func touchesBegan(_ touches: Set, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
paddle1.run(SKAction.moveTo(x: location.x,duration: 1.0))
paddle2.run(SKAction.moveTo(x: location.x, duration: 1.0))
paddle3.run(SKAction.moveTo(x: location.x, duration: 1.0))
paddle4.run(SKAction.moveTo(x: location.x, duration: 1.0))
}
}
I also want to make my character jump to the moving paddles but I don't know how I would make my character jump up by dragging the screen up and releasing it to the current location of the paddle. How would I make it not restricted to not jumping only straight up but be flexible enough to jump x and y. Thank you
Yes you can. You will need to give the player and each of the paddles a SKPhysicsBody and then use SKPhysicsContactDelegate in you scene to detect collisions between the paddle and the player.
When there is a collision between the paddle and the player you can run a func like the one in the example below to stop the paddle if you are moving your player using velocity.
func stopPaddle(paddle: SKSpriteNode) {
paddle?.physicBody.velocity(CGVector(dx: 0, dy:0)
}
Please upload your code in future, as it will be easier to help you.

Move SKSpriteNode to a specific tile on SKTileMapNode

For simplicity, let's say I have an SKSpriteNode and an SKTileMapNode like so
var background = childNode(withName: "Background") as! SKTileMapNode
var player = SKSpriteNode(imageNamed: "player") as! SKSpriteNode
I want to move player to the row position 5 and column position 8 in background, whats the best way to go about this?
To get started, you could retrieve the position of the specified tile and create a move action to run on the player node.
let destination = background.centerOfTile(atColumn: 8, row: 5)
let action = SKAction.move(to: destination, duration: 5)
player.run(action)
Then you might look at UITapGestureRecognizer so the player can move to where you tap on the map.

How to switch SKScenes in SpriteKit with Swift properly?

I am developing a game with 3 different SKScenes(scene1, scene2, scene3). In GameViewController i initialize all of them like this:
class GameViewController: UIViewController {
var hero = Hero()
var skView: SKView!
var scene1: SKScene!
var scene2: SKScene!
var scene3: SKScene!
override func viewDidLoad() {
super.viewDidLoad()
// init scenes
scene1 = SKScene(size: view.bounds.size, hero: hero)
scene2 = SKScene(size: view.bounds.size, hero: hero)
scene3 = SKScene(size: view.bounds.size, hero: hero)
scene1.scaleMode = .AspectFill
scene2.scaleMode = .AspectFill
scene3.scaleMode = .AspectFill
// set view
skView = self.view as SKView
// present the first scene
skView.presentScene(scene1)
}
My idea is to present the first scene at first and present(swith to) the other scene later(i.e. when hero is stronger). In each scene the hero sprite was added like this:
func addHero() {
let heroSprite = SKSpriteNode(imageNamed: "hero")
hero.sprite = heroSprite
heroSprite.position = CGPoint(x: size.width/4, y: size.height/2)
addChild(heroSprite)
}
And in update method, hero position is updated by touching.
func update() {
if touching {
hero.position++
}
}
Hero class looks like this:
class Hero {
var sprite: SKSpriteNode?
}
The problem is:
The hero is movable by touching when only the first scene(scene1) is initialized. Which means, the hero is not movable any more with code above.
Can anyone give me some advice what have i done wrong? Thanks in advance!
PS: The complete codes can be found in Github.
The issue is solved by another related question: Sprites must be cleaned before switch scenes with SpriteKit and Swift?
By switching scenes, be sure not to add the sprites twice by checking the init status. For example in "didMoveToView", "init" or "setup" method:
if isInit {
do nothing
} else {
add sprites
isInit = true
}

Resources