Im messing around with an xcode project and I am trying to make a red ball SKShapeNode move around when I touch it. My own source code in the touch began class is not doing the trick. What is the flaw with my code and what do I need to do in order to fix it.
import SpriteKit
class GameScene: SKScene {
//Rectangle Skeletions
var leftWallRect = CGRect(x: 0, y: 0, width: 40, height: 1000)
var ball = SKShapeNode(circleOfRadius: 25);
override func didMoveToView(view: SKView) {
// Declare the Sprites in your scene
var ball = SKShapeNode(circleOfRadius: 25);
let leftWall = SKShapeNode(rect: leftWallRect);
let rightWall = SKShapeNode(rect: leftWallRect);
let pin = SKSpriteNode(imageNamed: "pin");
// Ball Properties
ball.strokeColor = UIColor.blackColor()
ball.fillColor = UIColor.redColor()
ball.position = CGPointMake(self.frame.width / 2 , self.frame.height / 4 - 100 )
self.addChild(ball)
// Left Wall Properties
leftWall.fillColor = UIColor.purpleColor()
leftWall.strokeColor = UIColor.blackColor()
leftWall.position = CGPointMake(self.frame.size.width / 3 - 45, self.frame.size.height / 2 - 400)
self.addChild(leftWall)
//Right Wall Properties
rightWall.fillColor = UIColor.purpleColor()
rightWall.strokeColor = UIColor.blackColor()
rightWall.position = CGPointMake(self.frame.size.width / 2 + 175, self.frame.size.height / 2 - 400)
self.addChild(rightWall)
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
/* Called when a touch begins */
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
if touchLocation == ball.position{
ball.position = touchLocation
println("Touches");
}
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
}
LOL wow, this is a funny one, if touchLocation == ball.position I would be impressed if you can hit the exact pixel location of your ball. What you want is this:
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(touchLocation)
if touchedNode == ball{
...
But personally, what I would do is make a sub class of SKSpriteNode, and do your ball's touch code inside this child's touch routine
Related
So here is my code:
import SpriteKit
import GameplayKit
class GameScene: SKScene {
var ship1 = [2,1]
var ship2 = [1,2]
let jonahSpriteNode = SKSpriteNode(imageNamed: "jonah_spaceship")
let georgeSpriteNode = SKSpriteNode(imageNamed: "george_spaceship")
override func didMove(to view: SKView) {
//var jonahFrames = [SKTexture]()
jonahSpriteNode.position = CGPoint(x: 30, y: frame.midY)
jonahSpriteNode.size = CGSize(width: 100.0, height: 100.0)
addChild(jonahSpriteNode)
georgeSpriteNode.position = CGPoint(x: 628, y: frame.midY)
georgeSpriteNode.size = CGSize(width: 100.0, height: 100.0)
addChild(georgeSpriteNode)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches{
var touchLocation = touch.location(in: self)
var angle1 = atan2(jonahSpriteNode.position.y - touchLocation.y , jonahSpriteNode.position.x - touchLocation.x)
var angle = angle1 - CGFloat(Double.pi / 1)
makeCircularRange(to: jonahSpriteNode)
let rotate = SKAction.rotate(toAngle: angle, duration: 1.0)
let move = SKAction.move(to: CGPoint(x: touchLocation.x, y: touchLocation.y), duration: 2.5)
let sequence = SKAction.sequence([rotate, move])
jonahSpriteNode.run(sequence)
}
}
func makeCircularRange(to node: SKNode) {
let range = SKRange(lowerLimit: 0, upperLimit: 400)
let constraint = SKConstraint.distance(range, to: .zero)
node.constraints = [constraint]
}
}
I wanted to display the SKRange by showing upperLimit in a certain color. I tried making nodes around the limit and then coloring the nodes but it just showed a bunch of errors. If you have any ideas please answer.
Something like this:
The sprite node will be in the center and the circle will show where it can move.
You can make a circular shape using range.upperLimit as a radius an add to scene.
func drawCircularRangeBy(range: SKRange) {
let radius = range.upperLimit
let node = SKShapeNode(circleOfRadius: radius)
node.strokeColor = .white
addChild(node)
}
Take a look of this example: https://github.com/Maetschl/SpriteKitExamples/blob/master/CircularRange/CircularRange/GameScene.swift
If you really need dots instead of a line please see this answer: Drawing dashed line in Sprite Kit using SKShapeNode
I'm just starting in sprite kit and have hit a road block. I'm trying to recreate the old atari game asteroids. I'm currently trying to find out how to move the node "ship" from one side of the screen and come out the opposite side. An example of this would be pacman going from the right side of the screen and out the left side of the screen. Help is greatly appreciated.
Thanks in advance,
Jared
import SpriteKit
class GameScene: SKScene, SKPhysicsContactDelegate{
let base = SKSpriteNode(imageNamed: "Base")
let ball = SKSpriteNode(imageNamed: "Ball")
let ship = SKSpriteNode(imageNamed: "Ship")
let shoot = SKSpriteNode(imageNamed: "shootButton")
override func didMoveToView(view: SKView){
// var DynamicView=UIView(frame: CGRectMake(100, 200, 100, 100))
// DynamicView.backgroundColor=UIColor.greenColor()
// DynamicView.layer.cornerRadius=2
// DynamicView.layer.borderWidth=2
// self.view!.addSubview(DynamicView)
self.anchorPoint = CGPointMake(0.5, 0.5)
self.physicsWorld.contactDelegate = self
self.physicsWorld.gravity = CGVectorMake(0.0, 0.0)
self.addChild(base)
base.position = CGPointMake(-350, -200)
self.addChild(shoot)
shoot.position = CGPointMake(350, -200)
self.addChild(ball)
ball.position = base.position
self.addChild(ship)
ship.position = CGPointMake(20, 47)
ship.xScale = 0.7
ship.yScale = 0.7
ship.physicsBody?.dynamic = true
ship.physicsBody?.allowsRotation = true
ship.physicsBody?.affectedByGravity = true
ship.physicsBody = SKPhysicsBody(texture: SKTexture(imageNamed: "Ship"), size: ship.size)
self.physicsBody = SKPhysicsBody(edgeLoopFromRect: self.frame)
ball.alpha = 0.4
base.alpha = 0.4
}
// func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
// /* Called when a touch begins */
//
// for touch in (touches as! Set<UITouch>) {
// let location = touch.locationInNode(self)
//
//
// }
// }
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
for touch in (touches ) {
let location = touch.locationInNode(self)
let v = CGVector(dx: location.x - base.position.x, dy: location.y - base.position.y)
let angle = atan2(v.dy, v.dx)
let deg = angle * CGFloat(180 / M_PI)
// print( deg + 180)
let length:CGFloat = base.frame.size.height / 2
let xDist:CGFloat = sin(angle - 1.57079633) * length
let yDist:CGFloat = cos(angle - 1.57079633) * length
ball.position = CGPointMake(base.position.x - xDist, base.position.y + yDist)
if CGRectContainsPoint(base.frame, location) {
ball.position = location
}
else{
ball.position = CGPointMake(base.position.x - xDist, base.position.y + yDist)
}
ship.zRotation = angle - 1.57079633
ship.physicsBody?.mass = 2
var shipRotation : CGFloat = ship.zRotation
var calcRotation : Float = Float(angle - 1.57079633) + Float(M_PI_2);
let intensity : CGFloat = 2000.0 // put your value
let xVelocity = intensity * CGFloat(cosf(calcRotation))
let yVelocity = intensity * CGFloat(sinf(calcRotation))
let vector : CGVector = CGVectorMake(xVelocity, yVelocity)
//Apply force to spaceship
ship.physicsBody?.applyForce(vector)
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
let move:SKAction = SKAction.moveTo(base.position, duration: 0.2)
move.timingMode = .EaseOut
ball.runAction(move)
}
}
// overridefunc update(currentTime: CFTimeInterval) {
// /* Called before each frame is rendered */
//
//}
In func update(currentTime) check if ship.position.x < 0 or ship.position.x > scene.width. If true, set ship.position.x to the opposite side.
It looks like you're using physics to move the ship (as opposed to updating its position by a certain amount in the update() method)
So what you could do is to override the didiSimulatePhysics() method (which is called after the SpriteKit game engine has done all the physics calculations and moved all the nodes) and if your ship is off screen (which you could do by seeing if it's position is outside the screne's x & y boundaries, or by using the intersectsRect method to see if. The ship's frame no longer overlaps the screen frame) and if it is, simply wrap it to the other side of the screen.
Im trying to create a method that when I touch a sprite named StartSprite Through my touchesbegan function it will print out something in my console. But for some reason when I click on the sprite nothing happens. This is my code.
import SpriteKit
class GameScene: SKScene {
let StartSprite = SKSpriteNode(imageNamed: "startLabel")
override func didMoveToView(view: SKView) {
let borderRect = CGRect(x: 0 , y: 0 , width: 400, height: 725)
let welcomeLabel = SKLabelNode(fontNamed: "welcome");
welcomeLabel.text = "Welcome";
welcomeLabel.fontColor = UIColor.whiteColor()
welcomeLabel.fontSize = 65
welcomeLabel.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2 + 150)
self.addChild(welcomeLabel)
//StartLabel
let rectangleBorder = SKShapeNode(rect: borderRect)
rectangleBorder.position = CGPoint(x: 315, y: 25)
rectangleBorder.strokeColor = UIColor.whiteColor()
self.addChild(rectangleBorder)
self.backgroundColor = UIColor.grayColor()
StartSprite.position = CGPoint(x: self.frame.width / 2, y: self.frame.height / 2)
self.addChild(StartSprite)
println("Hello")
}
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
if touchLocation == StartSprite.position{
println("Touches")
}
}
}
Your code requires that you touch exactly the one pixel at StartSprite.position.
Try this instead:
let p = StartSprite.convertPoint(touchLocation, fromNode: self)
if StartSprite.containsPoint(p) {
print("touched StartSprite")
}
If you're going to add more buttons, you might want to do this instead:
let target = nodeAtPoint(touchLocation)
if target == StartSprite {
print("touched StartSprite"
}
// check other buttons here
i Like to create left side and right side that when i touch them , A bird will fly to the left or right !
I create a bird
var birdtexture = SKTexture(imageNamed: "flappy1.png")
bird = SKSpriteNode(texture: birdtexture)
bird.position
bird.size
bird.physicsBody = SKPhysicsBody(circleOfRadius: bird.size.width/2)
bird.physicsBody?.dynamic = true
bird.physicsBody?.allowsRotation = false
self.addChild(bird)
Then i create left node
var groundleft = SKSpriteNode()
groundleft.position = CGPoint(x: 0, y: 50)
groundleft.size = CGSize(width: 500, height: 100)
groundleft.color = UIColor(red: 7, green: 5, blue: 7, alpha: 20)
groundleft.physicsBody = SKPhysicsBody(rectangleOfSize:CGSizeMake(self.size.width, 100))
groundleft.physicsBody?.dynamic = true
groundleft.physicsBody?.affectedByGravity = false
groundleft.name = "toleft"
self.addChild(groundleft)
then i go to TouchBegan
let touch = touches.first as! UITouch
let touchLocation = touch.locationInNode(self)
let touchedNode = self.nodeAtPoint(touchLocation)
if(touchedNode.name == "toleft"){
bird.physicsBody?.velocity = CGVectorMake(0, 0)
bird.physicsBody?.applyImpulse(CGVectorMake(-10, 100))
}
why it didnt work . Is my method wrong ? Is there any another way for me to make it work ??
please help , so many thanks
In your touchesBegan method try this:
override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {
if let touch = touches.first as? UITouch {
let touchLocation = touch.locationInNode(self)
if nodeAtPoint(touchLocation) == groundleft { //your sprite node
//do something
}
}
super.touchesBegan(touches , withEvent:event)
}
Hi everyone I am trying to make a basic line drawing test with xcode 6 using swift. But my collision system isn't working at all. This is the code of my collision system:
func drawLines() {
CGPathMoveToPoint(path, nil, location.x, location.y)
CGPathAddLineToPoint(path, nil, self.frame.size.width/2, self.frame.size.height / 5)
drawLine.append(SKShapeNode())
drawLine[index] = SKShapeNode()
line.append(drawLine[index])
line[index].path = path
line[index].strokeColor = UIColor.redColor()
line[index].lineWidth = 5.0
line[index].physicsBody = SKPhysicsBody(rectangleOfSize: line[index].frame.size)
line[index].physicsBody.dynamic = false
line[index].zPosition = 1
self.addChild(line[index])
index++
}
I can't figure out the problem but I think I made a mistake in that piece of code.
Here is the rest of my code:
class GameScene: SKScene {
var line: [SKShapeNode] = []
var drawLine: [SKShapeNode] = []
var path = CGPathCreateMutable()
var touch: UITouch!
var location:CGPoint!
var index = 0
let player = SKSpriteNode(imageNamed: "player")
override func didMoveToView(view: SKView) {
player.position = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2)
player.physicsBody = SKPhysicsBody(rectangleOfSize: player.size)
player.physicsBody.dynamic = true
self.physicsWorld.gravity = CGVectorMake(0,-1)
player.zPosition = 1
self.addChild(player)
}
override func touchesBegan(touches: NSSet, withEvent event: UIEvent) {
/* Called when a touch begins */
touch = touches.anyObject() as UITouch!
location = touch.locationInNode(self)
drawLines()
}
func drawLines() {
CGPathMoveToPoint(path, nil, location.x, location.y)
CGPathAddLineToPoint(path, nil, self.frame.size.width/2, self.frame.size.height / 5)
drawLine.append(SKShapeNode())
drawLine[index] = SKShapeNode()
line.append(drawLine[index])
line[index].path = path
line[index].strokeColor = UIColor.redColor()
line[index].lineWidth = 5.0
line[index].physicsBody = SKPhysicsBody(rectangleOfSize: line[index].frame.size)
line[index].physicsBody.dynamic = false
line[index].zPosition = 1
self.addChild(line[index])
index++
}
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
}
-------------------EDIT -------------------
I now use this line of code for the physics of my line:
line[index].physicsBody = SKPhysicsBody(rectangleOfSize:
CGSizeMake(line[index].frame.width*2 ,line[index].frame.height*2))
This problem here I think is that when I draw my line at an angle the rectangle doesn't turn with it so my rectangle ends up way to big.
As far as I know, touchesBegan returns an NSSet of touches (an array of touches roughly saying), therefore you would want to loop through them or access a specific touch by its index. I would recommend looping through touches like the following code.
override func touchesBegan(touches:NSSet) {
for touch: AnyObject in touches {
var location:CGPoint = touch.locationInNode(self.scene)
performSomethingCrazy(withLocationAt: location)
}
}
Enjoy.