I am trying create a CGPath for a node to follow but when I have tried using SKShapeNode as defined in the actions and constants slide from 608_hd_best_practices_for_building_spritekit_games I get the error Extra argument 'count' in call. Any thoughts?
import SpriteKit
class GameScene: SKScene {
var groundNode: SKSpriteNode? = SKSpriteNode()
var path = [CGPoint]()
override func didMoveToView(view: SKView) {
groundNode = childNodeWithName("ground") as? SKSpriteNode
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
path = [CGPoint]()
}
override func touchesMoved(touches: NSSet, withEvent event: UIEvent) {
var newPoint = touches.anyObject()?.locationInNode(groundNode)
path.append(newPoint!)
}
override func touchesEnded(touches: NSSet, withEvent event: UIEvent) {
let sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite.xScale = 0.25
sprite.yScale = 0.25
sprite.position = path.first!
groundNode?.addChild(sprite)
// TODO: this currently isnt working
let count = path.count
// CGPathRef p = [SKShapeNode shapeWithSplinePoints:points]
let p: CGPathRef = SKShapeNode(splinePoints: path, count: count)
let speed:CGFloat = 1.0
let action = SKAction.followPath(p, speed: speed)
sprite.runAction(action)
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
init(splinePoints:count:) takes an UnsafeMutablePointer<CGPoint> (i.e., a C array of CGPoints) and an unsigned integer as its arguments. It also returns an SKShapeNode object not a CGPathRef. Try the following...
let p = SKShapeNode(splinePoints: &path, count: UInt(count))
EDIT: Make the following changes as well
let speed:CGFloat = 1.0
let action = SKAction.followPath(p.path, speed: speed)
sprite.runAction(action)
Related
I would like to repeatedly show one of the two games cards, whenever the user touches the deckOfCards.
I got it working once so far, but when I tap on the deckOfCards again, the card does not change. Trying this with 10 or more card names, didn't work either.
class GameScene: SKScene {
let cardname = ["card2", "ace"]
let randomNumber = Int(arc4random_uniform(13))
var deckOfCards = SKSpriteNode()
var yourCard = SKSpriteNode()
override func didMove(to view: SKView) {
deckOfCards = self.childNode(withName: "deckOfCards") as! SKSpriteNode
yourCard = self.childNode(withName: "yourCard") as! SKSpriteNode
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view?.endEditing(true)
for touch: AnyObject in touches {
let location = touch.location(in: self)
let node : SKNode = self.atPoint(location)
if node.name == "deckOfCards" {
yourCard.texture = SKTexture(imageNamed: "\(cardname[randomNumber])")
}
}
}
randomNumber is a constant outside of touchesBegan. It never changes. Put it inside touchesBegan.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view?.endEditing(true)
for touch: AnyObject in touches {
let location = touch.location(in: self)
let node = self.atPoint(location)
let randomNumber = Int(arc4random_uniform(13))
if node.name == "deckOfCards" {
yourCard.texture = SKTexture(imageNamed: "\(cardname[randomNumber])")
}
}
}
I'm having trouble with adding and removing my SKPhysicsJointPin in the touchesBegan function. The issue is that my joint is declared in the didMoveToView function because it needs to be positioned based on expressions that exists within it.
That being so I can't refer to the SKPhysicsJoint within the touchesBegan function, which is necessary for what I'm trying to do with my project. Any solutions or suggestions?
Code:
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate {
var head = SKSpriteNode(imageNamed: "crown.png")
var headTexture = SKTexture(imageNamed: "crown.png")
var neck = SKSpriteNode(imageNamed: "throat.png")
var neckTexture = SKTexture(imageNamed: "throat.png")
override func didMoveToView(view: SKView) {
head.position.x = torso.position.x - 1
head.position.y = torso.position.y + 77
head.physicsBody = SKPhysicsBody(texture: headTexture, size: head.size)
head.physicsBody!.categoryBitMask = ColliderType.part.rawValue
head.physicsBody!.contactTestBitMask = ColliderType.part.rawValue
head.physicsBody!.collisionBitMask = ColliderType.part.rawValue
self.addChild(head)
neck.position.x = torso.position.x
neck.position.y = torso.position.y + 44
neck.physicsBody = SKPhysicsBody(texture: neckTexture, size: neck.size)
neck.physicsBody!.categoryBitMask = ColliderType.mjoint.rawValue
neck.physicsBody!.contactTestBitMask = ColliderType.mjoint.rawValue
neck.physicsBody!.collisionBitMask = ColliderType.mjoint.rawValue
self.addChild(neck)
let headToNeck = SKPhysicsJointPin.jointWithBodyA(head.physicsBody!, bodyB:neck.physicsBody!, anchor:CGPointMake(head.position.x, head.position.y - 20.8))
headToNeck.shouldEnableLimits = true
self.physicsWorld.addJoint(headToNeck)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.removeJoint(headToNeck)
}
}
Try creating a class variable like this:
class GameScene: SKScene, SKPhysicsContactDelegate {
var headToNeck: SKPhysicsJoint!
//other variables
override func didMoveToView(view: SKView) {
//other code
self.headToNeck = SKPhysicsJointPin.jointWithBodyA(head.physicsBody!, bodyB:neck.physicsBody!, anchor:CGPointMake(head.position.x, head.position.y - 20.8))
self.headToNeck.shouldEnableLimits = true
self.physicsWorld.addJoint(self.headToNeck)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
self.physicsWorld.removeJoint(self.headToNeck)
}
}
I'm moving a sprite by using the touchesMoved method. So far this is working fine, but the result looks a little bit unnatural. The sprite stops immediately, once the movement of my finger stops. A more natural impression would be, if the sprite continuous the movement a little time with an ease out function. Any idea how to implement this?
Here is my code:
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode?
var xOrgPosition: CGFloat = 0.0
override func didMoveToView(view: SKView) {
sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite!.xScale = 0.1
sprite!.yScale = 0.1
sprite!.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(sprite!)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
let xTouchPosition = touch.locationInNode(self).x
if xOrgPosition != 0.0 {
// calculate the new position
sprite!.position = CGPoint(x: sprite!.position.x - (xOrgPosition - xTouchPosition), y: sprite!.position.y)
}
// Store the current touch position to calculate the delta in the next iteration
xOrgPosition = xTouchPosition
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Reset value for the next swipe gesture
xOrgPosition = 0
}
}
Update:
I've made a short sample project, based on the answers from hamobi
Tutorial
Git repository
i think this might be what youre going for. let me know if you have any questions :)
import SpriteKit
class GameScene: SKScene {
var sprite: SKSpriteNode?
var xOrgPosition: CGFloat?
override func didMoveToView(view: SKView) {
sprite = SKSpriteNode(imageNamed:"Spaceship")
sprite!.xScale = 0.1
sprite!.yScale = 0.1
sprite!.position = CGPoint(x:CGRectGetMidX(self.frame), y:CGRectGetMidY(self.frame));
self.addChild(sprite!)
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in touches {
xOrgPosition = touch.locationInNode(self).x
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
xOrgPosition = nil
}
override func update(currentTime: NSTimeInterval) {
if let xPos = xOrgPosition {
sprite!.position.x += (xPos - sprite!.position.x) * 0.1
}
}
}
I have the following segment of code in which I want a tap to cause the ball to move in my screen.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
moveBallUp()
moveBallLeft()
moveBallRight()
}
func moveBallUp() -> Void {
ball.physicsBody?.applyImpulse(CGVectorMake(0, impulseFactor))
}
func moveBallLeft() -> Void {
var random = -1 * CGFloat(Float(arc4random()))
ball.physicsBody?.applyImpulse(CGVectorMake(random % impulseFactor, 0))
}
func moveBallRight() -> Void {
var random = CGFloat(Float(arc4random()))
ball.physicsBody?.applyImpulse(CGVectorMake(random % impulseFactor, 0))
}
How do I make it such that only taps on the SKSpriteNode variable "ball" will cause the ball to move?
You can set ball's name (ballNode.name = "ball") and access it like this:
touchesBegan:
let location = (touch as UITouch).locationInNode(self)
if let ball = self.nodeAtPoint(location)
if ball.name == "ball" {
//move the ball
}
}
Another way would be using subclassing SKSpriteNode (and implementing touchesBegan method) like this:
class Ball : SKSpriteNode
{
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
//do your stuff here
}
}
If you are subclassing SKSpriteNode you have to set userInteractionEnabled = true. you can do this in ball's init method or after you create Ball object.
I'm building a 2D game, the aim of the game is to jump over obstacles on the ground and flying in the air. At present the character can jump multiple times in mid air and has the ability to fly.
I'm looking to only let the character jump every second or so, is there a way to set a time delay on 'touchesBegan'. Ideally id like to be able to alter the time delay to ensure gameplay is fun yet challenging.
Below is a copy of my touchesBegan, let me know if you need more script or the below isn't quite right.
Thank you.
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
cat.physicsBody!.velocity = CGVectorMake(0, 0)
cat.physicsBody!.applyImpulse(CGVectorMake(0, 20))
}
let runningBar = SKSpriteNode(imageNamed: "ground")
var velocityY = CGFloat(0)
var onGround = true
func didMoveToView(view: SKView) {
initHero()
}
func initHero() {
hero = SKSpriteNode(imageNamed: "hero")
self.heroBaseline = self.runningBar.position.y + (self.runningBar.size.height / 2) +
(self.hero.size.height / 2)
self.hero.position = CGPointMake(
CGRectGetMinX(self.frame) + (self.hero.size.width / 3) + (self.hero.size.width / 4),
self.heroBaseline)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if self.onGround {
self.velocityY = -18.0
self.onGround = false
}
}
override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {
if self.velocityY < -9.0 {
self.velocityY = -9.0
}
}
You need to create a baseline (ground) and limit it to that like in the code above.