Move SKSpriteNode to a specific tile on SKTileMapNode - ios

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.

Related

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

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.

Moving SKNode by One Tile From Its Current Position

I'm playing with the tile editor, with which I've created a simple, somewhat large map like the following. The tile size is 64 x 64. And the map size is 58 x 32.
And I want to know the current position of the game character. Let me call it player (as SKNode). I want to know this guy's current position so that I can find out whether any of its adjascent tile is NOT an obstacle. The following lines of code gives me (7, -3).
background = self.childNode(withName: "World") as! SKTileMapNode
let position = background.convert(player.position, from: player)
let column = background.tileColumnIndex(fromPosition: position)
let row = background.tileRowIndex(fromPosition: position)
print(column, row)
, which suggests that these coordinates point to the center of the camera, indicated by the red circle. The following gives me (10, 2).
let position = background.convert(player.position, from: self)
let column = background.tileColumnIndex(fromPosition: position)
let row = background.tileRowIndex(fromPosition: position)
That's the position from the bottom-left corner.
Now, if I want to move the game character up by 1 tile, writing...
let position = background.convert(player.position, from: player)
let column = background.tileColumnIndex(fromPosition: position)
let row = background.tileRowIndex(fromPosition: position)
let destination = background.centerOfTile(atColumn: column, row: row + 1)
let action = SKAction.move(to: destination, duration: 1)
player.run(action)
, the game character will go missing in action, disappearing from the face of the map. So how can I move the node by one tile?
Maybe try this:
let currentPlayerPosition = background.convert(player.position, from: player)
let column = background.tileColumnIndex(fromPosition: currentPlayerPosition)
let row = background.tileRowIndex(fromPosition: currentPlayerPosition)
let destination = background.centerOfTile(atColumn: column, row: row + 1)
// the new line I added
let newPlayerPosition = background.convert(destination, to: player)
let action = SKAction.move(to: newPlayerPosition, duration: 1)
player.run(action)

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.

SceneKit NSNode split parts

My SceneKit project uses an imported .OBJ file, which contains only one node with a huge image. Image comprises different objects or parts. I need to tap on a foot, or image specific part, and have it highlighted.
This is code to import .obj File
sceneView = SCNView(frame: self.view.frame)
self.view.addSubview(sceneView)
let scene = SCNScene(named: "OBJ.obj")!
print("\(scene.rootNode.childNodes.first?.geometry?.materials.count)")
sceneView.scene = scene
and here I am using tap gesture recognizer
// add a tap gesture recognizer
let doubleTapRecognizer = UITapGestureRecognizer(target: self, action : #selector(self.tapGesture(sender:)));
doubleTapRecognizer.numberOfTapsRequired = 1;
doubleTapRecognizer.numberOfTouchesRequired = 1;
sceneView.addGestureRecognizer(doubleTapRecognizer);
func tapGesture(sender: UITapGestureRecognizer){
let hitResult : SCNHitTestResult
// check what nodes are tapped
let p = sender.location(in: sceneView)
let hitResults = sceneView.hitTest(p, options: nil)
}
I have 3D Model with different parts like left foot right foot and floor needed to be tapped and show different color on them. The problem is that all of these are in single node.
Your SCNHitTestResult will give you the index of the triangle that was tapped. But you'll still have to work out the logic of going from a single triangle to recognizing "that was the left arm".
I think your best bet is to go back to your 3D modeling software and break the object into smaller, logical components.

SpriteKit, Swift - How do I tap the button instead of starting my game?

Ok, I currently have four gesture recognises in my class
let TapUpRec = UITapGestureRecognizer()
let swipeRightRec = UISwipeGestureRecognizer()
let swipeLeftRec = UISwipeGestureRecognizer()
let swipeDownRec = UISwipeGestureRecognizer()
I have recently added a button node in my scene and was trying to get it to click without using the touches function and was wondering how I implement it so I can click on the screen to start my game but also click the button when I want, without starting the game.
Here is my tap function that moves the player forward currently:
func tapUp(){
let amountToMove:CGFloat = levelUnitHeight
let move:SKAction = SKAction.moveByX(0, y: amountToMove, duration: 0.1)
thePlayer.runAction(move)
clearNodes()
}

Resources