Like many here asking questions I'm new to programing, but I'm going to do my best to describe my dilemma. Thanks for any help in advance.
I've included a picture of my goal.
The Green line is a node that rotates around the center of the screen. I have its anchor point set to 1,1 and position x,y to the center of the device. Using SKActions I've made the node rotate so many degrees causing it to move like the second hand of a clock would around its center post. All the code to this point I've got down. Here is where I've reached a mental brick wall. I want to have a sprite constantly placed at the tip of the rotating node so that the sprite will move around the center in a circular motion. The sprite is represented by the Pink circle.
This was my plan of attack, but my lack of knowledge of the swift language prevents me from executing it.
Is there a way to add a reference point to the tip of the node? If so I was thinking of doing that, then in the update function set the position of the sprite to the x,y of that reference point. I hope I've included enough information. If anyone has a better approach to this, please let me hear it. Thanks so much in advance.
I am posting an answer, even though it was answered in the comments. If Leo posts the answer, I'll delete this one.
I am assuming that your ball is a child of the line, so you'd just offset the x position of your ball the width of the line. Which as noted in comments is the radius of the circle path your ball is following.
Your secondary issue could be solved by using another SKAction to offset the zRotation of the line. For example :
let lineRotateAction = SKAction.rotateByAngle(CGFloat(360).degreesToRadians, duration: 6)
let ballRotateAction = SKAction.rotateByAngle(CGFloat(-360).degreesToRadians, duration: 6)
You can simply put create the hands as children of an empty SKNode, position both hands correctly in relation to these SKNodes and then rotate the SKNodes themselves.
Two different ways: First using a parent node (which is potentially what you want):
let body = SKSpriteNode(color: .clear, size: CGSize(width: 20, height: 150))
body.anchorPoint = CGPoint(x: 0.5, y: 0)
body.position = CGPoint(x: frame.midX, y: frame.midY)
body.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI * 2), duration: 10)))
let hand = SKSpriteNode(color: .blue, size: CGSize(width: body.size.width/2, height: body.size.height))
hand.position = CGPoint(x: 0, y: body.size.height/2)
let ball = SKSpriteNode(color: .green, size: CGSize(width: body.size.width, height: body.size.width))
ball.position = CGPoint(x: 0, y: body.size.height - ball.size.height/2)
body.addChild(hand)
body.addChild(ball)
addChild(body)
Second is using physics, which produces a similar effect only on the surface but it might give you other ideas too:
let hand = SKSpriteNode(color: .blue, size: CGSize(width: 10, height: 150))
hand.anchorPoint = CGPoint(x: 0.5, y: 1)
hand.position = CGPoint(x: frame.midX, y: frame.midY)
hand.physicsBody = SKPhysicsBody(rectangleOf: hand.size)
hand.physicsBody?.affectedByGravity = false
hand.physicsBody?.isDynamic = false
hand.run(SKAction.repeatForever(SKAction.rotate(byAngle: CGFloat(M_PI * 2), duration: 10)))
addChild(hand)
let ball = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))
ball.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ball.position = CGPoint(x: frame.midX, y: frame.midY - hand.size.height)
ball.physicsBody = SKPhysicsBody(rectangleOf: ball.size)
addChild(ball)
let joint = SKPhysicsJointPin.joint(withBodyA: hand.physicsBody!,
bodyB: ball.physicsBody!,
anchor: ball.position)
physicsWorld.add(joint)
Have fun!
Related
This question already has answers here:
How to rotate UIBezierPath around center of its own bounds?
(3 answers)
Closed 4 years ago.
I wanted to rotate my ellipse but I don't manage to do it.
I tried to make a CGAffineTransform, but my rectangle disappeared and I also tried a to do a CATransformRotate or something like this on note, but didn't managed to use it properly
let ovalPath = UIBezierPath(ovalIn: CGRect(x: 100, y: 100, width: 10, height: 15))
UIColor.gray.setFill()
ovalPath.fill()
let rotation = CGAffineTransform(rotationAngle: CGFloat(M_PI / 3.0))
ovalPath.apply(rotation)
let note = CAShapeLayer()
note.path = ovalPath.cgPath
note.fillColor = UIColor.black.cgColor
view.layer.addSublayer(note)
You're rotating the path off the screen because of the x/y offset in the cgrect (it's rotating around (0,0)). try this and rotate ccw a bit to see the rotation behavior work correctly. If you want the layer to be at coordinate 100,100 you can use another transform to move it:
let ovalPath = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 10, height: 15))
UIColor.gray.setFill()
ovalPath.fill()
let rotation = CGAffineTransform(rotationAngle: -CGFloat(M_PI / 3.0))
ovalPath.apply(rotation)
let note = CAShapeLayer()
note.path = ovalPath.cgPath
note.fillColor = UIColor.black.cgColor
view.layer.addSublayer(note)
I am running through an entry level xCode course and I am working with SKLabelNode. I have quadruple checked my code to be duplicate of this, yet my label is appearing 99% off the screen it appears? Please help.
By Default Anchor point of your main scene is set to x= 0.5 and y=0.5, So, when you add a new node, it's coordinates starts from center of screen.
Now, either you can change the anchor points of your scene as
self.anchorPoint = CGPoint(x: 0.0, y: 0.0)
let label = SKLabelNode(text: "Player Score")
label.fontColor = SKColor.white
label.fontSize = 60
label.position = CGPoint(x: self.frame.width/2, y: self.frame.height/2)
self.addChild(label)
or you can change the position of label to :-
label.position = CGPoint(x: 0, y: 0)
I'm just starting out looking into Swift 3 - never coded before so I'm completely new to it all. Been looking at a really basic Node tutorial and have the following code:
class GameScene: SKScene {
override func didMove(to view: SKView) {
// SKLabelNode
var exampleLabelNode = SKLabelNode(fontNamed: "Helvetica")
exampleLabelNode.text = "Example Label Node!"
exampleLabelNode.fontSize = 30
exampleLabelNode.fontColor = SKColor.white
exampleLabelNode.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.75)
self.addChild(exampleLabelNode)
// SKSpriteNode
var exampleSpriteNode = SKSpriteNode(imageNamed: "myImage")
exampleSpriteNode.size = CGSize(width: 180, height: 180)
exampleSpriteNode.anchorPoint = CGPoint(x: 0.5, y: 0.5)
exampleSpriteNode.position = CGPoint(x: self.frame.size.width / 2, y: self.frame.size.height * 0.25)
exampleSpriteNode.zPosition = 100
exampleSpriteNode.name = "exampleName"
self.addChild(exampleSpriteNode)
}
}
It's meant to position exampleLabelNode centre and 3/4 at the top of the screen and exampleSpriteNode 1/4 at the bottom of the screen.
However its positioning exampleSpriteNode 3/4 to the top of the screen and half off to the right with the exampleLabelNode positioned off the screen.
The tutorial is for Swift 2, so is the positioning syntax etc different for Swift 3?
This is happening because the default scene anchorPoint is (0.5, 0.5) meaning the centre of the scene. That's also the default anchorPoint for any node. That makes the point (x: 0, y: 0) at the centre of the scene.
I suggest you read more about this or ask questions to get a better understanding of it if you're having trouble.
Official Apple Docs
SKSpriteNode anchorPoint
SKScene anchorPoint
Note: The docs for the SKScene is incorrect when it says that the default value is (0, 0).
To solve your issue, you can add this line to the beginning of your didMove(to view):
self.anchorPoint = CGPoint(x: 0, y: 0)
This sets the scene anchorPoint to the bottom left of the scene, which used to be how it was (The tutorial is outdated).
Alternatively, you could redo the sprite placement now that you know how anchorPoint works. I suggest this because I find building games to be easier when building the scene from the centre outwards rather than from the bottom left corner.
I'm making a SpriteKit game on iOS using Swift (although an Objective-C answer would still help), and I have an SKSpriteNode whose parent is another SKSpriteNode. However, I only want to sub-node to be drawn when it is within the frame of the parent node. So for example, I have:
let scene = GameScene(size: CGSize(width: 10, height: 10))
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
let skView = self.view as! SKView
skView.presentScene(scene)
let superNode = SKSpriteNode(color: UIColor.blueColor(), size: CGSize(width: 1, height: 1))
scene.addChild(superNode)
let subNode = SKSpriteNode(color: UIColor.redColor(), size: CGSize(width: 0.5, height: 0.5))
superNode.addChild(subNode)
It looks as follows:
However, if I move subNode to (1.5, 1.5):
subNode.position = CGPoint(1.5, 1.5)
Then subNode is visually outside of superNode, but it is still drawn:
However, I would like it to look as follows:
As a further example, if I set subNode's position to (1.0, 1.0), it looks as follows:
But I would like it to look like this:
How do I get it to only be drawn when it is within superNode? Any help would be much appreciated. Thanks:)
Im trying to get two SKshapeNodes to be positioned on the far left and far right of the screen without any part of the nodes offscreen like this http://i.stack.imgur.com/9rhAH.png. I don't want one node to be positioned according to the other node though.
Ive been trying to use minX and maxX and use the width of the screen and SKshapeNodes and I can't figure it out.
This is what I have so far
class GameScene: SKScene {
override func didMoveToView(view: SKView) {
let firstShapeNode = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 50, height: 50))
firstShapeNode.position = CGPoint(x: 0, y: self.frame.height / 2)
firstShapeNode.fillColor = SKColor.purpleColor()
self.addChild(firstShapeNode)
let secondShapeNode = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 50, height: 50))
secondShapeNode.position = CGPoint(x: 0, y: self.frame.height / 2)
secondShapeNode.fillColor = SKColor.cyanColor()
self.addChild(secondShapeNode)
}
Any suggestions?
To align the nodes to the left and right sides of the screen, respectively, try this:
firstShapeNode.position = CGPoint(x: firstShapeNode.size.width / 2, y: self.frame.height / 2)
secondShapeNode.position = CGPoint(x: self.frame.maxX - secondShapeNode.size.width / 2, y: self.frame.height / 2)
In SpriteKit, unlike UIKit, the default origin (0,0) point on the screen is in the bottom left corner. Additionally, by default, the position of an SKNode is the center of the node, which is why they need to be offset by half of their width.