Adding an enemy every 10 seconds which tracks your location - ios

Below I have part of the code for a simple game I am making. in the game, your finger around the screen a ball is underneath your finger. Then every 10 seconds a ball gets added in which follows your ball. I have an SKAaction which calls my add enemy function every 10 seconds which spawns the enemy. The issue is that I can't make the add enemy function update every frame because the SKAction won't let me call it if its updating every frame, so I'm not sure what to do in order for the the ball to be added in every 10 seconds and to have that ball track your location. Because currently it only tracks the initial location of the ball when it was added in. any help is appreciated, thank you.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var me = SKSpriteNode()
override func didMove(to view: SKView) {
me = self.childNode(withName: "me") as! SKSpriteNode
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 10.0)])))
}
func createEnemy () {
let enemy = SKSpriteNode(imageNamed: "ball 1")
enemy.name = "enemy"
enemy.position = CGPoint(x:667, y: -200)
enemy.run(SKAction.moveTo(x: me.position.x, duration: 2))
enemy.run(SKAction.moveTo(y: me.position.y, duration: 2))
enemy.zPosition = +1
addChild(enemy)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func update(_ currentTime: TimeInterval) {
}
}

Keep a list of all of your currently alive enemies in a dictionary via their .name property. The values in this dictionary are a tuple. This tuple keeps track of the enemy's instance, and its target's instance.
I do this in your createEnemy via makeEnemyName and addEnemyToDict
during update give each enemy a new action to follow its target. This is done by iterating through the dictionary, then using each key's value to moveFollowerToTarget. This information is stored in the tuple type we created.
import SpriteKit
class GameScene22: SKScene {
// MARK: - My code:
// Tuple to keep track of enemy objects:
typealias FollowerAndTarget = (follower: SKSpriteNode, target: SKSpriteNode)
// [followerName: (followerSprite, targetSprite):
var spriteDictionary: [String: FollowerAndTarget] = [:]
// Give each enemy a unique name for the dictionary:
var enemyCounter = 0
// Assign to each enemy a unique name for the dictionary:
private func makeEnemyName() -> String {
enemyCounter += 1
return "enemy\(enemyCounter)"
}
private func addEnemyToDict(enemy: SKSpriteNode, target: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = (enemy, target) }
else { print("enemy not found") } // error!
}
private func removeEnemyFromDict(enemy: SKSpriteNode) {
if let name = enemy.name { spriteDictionary[name] = nil }
else { print("enemy not removed from dictionary!") } // error!
}
// Note, you did not set the enemy to have a constant speed, so the enemy will move at random speeds
// based on how far they are away from the target.
private func moveFollowerToTarget(_ sprites: FollowerAndTarget) {
let action = SKAction.move(to: sprites.target.position, duration: 2)
sprites.follower.run(action)
}
private func allEnemiesMoveToTarget() {
for sprites in spriteDictionary.values {
moveFollowerToTarget(sprites)
}
}
// Use this carefully if you are using phsyics later on:
func killEnemy(_ enemy: SKSpriteNode) {
// Remove this enemy from the update loop:
removeEnemyFromDict(enemy: enemy)
enemy.removeAllActions()
enemy.removeFromParent()
enemy.physicsBody = nil
}
// MARK: - Your code (mostly):
var me = SKSpriteNode()
override func didMove(to view: SKView) {
me = SKSpriteNode(color: .blue, size: CGSize(width: 50, height: 50))
me.name = "me"
addChild(me)
self.anchorPoint = CGPoint(x: 0.5, y: 0.5)
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 10.0)])))
}
func createEnemy () {
let enemy = SKSpriteNode(color: .purple, size: CGSize(width: 30, height: 30))
enemy.name = makeEnemyName()
addEnemyToDict(enemy: enemy, target: me)
moveFollowerToTarget((follower: enemy, target: me))
enemy.zPosition = +1
addChild(enemy)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
allEnemiesMoveToTarget()
}
}
override func update(_ currentTime: TimeInterval) {
// Will iterate through dictonary and then call moveFollowerToTarget()
// thus giving each enemy a new movement action to follow.
allEnemiesMoveToTarget()
}
}

Related

How to drag and flick a node in SpriteKit while gravity is present?

With my current code, the node is extremely laggy, and moves or teleports in random directions for some reason when its flicked. How can i fix this, and also can someone explain why it is teleporting and moving to random places in the scene.
Also, is there anyway to allow the node to be moved only when it is dragged from its position, rather than being at the gesturerecognizer's coordinates at all times?
override func didMove(to view: SKView) {
let gestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.pan(_:)))
view.addGestureRecognizer(gestureRecognizer)
circleNode.physicsBody = SKPhysicsBody(circleOfRadius: 20)
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
self.addChild(circleNode)
}
#objc func pan(_ recognizer: UIPanGestureRecognizer) {
if recognizer.state == .changed {
self.physicsWorld.gravity = CGVector(dx: 0, dy: 0)
var location = recognizer.location(in: self.view!)
location = self.convertPoint(fromView: location)
circleNode.position = location
}
if recognizer.state == .ended {
self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
let transformerX = 1024/self.view!.frame.size.width
let transformerY = 768/self.view!.frame.size.height
let velocity = recognizer.velocity(in: self.view)
circleNode.physicsBody?.applyForce(CGVector(dx: velocity.x * transformerX, dy: velocity.y * transformerY))
}
}
Here is some code I was playing around with. I'm able to drag and flick a spear (spear Image) and also "pop" a pig head. This is the whole GameScene.Remove the code you don't need. :)
import SpriteKit
import CoreMotion
class GameScene: SKScene, SKPhysicsContactDelegate {
enum CollisionTypes: UInt32{
case spear = 1
case wall = 2
case head = 4
}
var touchPoint: CGPoint = CGPoint()
var touching: Bool = false
override func didMove(to view: SKView) {
self.physicsBody = SKPhysicsBody(edgeLoopFrom: self.frame)
//Add contact delegate
physicsWorld.contactDelegate = self
self.backgroundColor = .white
self.addChild(spearNode)
self.addChild(headNode)
}
lazy var spearNode: SKSpriteNode = {
let node = SKSpriteNode(imageNamed: "spear2")
node.name = "Spear"
node.physicsBody = SKPhysicsBody(texture: node.texture!,
size: CGSize(width: node.frame.width , height: node.frame.height))
node.position = CGPoint(x:self.frame.midX , y:self.frame.midY)
node.physicsBody?.affectedByGravity = true
node.physicsBody?.allowsRotation = false
node.size = CGSize(width: node.frame.width , height: node.frame.height )
node.physicsBody?.categoryBitMask = CollisionTypes.spear.rawValue
node.physicsBody?.contactTestBitMask = CollisionTypes.head.rawValue
node.physicsBody?.collisionBitMask = CollisionTypes.head.rawValue
return node
}()
lazy var headNode: SKSpriteNode = {
let node = SKSpriteNode(imageNamed: "Pig")
node.name = "Pig"
node.physicsBody = SKPhysicsBody(texture: node.texture!,
size: CGSize(width: node.frame.width , height: node.frame.height))
node.position = CGPoint(x:self.frame.midX , y:self.frame.maxY - 100)
node.physicsBody?.affectedByGravity = true
node.physicsBody?.allowsRotation = false
node.size = CGSize(width: node.frame.width / 2 , height: node.frame.height / 2 )
node.physicsBody?.categoryBitMask = CollisionTypes.head.rawValue
return node
}()
func didBegin(_ contact: SKPhysicsContact){
guard let nodeA = contact.bodyA.node else {return}
guard let nodeB = contact.bodyB.node else {return}
print("Contacted")
if nodeA.name == "Pig" && nodeB.name == "Spear"{
nodeA.removeFromParent()
}
if nodeA.name == "Spear" && nodeB.name == "Pig"{
nodeB.removeFromParent()
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in:self)
if spearNode.frame.contains(location) {
touchPoint = location
touching = true
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in: self)
touchPoint = location
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
touching = false
}
override func update(_ currentTime: TimeInterval) {
physicsWorld.gravity = CGVector(dx:0, dy: -9.8)
if touching {
let dt:CGFloat = 1.0/60.0
let distance = CGVector(dx: touchPoint.x-spearNode.position.x, dy: touchPoint.y-spearNode.position.y)
let velocity = CGVector(dx: distance.dx/dt, dy: distance.dy/dt)
spearNode.physicsBody!.velocity=velocity
}
}
}
Why not simply impart a force to the object based upon the swipe gesture rather than turning off gravity, manually moving the object, and then turning on gravity again when the swipe is over?

Did touch function not working in SpriteKit

import SpriteKit
class GameScene: SKScene {
var cam: SKCameraNode?
var player: SKSpriteNode?
override func didMove(to view: SKView) {
super.didMove(to: view)
cam = SKCameraNode()
self.camera = cam
self.addChild(cam!)
player = self.childNode(withName: "player") as? SKSpriteNode
}
func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
let touch:UITouch = touches.anyObject() as! UITouch
let touchLocation = touch.location(in: self)
if touchLocation.x < self.frame.size.width / 2 {
let moveRight = SKAction.moveBy(x: 300, y: 0, duration: 1)
player?.run(moveRight)
} else {
let moveLeft = SKAction.moveBy(x: -300, y: 0, duration: 1)
player?.run(moveLeft)
}
}
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
if let camera = cam, let pl = player {
camera.position = pl.position
}
}
}
That is my whole game scene and the sprites I have dragged and dropped onto the screen using the sk scene. I have added a camera to the scene if that affects anything. Thanks for any help.
You need to override the touches began function. It also helps to put in a print statement to show that touches are being received.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
print("touch detected")
let touchLocation = touch.location(in: self)
if touchLocation.x < self.frame.size.width / 2 {
let moveRight = SKAction.moveBy(x: 300, y: 0, duration: 1)
player?.run(moveRight)
} else {
let moveLeft = SKAction.moveBy(x: -300, y: 0, duration: 1)
player?.run(moveLeft)
}
}
}
import SpriteKit
class GameScene: SKScene {
var cam: SKCameraNode?
var player: SKSpriteNode?
override func didMove(to view: SKView) {
super.didMove(to: view)
cam = SKCameraNode()
self.camera = cam
self.addChild(cam!)
player = self.childNode(withName: "player") as? SKSpriteNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
print("touch detected")
let touchLocation = touch.location(in: self)
if touchLocation.x < (player?.position.x)! {
let moveRight = SKAction.moveBy(x: 300, y: 0, duration: 1)
print("right")
player?.run(moveRight)
} else {
let moveLeft = SKAction.moveBy(x: -300, y: 0, duration: 1)
print("Left")
player?.run(moveLeft)
}
}
}
override func update(_ currentTime: TimeInterval) {
super.update(currentTime)
if let camera = cam, let pl = player {
camera.position = pl.position
}
}
}
I figured it out with the help of JohnL. By adding if touchLocation.x < (player?.position.x)! instead of if touchLocation.x < self.frame.size.width / 2

How do I register a tap to the screen to restart the game

Everything I need are commented down below, I have a function that when I tap it, the game should restart. The restart function works by its self, but I only want it to restart after the user taps the screen. If you need some clearing up on what certain parts of the code do, just comment down below please Could you please let me know what I've done wrong, thanks!
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ball = SKSpriteNode()
var enemy = SKSpriteNode()
var main = SKSpriteNode()
var topLbl = SKLabelNode()
var btmLbl = SKLabelNode()
var score = [Int]()
func pauseGame() { // PAUSE GAME FUCTION
self.isPaused = true
self.physicsWorld.speed = 0
self.speed = 0.0
self.scene?.view?.isPaused = true
}
func test(gestureRecognizer: UITapGestureRecognizer) { // MY FUNC TO RESTART THE GAME
let skView = self.view!
skView.presentScene(scene)
}
override func didMove(to view: SKView) {
topLbl = self.childNode(withName: "topLabel") as! SKLabelNode
btmLbl = self.childNode(withName: "btmLabel") as! SKLabelNode
ball = self.childNode(withName: "ball") as! SKSpriteNode
print(self.view?.bounds.height)
enemy = self.childNode(withName: "enemy") as! SKSpriteNode
enemy.position.y = (self.frame.height / 2) - 50
main = self.childNode(withName: "main") as! SKSpriteNode
main.position.y = (-self.frame.height / 2) + 50
let border = SKPhysicsBody(edgeLoopFrom: self.frame)
border.friction = 0
border.restitution = 1
self.physicsBody = border
startGame()
}
func startGame() {
score = [0,0]
topLbl.text = "\(score[1])"
btmLbl.text = "\(score[0])"
ball.physicsBody?.applyImpulse(CGVector(dx: 10 , dy: 10))
}
func addScore(playerWhoWon : SKSpriteNode){
ball.position = CGPoint(x: 0, y: 0)
ball.physicsBody?.velocity = CGVector(dx: 0, dy: 0)
if playerWhoWon == main {
score[0] += 1
ball.physicsBody?.applyImpulse(CGVector(dx: 10, dy: 10))
}
else if playerWhoWon == enemy {
score[1] += 1
ball.physicsBody?.applyImpulse(CGVector(dx: -10, dy: -10))
}
if score[0] >= 10 {
pauseGame()
test() // HERE'S WHERE I TRY AND CALL THE FUNCTION, BUT IT's NOT WORKING
}
else if
score [1] >= 10 {
pauseGame()
test() // HERE'S WHERE I TRY AND CALL THE FUNCTION, BUT IT's NOT WORKING AGAIN
}
topLbl.text = "\(score[1])"
btmLbl.text = "\(score[0])"
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
if currentGameType == .player2 {
if location.y > 0 {
enemy.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
if location.y < 0 {
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
else {
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)
if currentGameType == .player2 {
if location.y > 0 {
enemy.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
if location.y < 0 {
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
else{
main.run(SKAction.moveTo(x: location.x, duration: 0.2))
}
}
}
override func update(_ currentTime: TimeInterval) {
// Called before each frame is rendered
switch currentGameType {
case .easy:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.3))
break
case .medium:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 1.0))
break
case .hard:
enemy.run(SKAction.moveTo(x: ball.position.x, duration: 0.7))
break
case .player2:
break
}
if ball.position.y <= main.position.y - 30 {
addScore(playerWhoWon: enemy)
}
else if ball.position.y >= enemy.position.y + 30 {
addScore(playerWhoWon: main)
}
}
}
As far as I understand, SKScene conforms to UIResponder protocol since you're using touchesBegan and touchesMoved methods. The protocol also has touchesEnded(Set<UITouch>, with: UIEvent?) method.
Basucally you need to add something like:
override func touchesEnded(Set<UITouch>, with: UIEvent?)
{
let skView = self.view!
skView.presentScene(scene)
}
This method is invoked when user removes his finger from the screen after tapping the GameScene object.
You can use UITapGestureRecognizer as well. To do so however, you need to create an instance of it, declare your class as its delegate, add the view you want to tap into its collection and attach a method to it. I've never done this programmatically, only in the IB. The setup looks like so:
To add a tap gesture via code:
In your GameScene class:
weak var tapGesture : UITapGestureRecognizer!
override func didMoveToView(view: SKView) {
tapGesture = UITapGestureRecognizer(target:self,action:#selector(self.handleTap:)
view.addGestureRecognizer(tapGesture )
}
func handleTap(sender:UITapGestureRecognizer){
//restartLogic here
}
deinit{
view.removeGestureRecognizer(tapGesture)
}
Skip the gesture recognizer.
Simply call the restart code from touchesEnded if the game is not in progress.

how to have a enemy be added in every 10 seconds and have this enemy track your location and follow it

im currently working on an app in which your player which is a small round ball, gets dragged around the screen by your finger. Then every 10 seconds a enemy ball gets added in which automatically tracks your ball and follows it until it runs into it. this is the code I have for this so far. you can drag your ball around the screen, bu the enemy ball which is only showing up as a red x even though its file is in the assets gets spawned every frame and they just move to the position of where your ball was when it was spawned. is there any way I can fix this, any help is appreciated. the contact between the balls I will add later on.
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var me = SKSpriteNode()
let enemy = SKSpriteNode (imageNamed: "ellipse 1")
override func didMove(to view: SKView) {
me = self.childNode(withName: "me") as! SKSpriteNode
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func update(_ currentTime: TimeInterval) {
let enemy = SKSpriteNode (imageNamed: "ball 2")
enemy.position = CGPoint(x:667, y: -200)
enemy.run(SKAction.moveTo(x: me.position.x, duration: 1.5))
enemy.run(SKAction.moveTo(y: me.position.y, duration: 1.5))
enemy.zPosition = +1
addChild(enemy)
}
}
So the problem you're having is that your enemy ball images aren't loading, and you're seeing a red X instead?
If so you need to break your code that creates your sprite into steps. First load the image into a temporary variable, print it, and then use the image to create your sprite:
let enemyImage = imageNamed: "ellipse 1"
print("enemyImage = \(enemyImage)")
let enemy = SKSpriteNode (enemyImage)
If enemyImage is nil, you need to figure out why that is.
Here is a modified version of your code that'll spawn an enemy once every 10 seconds and have them follow you. I used the Spaceship graphic provided by Apple's SpriteKit template for the enemy. As for your issue with the enemy graphic not showing up I'd make sure that the image is named "ball 2" in the assets folder.
import SpriteKit
import GameplayKit
class Enemy: SKSpriteNode {
var enemySpeed: CGFloat = 4
}
class GameScene: SKScene {
var me: SKSpriteNode!
var enemies = [Enemy]()
override func didMove(to view: SKView) {
me = self.childNode(withName: "me") as! SKSpriteNode
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
spawnEnemy() // Spawn an enemy to begin with
Timer.scheduledTimer(timeInterval: 10.0, target: self, selector: #selector(spawnEnemy), userInfo: nil, repeats: true) // Spawns an enemy every 10 seconds
}
func spawnEnemy() {
let enemy = Enemy(imageNamed: "Spaceship")
enemy.xScale = 0.25
enemy.yScale = 0.25
enemy.position = CGPoint(x: CGFloat(arc4random() % UInt32(size.width)) - size.width / 2, y: CGFloat(arc4random() % UInt32(size.height)) - size.height / 2)
enemy.zPosition = 1
addChild(enemy)
enemies.append(enemy)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
me.run(SKAction.move(to: location, duration: 0.05))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
let location = touch.location(in: self)
me.run(SKAction.move(to: location, duration: 0.05))
}
}
override func update(_ currentTime: TimeInterval) {
for enemy in enemies {
let angle = CGFloat(atan2f(Float(me.position.y - enemy.position.y), Float(me.position.x - enemy.position.x)))
enemy.zRotation = angle - CGFloat.pi / 2
enemy.position = CGPoint(x: enemy.position.x + cos(angle) * enemy.enemySpeed, y: enemy.position.y + sin(angle) * enemy.enemySpeed)
}
}
}
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var me = SKSpriteNode()
override func didMove(to view: SKView) {
me = self.childNode(withName: "me") as! SKSpriteNode
let border = SKPhysicsBody (edgeLoopFrom: self.frame)
border.friction = 0
self.physicsBody = border
run(SKAction.repeatForever(SKAction.sequence([SKAction.run(createEnemy), SKAction.wait(forDuration: 10.0)])))
}
func createEnemy () {
let enemy = SKSpriteNode(imageNamed: "ball 1")
enemy.name = "enemy"
enemy.position = CGPoint(x:667, y: -200)
enemy.run(SKAction.moveTo(x: me.position.x, duration: 1.5))
enemy.run(SKAction.moveTo(y: me.position.y, duration: 1.5))
enemy.zPosition = +1
addChild(enemy)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
me.run(SKAction.moveTo(x: location.x, duration: 0))
me.run(SKAction.moveTo(y: location.y, duration: 0))
}
}
override func update(_ currentTime: TimeInterval) {
}
}

SKShpapeNode position and touch.location difference

I was learning about SKNodes in Swift and have encountered a problem. App was supposed to be very simple: touching screen and getting node to appear in the touched position. I don't know why but the rectangle keeps showing in different place on the screen but sn.position is the same as touch.location(in: view) position. What's wrong?
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var spinnyNode : SKShapeNode?
private var touchPoint : CGPoint!
override func didMove(to view: SKView) {
let size = CGSize(width: 50, height: 50)
spinnyNode = SKShapeNode(rectOf: size, cornerRadius: CGFloat(0.6)) //init
if let spinnyNode = self.spinnyNode{
spinnyNode.lineWidth = 3
let rotate = SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI), duration: 1))
let fade = SKAction.fadeOut(withDuration: 0.5)
let remove = SKAction.removeFromParent()
spinnyNode.run(rotate)
spinnyNode.run(SKAction.sequence([fade, remove]))
}
}
func touchDown(point pos : CGPoint){
if let sn = self.spinnyNode?.copy() as! SKShapeNode? {
sn.position = CGPoint(x: touchPoint.x , y: touchPoint.y)
print("touchDown x:\(touchPoint.x), y:\(touchPoint.y)")
self.addChild(sn)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard touches.count == 1 else{
return
}
if let touch = touches.first{
touchPoint = touch.location(in: view)
touchDown(point: touchPoint)
print("touchesBegan -> x: \(touchPoint.x) y: \(touchPoint.y)")
}
}
Try doing something like this
import SpriteKit
import GameplayKit
class GameScene: SKScene {
//use whichever image for your node
var ballNode = SKSpriteNode(imageNamed: "ball")
var fingerLocation = CGPoint()
override func didMove(to view: SKView) {
ballNode.size = CGSize(width: 100, height: 100)
ballNode.position = CGPoint(x: self.size.width*0.5, y: self.size.height*0.5)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
if let location = touches.first?.location(in: self){
if let copy = ballNode.copy() as? SKSpriteNode {
copy.position = location
addChild(copy)
}
}
}
}
Every time I click on a random spot, the ball appears. Hope this helps.

Resources