Hi I'm working in Sprite Kit and I'm trying to make a sprite move from one point to another. Currently, I am able to do this with SkAction.moveTo and the sprite moves in a straight line. However, I'm curious as to if it would be possible for the sprite to move in a parabola instead of a straight line as it reaches its destination. All help is appreciated.
Here is a simple way to create a parabolic UIBezierPath:
let path = UIBezierPath()
path.moveToPoint(CGPointZero)
path.addQuadCurveToPoint(CGPoint(x: 100, y: 0), controlPoint: CGPoint(x: 50, y: 200))
This looks like this when graphed in a Playground:
For your sprite to move with this path, use this code:
mySprite.runAction(SKAction.followPath(path.CGPath, duration: 1.0))
To fine-tune the parabola, change the constants in the code above to change the path.
I've been drawn quite awhile in this problem. I would like to share a bit about my experience about parabola movement in SKAction.
This is the code for Swift 3
let path = UIBezierPath()
path.move(to: CGPoint(x:0, y:0))
path.addQuadCurve(to: CGPoint(x: 100, y: 0), controlPoint: CGPoint(x: 50, y: 200))
let parabolaAction = SKAction.follow(path.cgPath, duration: 1)
Your Sprite Node must have been placed in a certain position.
The second line means that the Sprite Node will move by x:0 and y:0. It's a relative movement. The problem why I'm struggling was considering that the Point is the new absolute position. But it's not.
The third line means that the Sprite Node will move by x:100, y:0 into a new position with the help of control point. Control point is the top coordinate like what erdekhayser shows.
If you set points in path with Sprite Node position + certain value then your Sprite Node might be positioned off the scene.
Hope this helps understanding UIBezierPath for parabola movement.
Related
I created a Sprite SKNode Class which works like a StackView. In Sprite Kit objects origin is always centered therefore I would like to offset the position by a certain amount (which is calculateAccumulatedFrame().width/2) so it can be positioned comfortable. What would be the best way to do so?
First I thought I could do something like this
override var position: CGPoint {
didSet {
self.position = CGPoint(x: position.x - self.calculateAccumulatedFrame().width/2, y: position.y)
}
}
But of course this is not possible since this would end in an endless loop
What would be other options?
In Sprite Kit objects origin is always centered
That is not true. There is this useful property called anchorPoint that you can set to specify where the "origin" is.
Judging from your code, you seem to want the anchor point to be on the midpoint of the right edge of the sprite, assuming the sprite to be a rectangle. This means that you want the anchor point to be (1, 0.5):
yourSprite.anchorPoint = CGPoint(x: 1, y: 0.5)
I'm struggling to understand how to achieve the following component:
Theory:
I've managed to create 4 draggable UIView'. When one of the UIView change position I'm creating UIBezierPath from connecting each UIView center, to a box shape and displaying it using CAShapeLayer.
I can't understand how to calculate the "addQuadCurve" control point to achieve the curved lines in the illustration.
Current Code:
func updateLines() {
let path = UIBezierPath()
path.move(to: v.center)
path.addLine(to: v2.center)
path.addLine(to: v4.center)
path.addLine(to: v3.center)
path.close()
line.path = path.cgPath
line.strokeColor = UIColor.black.cgColor
line.fillColor = UIColor.red.cgColor
}
Any help or advice for the right direction will be highly appreciated.
Best regards,
Roi
It looks to me like a connected set of cubic Bezier curves where the beginning and end are the same point. If you watch the animation, it looks like as you drag different points, the point that's the beginning/end of the curve gets changed.
Watch carefully and you'll see that 3 of the 4 corners are smooth curves, and one has a "kink" in it. The kinked corner seems to be a point other than the one that's being moved. That's probably the begin/end point.
I'm trying to build a small spriteKitGame. I have been trying to use the function to move a couple of tank sprite nodes to a specific point.
Attached below is the code snippet.
let tankSpawn = CGPoint(x: self.size.width , y: 70);
tank.position = tankSpawn;
tank.zPosition = 3.0;
let targetPoint = CGPoint(x: -tank.size.width/2, y: tank.position.y);
let actionMove = SKAction.move(to: targetPoint, duration: TimeInterval(tankMoveDuration))
This is my result. They are spawning at the correct point ( 70units high ), but are going down as shown.
I want them to go in a straight line. I set the target points y as a constant. I have no idea why they are going to wards some bottom source.
I have similar code for planes that spawn above( which are working perfectly ).
let plane = SKSpriteNode(imageNamed: "SpaceShip");
let planeMoveDuration = 3.0
let planeSpawn = CGPoint(x: self.size.width , y: self.size.height/2);
plane.position = planeSpawn;
plane.zPosition = 3.0;
let actionMove = SKAction.move(to: CGPoint(x: -plane.size.width/2, y: plane.position.y), duration: TimeInterval(planeMoveDuration))
I have no idea what my mistake here is.
I have tried changing the y co ordinate of the target to tank.position.y, but it doesn't work.
Are they falling under gravity? A sprite-kit scene with physics bodies will have gravity and things will fall unless you take specific action to avoid this.
It's easily done - you're developing your game, you have basic elements on screen and movement etc is all working well, then you want to add some collision detection so you add physicsBodies and then whoosh - where'd my sprites go?
I have a spotlight, created with the code beneath, casting shadows on all of my nodes:
spotLight.type = SCNLightTypeSpot
spotLight.spotInnerAngle = 50.0
spotLight.spotOuterAngle = 150.0
spotLight.castsShadow = true
spotLight.shadowMode = SCNShadowMode.Deferred
spotlightNode.light = spotLight
spotlightNode.eulerAngles = SCNVector3(x: GLKMathDegreesToRadians(-90), y: 0, z: 0)
spotlightNode.position = levelData.coordinatesForGridPosition(column: 0, row: playerGridRow)
spotlightNode.position.y = 1.5
rootNode.addChildNode(spotlightNode)
The scene is moving along the z axis, and the camera has an infinite animation that makes it move:
let moveAction = SCNAction.moveByX(0.0, y: 0.0, z: CGFloat(-GameVariables.segmentSize / 2), duration: 2.0)
cameraContainerNode.runAction(SCNAction.repeatActionForever(moveAction))
As the camera moves though, the light doesn't, so after a while, the whole scene is dark. I want to move the light with the camera, however if I apply to the light node the same moving animation, all the shadows start to flicker. I tried to change the SCNShadowMode to Forward and the light type to Directional, but the flickering is still there. With directional, I actually loose most of my shadows. If I create a new light node later on, it will seem that I have two "suns", which of course is impossible. The final aim is simply to have an infinite light that shines parallel to the scene from the left, casting all the shadows to the right. Any ideas?
Build a node tree to hold both spotlight and camera.
Create, say, cameraRigNode as an SCNNode with no geometry. Create cameraContainerNode and spotlightNode the same way you are now. But make them children of cameraRigNode, not the scene's root node.
Apply moveAction to cameraRigNode. Both the camera and the light will now move together.
I put a circular attack oval on a blue space ship and, if any SKSpriteNode enters the SKShapeNode (attack oval) the blue space ship can fire on the SKSpriteNode. The problem is that I can't figure out how to do the detection. I have tried physical bodies but, I can't have contact without having a collision.
Here is an example. I want the purple/blue attack circle to detect A,B,C,D,E
Here is the code I think you will need. RSSprite is short for red ship sprite
blueShip.position = CGPoint(x: 800, y: 400)
attackCircle = SKShapeNode(ellipseOfSize: CGSize(width: 1000, height: 400))
attackCircle.position = CGPoint(x: blueShip.position.x, y: blueShip.position.y)
RSSprite!.position = CGPoint(x: 200, y: 700)
RSSprite!.physicsBody = SKPhysicsBody(rectangleOfSize: RSSprite!.size)
In the update method you can check for an intersection of 2 nodes like this:
if([nodeA intersectsNode:nodeB]) {
// you have a collision
}