Change FPS of Sprite-Kit Game? - swift

Is it possible to change the FPS of a Sprite-Kit game? If it is possible, how can I implement this into my code?
For example, if a user wants to conserve battery the game can change the FPS from 60 (default value) to 30 or 20.
Thanks for helping

Set the SKView's frameInterval to the desired value.
Ref: https://developer.apple.com/library/mac/documentation/SpriteKit/Reference/SKView/index.html#//apple_ref/occ/instp/SKView/frameInterval
Setting the interval to 2 will cause half the default frame rate. (It is an integer though so it appears that the only option would be to cut the frame rate by half, third, fourth, etc.

let gameView = SKView()
if #available(iOS 10.0, *) {
gameView.preferredFramesPerSecond = 30
} else {
gameView.frameInterval = 2 //Deprecated
}

Related

How to get current frame from Animated Tile/Tilemap.animationFrameRate in Unity

I am using tilemaps and animated tiles from the 2dExtras in unity.
My tiles have 6 frames, at speed=2f, and my tilemap frame rate is 2.
New tiles placed always start on frame 1 and then immediately jump to the current frame of the other tiles already placed, the tilemap is keeping every tile at the same pace, which is working as I want.
However I would like the newly placed tiles to start at the frame the others are currently on,(instead of placing a tile that jumps from frame 1 to frame 4) I would like the new tile to start on frame 4
I've found how to pick the frame I want to start on, however I am having trouble retrieving which frame the animation is currently on, so I was wondering how exactly can I access the current frame of animation of a given tilemap ( Or a given tile, I can create a dummy tile and just read the info out of it, how can I get the current frame of an animated tile? )
The animated tilemaps feature seems to lack the feature to retrieve this information, also when I try tilemap.getsprite it always returns the first frame of the sequence(does not return the sprite currently displayed), and there doesn't seem to be any method to poll info from tilemap.animationFrameRate.
I thought another method would be to set a clock and sync it to the rate of the animation but since I can't get the exact framerate duration the clock eventually goes out of sync.
Any help would be appreciated!
I found a way to solve this question. But it's not 100% insurance.
First of all, I used SuperTile2Unity. That doesn't seem to be the point.
private void LateUpdate()
{
// I use this variable to monitor the run time of the game
this.totalTime += Time.deltaTime;
}
private void func()
{
// ...
TileBase[] currentTiles = tilemap.GetTilesBlock(new BoundsInt(new Vector3Int(0, 0, 0), new Vector3Int(x, y, 1)));
Dictionary<string, Sprite> tempTiles = new Dictionary<string, Sprite>();
//I use SuperTiled2Unity. But it doesn't matter, the point is to find animated tile
foreach (SuperTiled2Unity.SuperTile tile in currentTiles)
{
if (tile == null)
{
continue;
}
if (tile.m_AnimationSprites.Length > 1 && !tempTiles.ContainsKey(tile.name))
{
// find animated tile current frame
// You can easily find that the way SuperTile2Unity is used to process animation is to generate a sprite array based on the time of each frame set by Tiled animation and the value of AnimationFrameRate parameter.
// The length of array is always n times of AnimationFrameRate. You can debug to find this.
tempTiles.Add(tile.name, tile.m_AnimationSprites[GetProbablyFrameIndex(tile.m_AnimationSprites.Length)]);
}
}
//...
}
private int GetProbablyFrameIndex(int totalFrame)
{
//According to the total running time and the total length of tile animation and AnimationFrameRate, the approximate frame index can be deduced.
int overFrameTime = (int)(totalTime * animationFrameRate);
return overFrameTime % totalFrame;
}
I have done some tests. At least in 30 minutes, there will be no deviation in animations, but there may be a critical value. If the critical time is exceeded, there may be errors. It depends on the size of AnimationFrameRate and the accumulation mode of totalTime. After all, we don't know when and how the unity deals with animatedTile.
You could try using implementation presented in [1] which looks as follows:
MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.length * (MyAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime % 1) * MyAnimator.GetCurrentAnimatorClipInfo(0)[0].clip.frameRate;
[1] https://gamedev.stackexchange.com/questions/165289/how-to-fetch-a-frame-number-from-animation-clip

Check if the player has hit a margin

I'm making a little game using swift, a Snake Game. I've already tried to do this game using python and it worked! To run the game I used a while loop. In this way, I could always change the player position and check if he had hit the margins. Now I have to do this again, but I don't know how to tell to my program to check all the time if the snake has hit the margins or himself.
I should do something like that
if player.position.x <= 0 || player.position.x >= self.size.width || player.position.y <= 0 || player.position >= self.size.height{
death()
}
So, if the player position on x or y axis is major than the screen size or minor than 0, call the function "death()".
If I had to do this with python, I'd have just put all this code inside the "main while loop". But with swift there's not a big while I can use... any suggestions?
Use SpriteKit. You can select this when creating a new project, choose Game, and then select SpriteKit. It's Apple's framework to make games. It has what you will need, and is also faster - don't make games in UIKit.
Within SpriteKit, you have the update() method, as part of SKScene. Do NOT use a while loop. These are highly unreliable, and the speed of the snake will vary between devices.
Here is a small piece of code to help you get started on the SKScene:
import SpriteKit
class Scene: SKScene {
let timeDifference: TimeInterval = 0.5 // The snake will move 2 times per second (1 / timeDifference)
var lastTime: TimeInterval = 0
let snakeNode = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))
override func update(_ currentTime: TimeInterval) {
if currentTime > lastTime + timeDifference {
lastTime = currentTime
// Move snake node (use an SKSpriteNode or SKShapeNode)
}
}
}
After doing all this, you can finally check if the snake is over some margins or whatever within this update() loop. Try to reduce the code within the update() loop as much as possible, as it gets run usually at 60 times per second.
If I understood you correctly: You are looking for a loop in Swift that does all the calculation and drawing for your game. Here you have some tutorials about loops in Swift. In fact there are while loops that you could use in order to answer your question. I hope I could help.

SKEmitterNode: altering birth rate on update not adding more particles

I have an SKEmitterNode on my scene, when I increase the particles on update, the amount of particles being shown are not increasing. I am not sure what step I am missing.
The code is really simple:
Create any kind of default particle from Xcode.
Set birthrate to 1, max to 0
Everything else doesn't really matter.
On GameScene update:
func update(currentTime: NSTimeInterval) {
//whatever it takes to get the particle from the scene
let particles = childNodeWithName("particles") as? SKEmitter
particles!.particleBirthRate = particles!.particleBirthRate + 1;
}
Note: When doing a print, the birth rate does increase, so I know it is not using a copy

Use an huge image as a sprite

I'd like to use an huge image as a sprite in my game made with corona SDK. The image dimensions are 4172x320, for a total of 28 frames.
The fact is that when I load the scene that contains this image, the physics engine turns off. I read that the dimensions limits for a sprite is set to 2048x2048 and in fact it works as it should, but I lost the smoothness that 28 frames give to the sprite.
The code I've used to declare the spritesheet is:
local sheet2 = graphics.newImageSheet( "immagini/profDonnaCOMP.png", { width=149, height=320, numFrames=28 } )
local instance2 = display.newSprite( sheet2, { name="profDonna", start=1, count=28, time=800 } )
instance2.x = _W/2
instance2.y = _H/2+150
instance2.myName = "instance2"
instance2:play()
physics.addBody( instance2, "dynamic", { friction=0.5, bounce=0 } )
What can I do to fix this issue?
Hi try making other sprite which will be 7x4 instead of 28x1 and you will get 1043x960 image which is good to go.

Discursive UIAlertView animation while continuous animation?

I'm trying to write a little app, where on the main screen, I animate a flying "bubble". This animation has to be continuous. (I reuse the bubbles, which fly off the screen) I heard that animations have to run on the main thread, as does every operation which changes the UI. Is this true? When I try to show a UIAlertView on this screen, it's animation becomes very discursive because of the continuous bubble animation. (this is a custom alertview with an indicator) The device is an iPhone 4, so I don't think it should be a problem to show a normal UIAlertView.
And I would like to ask if I use the correct method for the bubble animation. So first of all, I use an NSTimer, which invokes the startAnimation method in every 0.01 seconds (I start it in the controller's viewDidAppear: method). In the startAnimation method, at first I generate bubbles with random x and y coordinates (to see bubbles on the screen right after the viewdidappear), and I generate bubbles on the bottom with random x and y = 460 coordinates. In the startAnimation method, I run a counter (called frames), and when the value of this counter equals 35, I call the bubble generate method again.
The problem:
I store the generated bubbles in an array, and the 'gone' bubbles (which are off the screen) in another array. First I try to reuse the bubbles in the gonebubbles array, then if the array is run out, I generate new bubbles. While this operation is processed, the continuous animation stops, then continues. The break is about one second, but this is very disturbing.
Can anyone help in this problem? Thanks in advice, madik
- (void)viewDidAppear {
.
timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(startAnimation) userInfo:nil repeats:YES];
.
}
- (void)startAnimation {
self.current = [NSDate timeIntervalSinceReferenceDate];
double diff = (self.start - self.current);
if ( diff < 0 ) {
diff = (-1) * diff;
}
self.start = self.current;
frames++;
if ( shouldMoveBubbles ) {
[mug moveBubbles:diff];
}
if ( frames == 35 ) {
DebugLog(#"################################################################");
DebugLog(#"####################### FRAME = 35 ###########################");
DebugLog(#"################################################################");
[mug createNewBubbleOnTheBottomOfView:self.view];
frames = 0;
}
}
In the Mug class:
- (void)moveBubbles:(double)millisElapsed {
for (Bubble *bubble in bubbles) {
int bubbleSpeed = bubble.speed;
float deltaX = (float)(bubbleSpeed * -degrees_sinus * millisElapsed * 100);
float deltaY = (float)(bubbleSpeed * -degrees_cosinus * millisElapsed);
DebugLog(#"movebubbles x: %f, y:%f, speed: %d, sin:%f, cos:%f", deltaX, deltaY, bubbleSpeed, degrees_sinus, degrees_cosinus);
[bubble moveBubbleX:deltaX Y:deltaY];
}
}
And in the Bubble class:
- (void)moveBubbleX:(float)deltaX Y:(float)deltaY {
self.bubbleImage.center = CGPointMake(self.bubbleImage.center.x + deltaX, self.bubbleImage.center.y + deltaY);
}
This sounds like a memory problem. Slow UIAlertView animation is a sure sign of this. It sounds like the way you are generating bubbles is causing the problem. You mentioned the you keep two arrays of bubbles. You never say if you limit the number of bubbles that can be in either array at once. You also don't mention when you clean up these bubbles. It sounds like a memory "black hole". I'd recommend setting a maximum number of bubbles that you can show on screen at once.
Also, you mention a custom alert view. If you're modifying the UIAlertView, you're going to run into problems since that's not officially supported. Additionally, I've seen UIAlertView animation become slow when memory is tight. If you solve the memory issues with your bubbles, you'll probably solve this one too.
Finally, a word of advice. Making an animated game in UIKit is probably not a good idea. NSTimers are not as accurate as many people would like to think. UIImages are relatively expensive to load. Touching moving buttons is known to be unreliable at worst, hackish at best. I suggest looking into a game framework, such as Cocos2d-iphone.
Good luck!