Sprite won't move with finger/ SpriteKit / Swift 3 - swift

*I searched most places and could not find a "basic solution" to my question
Hi there, I am trying to create a simple SKSpriteNode that will move along with my finger anywhere on the screen (x & y coords). So far what I have done is the code below, and I can't seem to figure out much else because my Sprite won't even move when the game is ran. I am also getting an error at:
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
This line of code causes my program to not run since I've added it. Please and thanks for your help.
In this case Sprite "simpleS" is the Sprite I am trying to move when touches begin.
CODE STARTS HERE:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var simpleS = SKSpriteNode()
override func didMove(to view: SKView) {
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
simpleS.physicsBody?.affectedByGravity = true
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
simpleS.run(SKAction.moveTo(x: location.x, duration: 0.0))
simpleS.run(SKAction.moveTo(y: location.y, duration: 0.0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
simpleS.run(SKAction.moveTo(x: location.x, duration: 0.0))
simpleS.run(SKAction.moveTo(y: location.y, duration: 0.0))
}
}
}

this code
simpleS = self.childNode(withName: "simpleS") as! SKSpriteNode
connects the sprites in your GameScene.sks with GameScene.swift
so in the first step you have to make sure that you set the right name (exactly "simpleS") in your sks file.
if you did it right, so please send the error for us.
i have built and ran your code and everything works in a right way.
another point is that if you want your sprites only moves by your finger movement you have to delete the codes in touchesBegan function, because touchesBegan moves your sprite wherever you touch.

Related

Spritekit: Dragging a SKCameraNode()

I am rather new to Swift and SpriteKit. I made a plane move around on a big background. What I am trying to do now is DRAG the "camera" so i can see the plane when its outside my view.
I made a SKCameraNode()
I can change its position without problem. And then I tried this for drag:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let location = touch.location(in: self)
camera?.position = CGPoint(x: location.x, y: location.y)
}
}
The camera moves when i drag, but super fast and far far far away...
Some ideas? Thanks!

Swift SpriteKit add physics to user-drawn line

I want to create a game in which the player draws a line with physics, similar to the game Happy Glass.
What I have tried:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
touchPosition = location
}
}
func draw(pos: CGPoint){
let node = SKSpriteNode(imageNamed: "circle")
node.position = CGPoint(x: pos.x, y: pos.y)
node.size = CGSize(width: 10, height: 10)
node.physicsBody = SKPhysicsBody(circleOfRadius: node.frame.width / 2)
//set up the physics
self.addChild(node)
}
override func didSimulatePhysics() {
if touching{
draw(pos: touchPosition)
}
}
So I basically change the touchPosition variable every time a touch is moved(when the user drags their finger across the screen) then I have didSimulatePhysics as repeating timer to add small circles at the touchPosition with physics on them.
The Problem:
This all works. The only problem is that they are too spread out. I want it to be a continuous line but the touchesMoved method is not recognizing enough touches so it looks like this.
Is there a way to recognize touches more frequently so I can fill an entire line or some way to possibly do this with a CGPath? I just can't have these gaps in between these points basically because I can't have other nodes with physicBodies falling between the cracks.
The other thing is that the points are constantly moving off the screen with a SKAction, so I can just draw a CGPath line from the current touch to the last touch because the point from the last touch will have moved slightly so i'm kind of confused in what to do and any suggestions would be helpful.
Thanks

Sprite Nodes Phasing

I am trying to make a maze app. The goal is to move a ball (drag the ball with your finger) through a "maze" like level which has traps and other dangers. However, when I made it so the ball/player moves when its dragged, it started to now phase though the other sprite nodes instead of staying inside of the level. How can I make it so it doesn't go outside of the level?
Code:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKSpriteNode()
var danger1 = SKSpriteNode()
var danger2 = SKSpriteNode()
var goal = SKSpriteNode()
override func didMove(to view: SKView) {
ball = self.childNode(withName: "ball") as! SKSpriteNode
danger1 = self.childNode(withName: "danger1") as! SKSpriteNode
danger2 = self.childNode(withName: "danger2") as! SKSpriteNode
goal = self.childNode(withName: "goal") as! SKSpriteNode
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 0
print("x: \(ball.position.x), y: \(ball.position.y)")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
ball.position.x = location.x
ball.position.y = location.y
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
Screenshot of game:
Maze Level
You need to set up a collisionBitMask for your nodes and set up your desired collision rules accordingly (i.e. prevent ball from clipping through the maze walls or dangers):
I'd recommend looking at the corresponding apple developer docs: https://developer.apple.com/documentation/spritekit/skphysicsbody/1520003-collisionbitmask
This other question's answer may also prove helpful: What are Sprite Kit's "Category Mask" and "Collision Mask"?
This was also a video that I found helpful when learning about bitmasks for detecting collisions & contact between SKSpriteNodes: https://youtu.be/467Doas5J6I?t=1114
*Edit*
You will also need to set up contact detection via contactTestBitMask so that you know when the ball has contacted the wall, at which point you can implement logic to ‘drop’ it from the dragging gesture. As #Steve Ives correctly noted, the dragging will override the collision physics and you would still get clipping without this.
Your major problem is you are moving your ball directly, ala hand of god.
What you need to do is play by the systems rules. Instead of applying the position directly, set the velocity of your ball to push your ball to where your finger is. This requires some math:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
//set the location's coordinate system to match the ball
let location = touch.location(in: ball.parent)
let angle = atan2(location.x,location.y)
let velocity = 1.0f //(change this to whatever speed you want your ball to move at)
ball.velocity = CGVector(velocity * cos(angle),velocity * sin(angle)) // you may have to swap around the sin/-sin/cos/-cos to get it the way you like it, I am assuming at angle 0 your ball is facing right, and it rotates in a counter clockwise direction)
}
}
Now your ball will forever be pushed towards the touching point.
To avoid bouncing, make sure you set the restitution to 0 on the physics body so that it loses all of its energy when it hits a wall.
Also check categoryBitmask is of some power of 2 on all objects that require physics (1 works in your example) so that it can collide with whatever is in its way

SpriteKit Swift: How to make a sprite jump in place when tapped?

So Ive been working on a game and have a little sprite that is currently running in place. I need to make him jump up whenever the user taps the screen to dodge obstacles. I also need him to return to his starting point on the ground after he jumps.
You can try something like this!
import SpriteKit
class GameScene: SKScene {
var player: SKSpriteNode?
override func didMove(to view: SKView) {
player = self.childNode(withName: "player") as? SKSpriteNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchDown(atPoint: t.location(in: self)) }
}
func touchDown(atPoint pos: CGPoint) {
jump()
}
func jump() {
player?.texture = SKTexture(imageNamed: "player_jumping")
player?.physicsBody?.applyImpulse(CGVector(dx: 0, dy: 500))
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchUp(atPoint: t.location(in: self)) }
}
func touchUp(atPoint pos: CGPoint) {
player?.texture = SKTexture(imageNamed: "player_standing")
}
}
On the player's attribute inspector window make sure you select 'Dynamic' and 'Affected By Gravity' options only, otherwise it will not fall back to the ground after the jump.. :)
I don't think physics would be overkill for a simple game as someone said in the previous answer... It's not a big deal for an iPhone or iPad hardware, they have a crazy computing power.
Using physics is overkill for a game like this. Not even the 2D Mario games use physics so I doubt you will need it.
As a very simple implementation you can use a sequence of SKActions.
// move up 20
let jumpUpAction = SKAction.moveBy(x: 0, y: 20, duration: 0.2)
// move down 20
let jumpDownAction = SKAction.moveBy(x: 0, y: -20, duration: 0.2)
// sequence of move yup then down
let jumpSequence = SKAction.sequence([jumpUpAction, jumpDownAction])
// make player run sequence
player.run(jumpSequence)
That should work. I may have mistyped something in the browser though.
You can tweak this to make the jump look more natural. Maybe add a few more steps to the jump process to change the speed of the rise/fall over time to make it look like he's accelerating. etc...

SpriteKit Gravity

Im just messing around in sprite-kit working on my game design skills and I came across something that I dont know how to do. That is make the physicsworld gravity more like moon gravity. I have a SKSpriteNode which is a red ball and I can drag that ball and click wherever I want it to go. What I wanted to create is somewhat of a throwing mechanism. Is this possible with one line of physics world gravity code? Or is it way more in depth this is code that I have.
import SpriteKit
class GameScene: SKScene {
let redBall = SKSpriteNode(imageNamed: "redball")
override func didMoveToView(view: SKView) {
let worldBorder = SKPhysicsBody(edgeLoopFromRect: self.frame)
self.physicsBody = worldBorder
self.physicsBody?.friction = 1
self.physicsWorld.gravity = CGVectorMake(0, -1)
redBall.position = CGPoint(x:250,y:50)
addChild(redBall)
redBall.physicsBody = SKPhysicsBody(circleOfRadius: redBall.size.width/2)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
redBall.position = location
}
override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let location = touch.locationInNode(self)
redBall.position = location
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
My game state right now is when I drag a ball to where I want and release it just drops. What I want to accomplish is for example if I grab the ball and drag up and to the right I want the ball to follow my the direction it was going when I released it. How would I create that in my code thanks!
In my code all I do is self.physicsworld.gravity = CGVectorMake(0, 0) (this would turn off gravity completely). Then just mess around with that vector and find something that feels like moon gravity.
You might have to make your game-scene be a SKPhysicsContactDelegate