How to move sprite relative to its original position with touch in spritekit - swift

I looking to move a sprite relative to the player's touch. I am familiar with the moveTo SKActions, however I am wondering how to implement sprite movement where the sprite moves along with the user's touch movement.
For example, I have a sprite in the centre of the screen. If I apply a touch at the bottom of the screen and move my finger up , the sprite will move up from the centre(it's original position).
Thanks!

Try this :
import SpriteKit
class GameScene: SKScene {
var node = SKSpriteNode()
var nodePosition = CGPoint()
var startTouch = CGPoint()
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
// node set up
node = SKSpriteNode(color: .red, size: CGSize(width: 50, height: 50))
node.position = CGPoint.zero
self.addChild(node)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
startTouch = location
nodePosition = node.position
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first
if let location = touch?.location(in: self){
node.run(SKAction.move(to: CGPoint(x: nodePosition.x + location.x - startTouch.x, y: nodePosition.y + location.y - startTouch.y), duration: 0.1))
}
}
}

Related

Getting Sprite To Move Slowly Toward Touch

I'm trying to have the "player" sprite move slowly toward touches on the screen. The code that I have now moves the sprite immediately to where the touch happens on the screen. Here is my current code. Thanks!
//
// GameScene.swift
// testing
//
// Created by Matthew Jahnes on 7/3/18.
// Copyright © 2018 Matthew Jahnes. All rights reserved.
//
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var player = SKSpriteNode()
override func didMove(to view: SKView) {
self.anchorPoint = CGPoint(x:0.5, y:0.5)
player = SKSpriteNode(color: UIColor.red, size: CGSize(width: 90, height:90))
player.position = CGPoint(x:0, y:0)
self.addChild(player)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
player.position.x = location.x
player.position.y = location.y
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
}
}
You need to
Create an action for moving the player to the destination point.
Stop the previous move action if exists
Run the new move action
Here's the code
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else { return }
let destination = touch.location(in: self)
let move = SKAction.move(to: destination, duration: 2)
player.removeAction(forKey: "move")
player.run(move, withKey: "move")
}

Making my game object bounce forever?

So I am trying to make a ping pong game and I am able to get the ball moving and bouncing but the ball slows down. Whats the code to keep the balls velocity at a constant? Here's what I got:
var ball = SKSpriteNode()
var enemy = SKSpriteNode()
var main = SKSpriteNode()
override func didMove(to view: SKView) {
ball.physicsBody = SKPhysicsBody(circleOfRadius: ball.size.width)
ball = self.childNode(withName: "ball") as! SKSpriteNode
enemy = self.childNode(withName: "enemy") as! SKSpriteNode
main = self.childNode(withName: "main") as! SKSpriteNode
ball.physicsBody?.applyImpulse(CGVector(dx: 20, dy: 20))
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.0))
}
}
My physics settings are set to the following:
physics definition
Thanks in advance!

App crash when 2 fingers are on the screen, touches began, touches moved

I'm not sure what's happening so i can't really describe it to you properly, I made an app that draws a line with the dragging of the users finger, its a sprite kit Game so i used touchesBegan and touchesMoved, so what happens is if i place a finger on the screen while I'm drawing another line the game crashes. what I'm looking for is a way to ignore the second touch until the first is over.My game Draws a line from the start position of the touch till the end position when the touches end
here is the code in my touches functions
var lineNode = SKShapeNode()
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
positionOfStartTouch = touch.location(in: self)
lastPoint = touch.location(in: self)
firstPoint = touch.location(in: self)
}
let pathToDraw = CGMutablePath()
print(pathToDraw.isEmpty)
pathToDraw.move(to: CGPoint(x: firstPoint.x, y: firstPoint.y))
if frame.width == 375 {
lineNode.lineWidth = 4
}else if frame.width == 414 {
lineNode.lineWidth = 6
}else if frame.width == 768 {
lineNode.lineWidth = 8
}
lineNode.strokeColor = UIColor.white
lineNode.name = "Line"
lineNode.zPosition = 100000
lineNode.path = pathToDraw
self.addChild(lineNode)
shapeNodes.append(lineNode)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
positionInScene = touch.location(in: self)
}
let pathToDraw = lineNode.path as! CGMutablePath
lineNode.removeFromParent()
pathToDraw.move(to: CGPoint(x: firstPoint.x, y: firstPoint.y))
pathToDraw.addLine(to: CGPoint(x: positionInScene.x, y: positionInScene.y))
lineNode.path = pathToDraw
shapeNodes.append(lineNode)
self.addChild(lineNode)
firstPoint = positionInScene
}
The node can only have one parent. You are trying to add lineNode multiple times the the scene. Try this:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch: AnyObject in touches{
positionInScene = touch.location(in: self)
}
let pathToDraw = lineNode.path as! CGMutablePath
lineNode.removeFromParent()
pathToDraw.move(to: CGPoint(x: firstPoint.x, y: firstPoint.y))
pathToDraw.addLine(to: CGPoint(x: positionInScene.x, y: positionInScene.y))
lineNode.path = pathToDraw
if let copy = lineNode.copy() as? SKShapeNode {
shapeNodes.append(copy)
self.addChild(copy)
}
firstPoint = positionInScene
}
Do the same in touchesBegan. Of course I am not going into your logic about what should happen when multiple touches occur. I am just pointing out where is the error and why your app crashes.

Bullet Firing In Direction Of Tap

So far, my app has a big ball in the middle and a small ball in the middle also. I would like to be able to tap anywhere on the screen and the small ball shoots in that direction. I've heard people say about creating vectors but I can't seem to get these working in swift 3. I am a beginner so sorry about a stupid question!
Here is my code:
var mainBall = SKSpriteNode(imageNamed: "Ball")
override func didMove(to view: SKView) {
mainBall.size = CGSize(width: 300, height: 300)
mainBall.position = CGPoint(x: frame.width / 2, y: frame.height / 2)
self.addChild(mainBall)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch = touches.first {
let position = touch.location(in: self)
print(position.x)
print(position.y)
}
for touch in (touches) {
touch.location(in: self)
let smallBall = SKSpriteNode(imageNamed: "Ball")
smallBall.position = mainBall.position
smallBall.size = CGSize(width: 100, height: 100)
smallBall.physicsBody = SKPhysicsBody(circleOfRadius: smallBall.size.width / 2)
smallBall.physicsBody?.affectedByGravity = false
self.addChild(smallBall)
}
}
You can use actions to animate SKSprideNodes:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard let touch = touches.first else {
return
}
let newPosition = touch.location(in: self)
...
//assuming self.smallBall exists and is visible already:
[self.smallBall runAction:[SKAction moveTo:newPosition duration:1.0]];
}

Apply impulse depending on rotation - Swift

I am currently creating a 2D game in which I have a cannon staying at the bottom of the screen that fires projectiles to some targets in the upper part of the screen. The user can rotate the cannon in order to aim for the targets. I want the projectile to be fired to the location that the canon faces. I have no idea how to do that and I need your help... Heres my code ->
import SpriteKit
class GameScene: SKScene {
var canon = SKSpriteNode()
var projectile = SKSpriteNode()
var touching = false
var locked = false
var location = CGPoint()
override func didMoveToView(view: SKView) {
/* Setup your scene here */
projectile.position = canon.position
projectile.color = UIColor.whiteColor()
projectile.size = CGSize(width: 50, height: 50)
projectile.physicsBody?.affectedByGravity = false
projectile.physicsBody?.linearDamping = 1
projectile.physicsBody?.dynamic = true
addChild(projectile)
canon.zPosition = 2
canon = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 50, height: 200))
canon.position = CGPoint(x: self.size.width/2.0, y: 10)
addChild(canon)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
/* Called when a touch begins */
touching = true
let touch = touches.first as UITouch!
location = touch.locationInView(self.view)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
rotateCanon(location.x)
projectile.zRotation = canon.zRotation
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
touching = false
}
func rotateCanon(locationx:CGFloat) {
if locationx <= frame.width/5 && touching {
print(1)
canon.runAction(SKAction.rotateByAngle(0.01, duration: 0.1))
}
if locationx > frame.width/5 && touching {
print(2)
canon.runAction(SKAction.rotateByAngle(-0.01, duration: 0.1))
}
}
}`
Thanks a lot if you can help that would be awesome :D