Is there a way to change the velocity/speed of a skaction and also to reset the skaction?
let wait = SKAction.waitForDuration(5.0)
let moveRight = SKAction.moveByX(300, y:0, duration: 1.0)
let sequence = SKAction.sequence([wait, moveRight])
let endlessAction = SKAction.repeatActionForever(sequence)
node.runAction(endlessAction)
This code works but the things i would like to change is how fast the SKSpriteNode moves to the right as at the moment it it quite slow and also to make the SKSpriteNode return to its orignal position rather than keep on moving to right forever?
Thank you
Since velocity = distance / time, decreasing the duration will increase the speed the the sprite will move across the screen.
Regarding your second point, by considering how SKAction.moveByX(300, y:0, duration: 1.0) moves the node to the right; SKAction.moveByX(-300, y:0, duration: 1.0) must therefore move the node to the left, back to its original position.
Hope that helps.
Related
I am attempting to generate a random X position for a simple object, in order to have it bounce back and forth inside the scene in a Swift SpriteKit game. The repeatForever action should generate a random value and then move the object (a circle) multiple times to different locations, left and right. However, it acts only one time. It is as if the random function, which works correctly, is called only one time, and the action then simply continues to move the object to the same position forever.
let circle = SKSpriteNode(imageNamed: "circle")
circle.run(SKAction.repeatForever(SKAction.move(to:
CGPoint(x: random(min: minCircleX, max: maxCircleX),
y: scene.size.height*0.5),
duration: 0.5)))
The circle moves only one time, to one position, and never seems to be moved after that. I suspect it is simply moving to the same position over and over. Thanks for any suggestions!
OK, after multiple efforts, the following works:
let customAction = SKAction.customAction(withDuration: 1000)
{
circle, _ in
let newXLocation: CGPoint = CGPoint(x: random(min: minCircleX, max: maxCircleX),
y: scene.size.height*0.5)
circle.run(SKAction.move(to: newXLocation, duration: 0.5))
}
circle.run(customAction)
Dai was correct in suggesting an anonymous function. The SKAction method customAction allows for that. And then running the actual action inside the function insured that the movement was random every time. Thanks so much!
Instead of repeat forever, use the completionblock to establish a new moveTo:
func newLocation(){
let newXLocation: CGPoint = CGPoint(x: random(min: minCircleX, max: maxCircleX),
y: scene.size.height*0.5)
circle.run(SKAction.move(to: newXLocation, duration: 0.5){
[weak self] in self?.newLocation()
}
}
What this does is upon finishing the moveTo, it will add a new moveTo and the next random location. The only "flaw" is it will start the next move during the same frame as the current move since this is being done in the action phase of the update. If you do not want this effect, then you need to store it in a block to be done during didFinishUpdate
var finishedUpdates = [()->()]()
func newLocation(){
let newXLocation: CGPoint = CGPoint(x: random(min: minCircleX, max: maxCircleX),
y: scene.size.height*0.5)
circle.run(SKAction.move(to: newXLocation, duration: 0.5){
[weak self] in
self?.finishedUpdates.append({weak self] in self?.newLocation()})
}
}
func didFinishUpdate()
{
finishedUpdates.forEach{$0()}
finishedUpdates = [()->()]() //Be sure to clear the array
}
My apologies in advance, this is written from memory alone, and may not be 100% syntactically correct
I am creating a game and I need a set of poles to move from the right side of the screen to the left. once it gets to the left, I need to reset the poles to the beginning and go again in a continuous loop. Create poles simply sets the x position of both poles to the original starting position. The poles move just fine the problem is the looping aspect. I am not sure why the code below will not work. I am very new to swift and admit I am not too sure what I am doing.
movePole()
let create = SKAction.run {
() in
self.createPoles()
self.movePole()
}
let delay = SKAction.wait(forDuration: 10)
let spawn = SKAction.sequence([create,delay])
self.run(SKAction.repeatForever(spawn))
Here's what you need to do:
Tell the poles to move a specific distance for a duration.
Tell the poles to move back to the start point.
Repeat.
As demonstrated here:
let AnimationTime = 5
let PoleTravelDistance = view.frame.width
let MovePolesToLeft = SKAction.move(by: CGVector(dx: PoleTravelDistance, dy: 0), duration: AnimationTime)
let ReturnPolesToRight = SKAction.move(to: CGPoint(x: (POLESNODE.frame.width)/2, y: (POLESNODE.position.y)), duration: 0)
let PoleAnimationSequence = SKAction.sequence([MovePolesToLeft, ReturnPolesToRight])
POLESNODE.run(SKAction.repeatForever(PoleAnimationSequence))
Hope that helps.
i have an SKSpriteNode named MainTank however when i try to move the tank, it goes left instead of what i did, here's my code
let moveRight = SKAction.moveBy(x: MainTank.position.x + 4, y:0, duration:0.1)
MainTank.run(moveRight)
thanks
The moveBy SKAction moves the sprite by the specified amount, so adding your sprite's current position does not make sense. Not sure why it is moving left but perhaps your sprite is already at a negative position?
To move by a distance of 4 use:
let moveRight = SKAction.moveBy(x:4, y:0, duration:0.1)
Or alternatively use the moveTo SKAction.
I have a SKAction that changes the y position of a sprite. The sprite is affected by gravity towards the right, and when i set the x position in the SKAction to the sprite's position the sprite movement is slowing down while the Action is running.
How can i change this so that the x movement is not effected by the action running?
let moveDown = SKAction.moveTo(CGPoint(x: player.position.x, y: 0), duration: 0.3)
player.runAction(moveDown)
You could try using linearDamping. I'm not sure this is exactly what you're looking for, but it's a property that reduces the body’s linear velocity.
player.physicsBody!.linearDamping = 0.0
Let me know if this works for you or if this wasn't what you were looking for!
Solved it using this code:
let moveDown = SKAction.moveToY(0, duration: 0.3)
player.runAction(moveDown)
I have a sprite that represents a cannon ball, and I shoot it in this method:
func shoot() {
let ball = Ball(radius: 8.0)
ball.position = CGPointMake(size.width / 2.0, 72.0)
self.addChild(ball)
// Explosion is just a simple particle system
let explosion = Explosion()
explosion.position = CGPointMake(size.width / 2.0, 64.0)
self.addChild(explosion)
let force = CGVectorMake(0.0, 20000.0)
ball.physicsBody!.applyForce(force)
}
Ball is a body with mass 1.0, created this way:
init(radius: CGFloat) {
super.init()
let path = UIBezierPath(arcCenter: CGPointZero, radius: radius, startAngle: 0.0, endAngle: 2.0 * PI, clockwise: false)
self.path = path.CGPath
self.strokeColor = SKColor.blackColor()
self.fillColor = SKColor.blackColor()
self.name = "Ball \(self)"
let body = SKPhysicsBody(circleOfRadius: radius)
body.dynamic = true
body.categoryBitMask = BallCategory
body.contactTestBitMask = EnemyCategory
body.collisionBitMask = EnemyCategory
body.mass = 1.0
body.affectedByGravity = false
physicsBody = body
}
The problem is that the first time (and only the first time) that I shoot the ball it's super-fast. All the other times they have a different, lower speed, why?
It looks like you are using applyForce in the wrong way. From the docs :
A force is applied for a length of time based on the amount of
simulation time that passes between when you apply the force and when
the next frame of the simulation is processed. So, to apply a
continuous force to an body, you need to make the appropriate method
calls each time a new frame is processed. Forces are usually used for
continuous effects
Means that you have to call applyForce: inside update: method. And from your code, it can be seen that you are not doing that (shoot() method is probably called inside touchesBegan).
Also from the docs related to applyForce method:
The acceleration is applied for a single simulation step (one frame).
About super-fast ball issue... I have a theory, but can't say for sure whats going on, especially because you are not using applyForce like its meant, which I think is the main problem.
So, here is the theory:
A time difference between each frame can vary, especially when you are starting an app and things are loading for the first time, and because force is multiplied by that time difference you are getting weird results.
On the other hand, applyImpulse: is perfect for your situation. Shooting a ball is an instantaneous action, and applyImpulse is not dependant on the simulation time like applyForce (see quote from docs I've posted).
Solution:
Use applyImpulse to shoot a ball. This is sanctioned way. If you want to move a ball with applyForce, do that through update method in each frame.
Also consider resource preloading (preloading sounds, emitters, textures) before starting an actual gameplay which will save you from fps drops when game starts.
Hope this helps!