Страницы

Поиск по вопросам

Показаны сообщения с ярлыком spritekit. Показать все сообщения
Показаны сообщения с ярлыком spritekit. Показать все сообщения

пятница, 5 июля 2019 г.

Как генерировать объекты за экраном с заданным промежутком

Приветствую всех! Делаю игру на spritekit с бесконечным уровнем (like Doodle jump)и возникла проблема: Не могу понять как генерировать платформы за экраном так, чтобы новые генерировались только после того, как предыдущая платформа уехала на определенное расстояние? Вот пример кода для генирации платформ - (void)addPlatforms { int random = arc4random() % (int)(self.frame.size.width-80)+100;
// right end platform SKSpriteNode *rightEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"leftPlatform"]; rightEndPlatform.size = CGSizeMake(16, 16); rightEndPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(rightEndPlatform.size.width, rightEndPlatform.size.height - 5)]; rightEndPlatform.position = CGPointMake(random, 0);
// left end platform SKSpriteNode *leftEndPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"rightPlatform"]; leftEndPlatform.size = CGSizeMake(16, 16); leftEndPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:CGSizeMake(leftEndPlatform.size.width, leftEndPlatform.size.height - 5)]; leftEndPlatform.position = CGPointMake(rightEndPlatform.position.x - PLATFORM_RANGE, rightEndPlatform.position.y);
// left platform SKSpriteNode *leftPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"]; leftPlatform.size = CGSizeMake(leftEndPlatform.position.x, 16); leftPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:leftPlatform.frame.size]; leftPlatform.position = CGPointMake(leftEndPlatform.position.x - leftPlatform.size.width/2, leftEndPlatform.position.y);
// right platform SKSpriteNode *rightPlatform = [SKSpriteNode spriteNodeWithImageNamed:@"centerPlatform"]; rightPlatform.size = CGSizeMake(self.frame.size.width+rightEndPlatform.position.x, 16); rightPlatform.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:rightPlatform.frame.size]; rightPlatform.position = CGPointMake(rightEndPlatform.position.x + rightPlatform.size.width/2, rightEndPlatform.position.y);
// add to the scene [self addChild:rightEndPlatform]; [self addChild:leftEndPlatform]; [self addChild:leftPlatform]; [self addChild:rightPlatform];
// add platforms to array [platformArray addObject:rightEndPlatform]; [platformArray addObject:leftEndPlatform]; [platformArray addObject:leftPlatform]; [platformArray addObject:rightPlatform];
for (int i = 0; i < [platformArray count]; i++) { SKSpriteNode *sprite = [platformArray objectAtIndex:i]; sprite.physicsBody.usesPreciseCollisionDetection = YES; sprite.physicsBody.dynamic = NO; sprite.name = [NSString stringWithFormat:@"beforePlayer"]; } } Генерирую платформу, потом напротив через промежуток другую платформу и достраиваю от краев экрана до этих платформ линии, получая стенку с проходом. Далее двигаю созданную конструкцию -(void)update:(CFTimeInterval)currentTime { for (int i = 0; i < [platformArray count]; i++) { SKSpriteNode *platform = [platformArray objectAtIndex:i]; platform.position = CGPointMake(platform.position.x, platform.position.y + PLATFORM_SPEED); if (platform.position.y > self.frame.size.height+100) { [platform removeFromParent]; } } } а генерация платформ происходит по времени timer = [NSTimer scheduledTimerWithTimeInterval:TIME_INTERVAL target:self selector:@selector(addPlatforms) userInfo:nil repeats:YES]; Вот и вопрос, вообще правильно ли я делаю или есть лучше вариант, как генерировать платформы не по времени а по расстоянию (первая сгенерированная платформа уехала на 100 единиц , тогда генерируем вторую, вторая уехала на 100 единиц- генерируем третью и т.д) Спасибо за внимание!


Ответ

Сразу прошу прощения, не стал вчитываться в код, (как известно, разбирать чужой код это, как лезть кому-то в душу) ). Наиболее изящный, по моему скромному мнению, выход из этой ситуации таков: 1) Остановите движение платформ, временно закомментировав соответствующую часть кода в update 2) На неподвижном экране создайте максимально возможное число платформ (на нужном Вам расстоянии друг от друга). Это легко сделать, с помощью цикла for. 3) Сдвиньте точку генерации первой из платформ на нужное расстояние за экраном. 4) Далее, в методе update начинайте двигать платформы (кстати, доступ к платформе можно получить, присвоив ей имя (если не знаете как, я напишу)) и, при этом, как только платформа пройдет нужное расстояние (то, что между каждой из платформ) за экран, Вам необходимо переместить ее в начальную точку (в ту, в которой происходила генерация первой платформы). При выполнении данного алгоритма у Вас получится непрерывный "поток" платформ, причем без наложений и дополнительной генирации (то макимальное число платформ вы просто перемещаете "по кругу") Надеюсь, у меня получилось донести до Вас мысль об общем построении таких конструкций. Если нужно что-то описать подробней, пишите, не стесняйтесь.

четверг, 11 октября 2018 г.

Как правильно воспроизводить звуки на iOS

Использую SpriteKit и все хорошо, если выключить звуки то показывает практически стабильные 60fps. Но стоит включить звуки, как начинаются неприятные просадки на 2-3-4-5 кадров во время воспроизведения звуков, которые особо ничего не портят, но при этом создают неприятные микрофризы, чувствуется что не хватает плавности.
Собственно воспрос: как выводить звуки на iOS/SpriteKit без потери fps?
Изначально я использовал для воспроизведения SKAudioNode без dispatch, и просадки были значительными, потом переделал под следующий вид:
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
SKAudioNode *newAudio = [[SKAudioNode alloc] initWithFileNamed:nameSound]; [newAudio runAction:[SKAction changeVolumeTo:1.0 duration:0]]; newAudio.autoplayLooped = false;
dispatch_async(dispatch_get_main_queue(), ^{ [scene addChild:newAudio]; [newAudio runAction:[SKAction play]]; }); });
После этого изменения стало намного лучше, но все равно, как выше написал, остались неприятные просадки от которых хотелось бы избавиться. Если вообще убрать воспроизведение звуков, то стабильные 60fps.
Пробовал так же воспроизводить звуки через AVAudioPlayer, но получалось хуже чем с SKAudioNode, просадки были еще больше.


Ответ

Я юзаю AVAudioPlayer
Каких-то проседаний фпс именно из-за звука пока не замечал. Раньше юзал SKAction.playSoundFile... и вот там не фпс проседал, а игра фризилась при первом воспроизведении звука из-за того что я создавал экш при каждом создании ноды. Решается простым вынесением экшна в проперти и последующем его применении к объекту.
Через SKAction'ы
Property:
let soundAction: SKAction = SKAction.playSoundFileNamed("nameOfFile.wav", waitForCompletion: false)
В методе, в котором нужно воспроизвести звук:
run(soundAction)
Через AVAudioPlayer:
var musicPlayer: AVAudioPlayer?
let url = Bundle.main.url(forResource: filename, withExtension: nil)
musicPlayer = AVAudioPlayer(contentsOf: url!)
if let player = musicPlayer { player.numberOfLoops = -1 player.prepareToPlay() player.play() }