I want to slow down the animations that are generated by my UIDynamicAnimator so that I can fine-tune my UIDynamicBehaviors.
In the ios simulator, there is a menu option under the Debug menu labeled "Toggle slow animations in frontmost app".
However, this option seems to have no effect on the animations produced by UIDynamicAnimator. Is there some other way to achieve my goal?
You could change the forces you specify in the animation to result in slower movement. For example, you could change the gravity magnitude to slow down the acceleration:
self.animator = UIDynamicAnimator(referenceView: self.view)
var gravity = UIGravityBehavior(items: [animatedView])
gravity.magnitude = 0.5
If you have collisions going on, you might also increase the friction and/or elasticity to slow things down, though in some cases this could affect trajectories:
let bounceProperties = UIDynamicItemBehavior(items: [animatedView])
bounceProperties.elasticity = 0.5
bounceProperties.friction = 0.2
var collision = UICollisionBehavior(items: [animatedView])
var boundaryId: NSMutableString = NSMutableString(string: "bottomBoundary")
let boundaryPath = UIBezierPath(rect: boundaryFrame)
collision.addBoundaryWithIdentifier(boundaryId, forPath: boundaryPath)
// Start animating
animator.addBehavior(gravity)
animator.addBehavior(collision)
animator.addBehavior(bounceProperties)
Related
I have a square = SKSpriteNode() that turns that rotates 360° when you touch it. I want to stop the spinning when you touch it again.
Now I would make square rotate through the SKAction.rotate but how can I stop the spinning realisticly meaning that I want the sprite to spin slower and slower until it stands still.
Did you try and ease out curve for the timingMode? If you don't like this effect you can provide your own custom timingFunction. There are several websites where you can explore animation curves online. I like this one.
You may want to consider using a physicsbody and applying an angular force.
let square = SKSpriteNode(color:.white,size:CGSize(10,10))
if let physicsBody = SKPhysicsBody(rectangleOf:square.frame.size)
{
physicsBody.isDynamic = true
physicsBody.allowsRotation = true
physicsBody.affectedByGravity = false
physicsBody.angularDamping = 0.1 //Adjust this to speed up or slow down the resistance of the spin
square.physicsBody = physicsBody
}
...
When you need to spin:
square.physicsBody!.angularImpulse(1) //Adjust this to change the amount of force applied to the spin
The goal is to animate particles coming from a SKEmitterNode, but the following code doesn't work. The particles don't change texture. They only show the first texture -- or more specifically the original image used in the Xcode Particle Editor -- during the lifetime.
The particle lifetime is longer than the frame duration so this isn't the issue.
// Create animation textures
let animationAtlas = SKTextureAtlas(named: atlasFilename)
var animationFrames = [SKTexture]()
// Set number of animation frames
let numImages = animationAtlas.textureNames.count
// Load texture array
for i in 0..<numImages {
let textureName = "\(texturePrefix)\(i)"
animationFrames.append(animationAtlas.textureNamed(textureName))
}
// Create emitter node w/ animation on each particle
let emitterNode = SKEmitterNode(fileNamed: EmitterFilename)!
let animation = SKAction.animate(with: animationFrames, timePerFrame: 0.05)
emitterNode.particleAction = animation
// Define fade out sequence
let fadeOut = SKAction.fadeOut(withDuration: sparkleFadeOutDur)
let remove = SKAction.removeFromParent()
let sequence = SKAction.sequence([fadeOut, remove])
// Add emitter node to scene
addChild(emitterNode)
emitterNode.run(sequence)
While your code looks flawless and this may potentially be a bug of the particle engine, it's worth assuming that your animation runs out of frames before the particles become large or visible enough so that you see the animation perform. If that's the case, after the animation is finished the texture may revert back to the original texture that you're seeing.
To check if that's the issue, you may want to wrap your animate action into a repeatForever action:
repeatAction = SKAction.repeatForever(animation)
and then change the particleAction assignment as follows:
emitterNode.particleAction = repeatAction
It's worth noting that Apple's documentation seems contradictory. At this page (https://developer.apple.com/reference/spritekit/skaction/1417828-animate) we see: "This action can only be executed by an SKSpriteNode object."
Particles are clearly not accessible sprite nodes as this page (https://developer.apple.com/reference/spritekit/skemitternode) states, but at the same time they should behave like sprites:
"For the purpose of using actions on particles, you can treat the particle as if it were a sprite. This means you can perform other interesting tricks, such as animating the particle’s textures."
Hi I am making a endless scrolling game where the character basically avoids obstacles as they come and he can jump over them. I got everything to work pretty well but I see that the character texture will bounce slightly after hitting the ground. I want the sprite to stop immediately after touching down. I tried setting the .restitution property to 0 but i still see it bouncing. Here is the setup code for my stickman character and the edge physics category in question
stickman.physicsBody?.dynamic = true
stickman.physicsBody?.allowsRotation = false
stickman.physicsBody?.usesPreciseCollisionDetection = true
stickman.physicsBody?.categoryBitMask = PhysicsCategory.Stickman
stickman.physicsBody?.collisionBitMask = PhysicsCategory.Edge
stickman.physicsBody?.contactTestBitMask = PhysicsCategory.Obstacle | PhysicsCategory.Edge
stickman.physicsBody?.restitution = 0
self.physicsWorld.gravity = CGVector(dx: 0, dy: -9.8)
physicsBody = SKPhysicsBody(edgeLoopFromRect: playableRect)
physicsWorld.contactDelegate = self
physicsBody?.categoryBitMask = PhysicsCategory.Edge
Where playable rect is just the screen boundary for universal deployment purposes.
Has anyone run into this problem. I couldn't quite find the same issue in other posts.
Set the restitution of the physics body your sprite is running into to 0 as well. Both physics bodies in a physics collision need to have a restitution of 0 to result in no bounciness.
I'm currently working on a game using Spritekit. The game has objects which spawn at the top of the screen and fall towards the player character, and the game ends when the player character collides with any of the objects. I am trying to find a way to gradually speed up gameplay over time to make the game more difficult (i.e. objects fall at normal speed when the game begins, after 5 seconds speed up 50%, after 5 more seconds speed up another 50%, ad infinitum.)
Would I need to use NSTimer to make a countdown to increase the gravity applied to the falling objects? Sorry if this is a basic thing, I'm kind of new to programming.
Thanks, Jake
EDIT:
My spawn method for enemies-
let spawn = SKAction.runBlock({() in self.spawnEnemy()})
let delay = SKAction.waitForDuration(NSTimeInterval(2.0))
let spawnThenDelay = SKAction.sequence([spawn, delay])
let spawnThenDelayForever = SKAction.repeatActionForever(spawnThenDelay)
self.runAction(spawnThenDelayForever)
And my method for making the enemies fall-
func spawnEnemy() {
let enemy = SKNode()
let x = arc4random()
fallSprite.physicsBody = SKPhysicsBody(rectangleOfSize: fallSprite.size)
fallSprite.physicsBody.dynamic = true
self.physicsWorld.gravity = CGVectorMake(0.0, -0.50)
enemy.addChild(fallSprite)
}
In spawnEnemy(), you set self.physicsWorld.gravity. Move this line to your update: method.
If you are not keeping track of the game's duration right now, you will want to implement that. You can use the parameter of the update: method to accomplish this.
You can then use the game duration to change the gravity.
For example,
override func update(currentTime: CFTimeInterval) {
if gameState == Playing{
//update "duration" using "currentTime"
self.physicsWorld.physicsBody = CGVectorMake(0.0, -0.50 * (duration / 10.0))
}
}
10.0 can be changed depending on how fast you want the gravity to increase. A higher number makes it change less drastically, and a smaller number makes the gravity increase quite rapidly.
Hopefully this answers your question.
I'm trying to figure out how to optimize my game. I have a lot of turrets etc shooting out physics bodies. The game is playable but can dip into 50 or 45 fps. I've figured out that it is related to adding objects to my scene on the fly.
for example. when my turret is shooting it runs this code
func shootBlaster(){
let blaster = Projectile(color: SKColor.cyanColor(), size: CGSize(width: convertNum(3), height: convertNum(3)))
blaster.name = "blaster"
blaster.physicsBody = SKPhysicsBody(rectangleOfSize: blaster.size)
blaster.physicsBody!.categoryBitMask = CategoryEnemyProjectile
blaster.physicsBody!.contactTestBitMask = CategoryShip | CategoryShipShield
blaster.physicsBody!.collisionBitMask = 0
let fireAction = SKAction.runBlock({
let angle = self.turret.base.zRotation + self.zRotation
let velocity = CGPoint(angle: angle) * convertNum(420)
let vector = CGVectorMake(velocity.x, velocity.y)
let blas = blaster.copy() as Projectile
blas.wpnDmg = 10
blas.position = self.gameScene.gameLayer.convertPoint(self.turret.barrelPos, fromNode: self.turret.base)
self.gameScene.gameLayer.addChild(blas)
blas.physicsBody!.velocity = vector
blas.zRotation = blas.physicsBody!.velocity.angle
blas.runAction(SKAction.removeFromParentAfterDelay(1))
})
let recoilAction = SKAction.moveByX(-5, y: 0, duration: 0.08)
let reverseRecoil = recoilAction.reversedAction()
self.turret.barrel.runAction(SKAction.repeatAction(
SKAction.sequence([
recoilAction,
fireAction,
reverseRecoil
])
,count: self.blasterNum))
}
you can see that I'm adding a "blaster" inside of each of the fireAction blocks. I've noticed games with better performance are rarely adding children at runtime. It seems best to have everything pre-loaded. It makes sense that loading resources during runtime would put a strain on things, but what is the alternative? Do I need to add everything to the scene ahead of time and somehow hide and show it?
With any kind of shooting game where you have numerous projectiles you want to utilize "pooling". Create a pool of projectiles and reuse them as opposed to creating new ones when you need them.