I am playing around trying to learn swift and I am trying to have a brick sprite placed every time a person's touch ends. I'm new and not quite sure of if or how this is possible with spriteKit. I would like to have the brick interact with physics so if there is another way to do this without creating new sprites that would work as well
Just add the method touchesEnded to your class, create a new SpriteNode and add it to your scene. Something like this:
func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
let yourNode = SKSpriteNode(imageNamed: "brick.png") //or the name of the brick texture file, if you have one
yourNode.position = CGPoint(x: 100, y: 100)
self.addChild(yourNode)
}
Here we added the node to (100,100), but you could add it to the location of the touch, adding this inside the method:
for touch in touches {
let location = touch.location(in: self)
yourNode.position = location
}
Remember to import SpriteKit to your class.
Related
Hi I am new to Xcode and Swift, right now I am trying to design a game that involves a spaceship as player with alien spaceships.
I ran into a little problem where I am trying to differentiate the movement of the spaceship from the firing of the spaceship.
Basically I used touchesBegan() function to run the function which my spaceship fires, and touchesMoved() function to move the spaceship's x-position.
These are the code:
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
pShoot()
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
let location = touch.location(in: self)
spaceship.run(SKAction.moveTo(x: location.x, duration: 0.5))
}
}
What I am trying to do is to differentiate the clicking or touching indicator and pressed and move indicator, in other words I dont want the spaceship to fire when I am pressed and move on the screen, and I do not want the spaceship to move when I am clicking constantly but at different position. ( touchesMoved() detects changes in touch positions so if I am clicking at different positions spaceship will move which I dont want)
I would like to know what would be the best way of implementing this, thank you.
You could try checking the area that the user pressed and deciding whether or not to move the spaceship depending on the origin of the touch.
I am very new to using swift and Xcode in general. I wish to create a very simple game and I am trying to figure out why my ball only goes down once rather than go up and down twice when the screen is touched
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let actionUp = SKAction.moveTo(y: 1330, duration: 0.5)
let actionDown = SKAction.moveTo(y: 50, duration: 0.5)
ball?.run(actionUp)
ball?.run(actionDown)
ball?.run(actionUp)
ball?.run(actionDown)
}
Just after the ball is told to move up, before it can do anything, it is told to move down, and then up again, and then down. Only the last action moveDown is seen because there are no other actions after it.
You need SKAction.sequence, otherwise the four actions will be run immediately one after another, before the previous one even finishes.
let sequenceOfActions = SKAction.sequence([moveUp, moveDown, moveUp, moveDown])
ball?.run(sequenceOfActions)
I'm trying to draw a single, straight line using UITouch and Spritekit. Where the line keeps showing during the dragging motion of my finger. if anyone knows a certain tutorial or can run me through the way of doing it i would be thankful
Probably not the best way to implement it, but it's simple. Just copy and paste this into your GameScene.swift
import SpriteKit
import GameplayKit
class GameScene: SKScene {
private var line:SKShapeNode = SKShapeNode()
private var path:CGMutablePath = CGMutablePath()
private var initialPointSet:Bool = false
override func didMove(to view: SKView) {
line.strokeColor = UIColor.orange
line.lineWidth = 4
addChild(line)
}
func touchMoved(toPoint pos : CGPoint) {
if !initialPointSet {
path.move(to: pos)
initialPointSet = true
}
path.addLine(to: pos)
line.path = path
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for t in touches { self.touchMoved(toPoint: t.location(in: self)) }
}
}
SpriteKit has some of the worst 2D drawing ever presented in a 2D game engine.
Actually, the worst.
SKShapeNode and its CGPath are atrocious nonsense. It's as if the
"designers" of SpriteKit have never once looked at the most primitive
of 2D drawing in anything like DirectX or OpenGL. Let alone the kinds
of things that animators might want to do with lines and shape
creation, mutation, distortion and progress and line animation. ~ Confused
Having gotten that little rant off my chest, in the vain hope that it recalibrates your expectations to not expect a drawing style solution, consider this:
SKSpriteNodes can be a simple box, and they can be scaled in both the X and Y axis, and they can be parented to a "dummy" SKNode that rotates to face the direction of the current touch, relative to the original position of the touch.
SO.... you can draw a skinny box, starting at the point of the initial touch, and as the touch is moved, scale the SKSpriteNode to that point by both rotating the SKDummyNode you create to be the parent of your "line", and then scaling it out along that length from the origin to the current position of the touch.
Viola, a LINE!
Of sorts.
I am trying to rotate a sprite using swift, IOS 10 and the touchesmoved function, the code I have works in the fact it moves the sprite but in not the right way, the wrong directions etc.
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
guard let touch=touches.first{
return
}
let touchLocation = touch.location(in: self)
self.zRotation=CGFloat(atan2(Double(touchLocation.y), Double(touchLocation.x)))
}
does anyone know the correct way to rotate a sprite using zRotation and touchesMoved?
Thank you
I think you've probably overlooked the wonderful power of constraints in SpriteKit. Easy enough to do, Apple does a terrible job of promoting, presenting and educating those considering using SpriteKit.
Constraints allow you to say "go here", or "look at this".
In your case, the "look at this" is ideal, from the docs:
Orientation Constraints
A common use for orientation constraints is to make a look-at
constraint. For example, you may create a look-at constraint to make a
pair of eyes follow a moving object or to have a rocket point in the
direction of its target.
More specifically, you can use these in your touchesMoved:
https://developer.apple.com/reference/spritekit/skconstraint/1519627-orient
thanks for all the suggestions. Yes my explanation of the problem was not too great. so will add the full code here and it seems to be working apart from occasionally moving by 90 degrees on its own when i stop dragging and start dragging again
What I was trying to do was rotate a sprite around another sprite for example a cannon barrel around its wheel... When the wheel is loaded from the scene it calls this class and adds a child node (the barrel) which should be able to be moved around its wheel
import SpriteKit
class WheelNode: SKSpriteNode, CustomNodeEvent{
private var tubeNode=SKSpriteNode(imageNamed: "cannon-barrel")
var previousPoint:CGPoint!
var touchLocation:CGPoint!
func didMoveToScene() {
guard let scene=scene else{
return
}
isUserInteractionEnabled=true
tubeNode.anchorPoint=CGPoint(x:0, y:0)
tubeNode.position=position
self.addChild(tubeNode)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
if let touch=touches.first{
previousPoint=touch.location(in: scene!)
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if let touch=touches.first{
touchLocation=touch.location(in: scene!)
var angle=atan2(touchLocation.y-previousPoint.y, touchLocation.x-previousPoint.x)
self.zRotation=angle
}
}
}
I'm attempting to create an overlay in SpriteKit which by using an SKSpriteNode. However, I want the touches to pass through the overlay, so I set isUserInteractionEnabled to false. However, when I do this, the SKSpriteNode still seems to absorb all the touches and does not allow the underlying nodes to do anything.
Here's an example of what I'm talking about:
class
TouchableSprite: SKShapeNode {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("Touch began")
}
}
class GameScene: SKScene {
override func sceneDidLoad() {
// Creat touchable
let touchable = TouchableSprite(circleOfRadius: 100)
touchable.zPosition = -1
touchable.fillColor = SKColor.red
touchable.isUserInteractionEnabled = true
addChild(touchable)
// Create overlay
let overlayNode = SKSpriteNode(imageNamed: "Fade")
overlayNode.zPosition = 1
overlayNode.isUserInteractionEnabled = false
addChild(overlayNode)
}
}
I've tried subclassing SKSpriteNode and manually delegating the touch events to the appropriate nodes, but that results in a lot of weird behavior.
Any help would be much appreciated. Thanks!
Reading the actual sources you find:
/**
Controls whether or not the node receives touch events
*/
open var isUserInteractionEnabled: Bool
but this refers to internal node methods of touches.
By default isUserInteractionEnabled is false then the touch on a child like your overlay SKSpriteNode is, by default, a simple touch handled to the main (or parent) class (the object is here, exist but if you don't implement any action, you simply touch it)
To go through your overlay with the touch you could implement a code like this below to your GameScene.Remember also to not using -1 as zPosition because means it's below your scene.
P.S. :I've added a name to your sprites to recall it to touchesBegan but you can create global variables to your GameScene:
override func sceneDidLoad() {
// Creat touchable
let touchable = TouchableSprite(circleOfRadius: 100)
touchable.zPosition = 0
touchable.fillColor = SKColor.red
touchable.isUserInteractionEnabled = true
touchable.name = "touchable"
addChild(touchable)
// Create overlay
let overlayNode = SKSpriteNode(imageNamed: "fade")
overlayNode.zPosition = 1
overlayNode.name = "overlayNode"
overlayNode.isUserInteractionEnabled = false
addChild(overlayNode)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("GameScene Touch began")
for t in touches {
let touchLocation = t.location(in: self)
if let overlay = self.childNode(withName: "//overlayNode") as? SKSpriteNode {
if overlay.contains(touchLocation) {
print("overlay touched")
if let touchable = self.childNode(withName: "//touchable") as? TouchableSprite {
if touchable.contains(touchLocation) {
touchable.touchesBegan(touches, with: event)
}
}
}
}
}
}
}
You need to be careful with zPosition. It is possible to go behind the scene, making things complicated.
What is worse is the order of touch events. I remember reading that it is based on the node tree, not the zPosition. Disable the scene touch and you should be seeing results.
This is what it says now:
The Hit-Testing Order Is the Reverse of Drawing Order In a scene, when
SpriteKit processes touch or mouse events, it walks the scene to find
the closest node that wants to accept the event. If that node doesn’t
want the event, SpriteKit checks the next closest node, and so on. The
order in which hit-testing is processed is essentially the reverse of
drawing order.
For a node to be considered during hit-testing, its
userInteractionEnabled property must be set to YES. The default value
is NO for any node except a scene node. A node that wants to receive
events needs to implement the appropriate responder methods from its
parent class (UIResponder on iOS and NSResponder on OS X). This is one
of the few places where you must implement platform-specific code in
SpriteKit.
But this may not have always been the case, so you will need to check between 8 , 9, and 10 for consistency