Путаница с позиционированием дочернего SkShapeNode

Я написал этот код для игры поверх сцены, которая у меня есть для игры:

#import "GameOverScene.h"
#import "SharedInfo.h"
@implementation GameOverScene

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */

    [self setupView];

}

-(void)showGameEndingWithGameInformation:(NSDictionary *)gameEndingInformation{

}
-(void)setupView{
    SKLabelNode *GOTitle = [SKLabelNode labelNodeWithFontNamed:@"Generica Bold"];
    GOTitle.fontSize = 40.f;
    NSString* text = [NSString stringWithFormat:@"GAME OVER"];
    [GOTitle setText:text];
    GOTitle.position = CGPointMake(CGRectGetMidX(self.frame), self.frame.size.height- GOTitle.frame.size.height*1.5);
    [GOTitle setFontColor:[[SharedInfo sharedManager]colorFromHexString:@"#2EB187"]];
    [self addChild: GOTitle];


    SKLabelNode *replayButton = [SKLabelNode labelNodeWithFontNamed:@"Quicksand-Bold"];
    replayButton.fontSize = 25.f;
    NSString* replayText = [NSString stringWithFormat:@"Play Again"];
    [replayButton setText:replayText];
    replayButton.name = kGOSceneReplayButton;
    replayButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)- self.frame.size.height/5);
    [replayButton setFontColor:[SKColor whiteColor]];
    SKShapeNode *bgNode = [SKShapeNode shapeNodeWithRectOfSize:replayButton.frame.size];
    [bgNode setFillColor:[UIColor redColor]];

    [replayButton addChild:bgNode];
    [self addChild:replayButton];

    NSLog(@"replay dimensions: %@",NSStringFromCGRect(replayButton.frame));
    SKLabelNode *returnButton = [SKLabelNode labelNodeWithFontNamed:@"Quicksand-Bold"];
    returnButton.fontSize = 25.f;

    NSString* returnText = [NSString stringWithFormat:@"Return To Main Menu"];
    [returnButton setText:returnText];
    returnButton.name = kGOSceneReturnToMainButton;
    returnButton.position = CGPointMake(CGRectGetMidX(self.frame), replayButton.position.y -self.frame.size.height/7  );
    [returnButton setFontColor:[SKColor whiteColor]];

    [self addChild:returnButton];

}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{

    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode *sprite = [self nodeAtPoint:location];

    NSLog(@"sprite name: %@",sprite.name);

    if ([sprite.name isEqualToString:kGOSceneReturnToMainButton]||[sprite.name isEqualToString:kGOSceneReturnToMainButton]) {
        //return to main menu or retry

        [self.gameEndingSceneDelegate goToScene:sprite.name withOptions:nil]; //Sort out the options later on. 

    }

}
@end

Однако, когда я запускаю его, я получаю следующее:

введите здесь описание изображения

Есть два вопроса, которые меня действительно смущают. Во-первых, почему у меня в сцене 8 узлов, а на самом деле должно быть 4? Я думаю, что что-то удваивает узлы, но это только предположение.

Более запутанной проблемой является красное позиционирование SKShapeNode. Я читал, что масштабирование родительского узла может вызвать проблемы с дочерним SKShapeNode, но я ничего не масштабирую. Кроме того, почему он помещает мой красный прямоугольник в случайное положение (это не середина родителя или не соответствует низу).

Большое спасибо за всю помощь заранее.

ОБНОВЛЕНИЕ 1: Итак, следуя предложению, я проверил, вызывается ли мой метод дважды и, таким образом, создает дубликаты. Не повезло, так как это называется только один раз. Тайна все еще сильна!

Что касается махинаций с позиционированием, я немного изменил код, чтобы установить положение красного прямоугольника в соответствии с его родительским узлом:

SKLabelNode *replayButton = [SKLabelNode labelNodeWithFontNamed:@"Quicksand-Bold"];
replayButton.fontSize = 25.f;
NSString* replayText = [NSString stringWithFormat:@"Play Again"];
[replayButton setText:replayText];
replayButton.name = kGOSceneReplayButton;
replayButton.position = CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)- self.frame.size.height/5);
[replayButton setFontColor:[SKColor whiteColor]];
SKShapeNode *bgNode = [SKShapeNode shapeNodeWithRectOfSize:replayButton.frame.size];
[bgNode setFillColor:[UIColor redColor]];


[self addChild:replayButton];
bgNode.position = replayButton.position;
[replayButton addChild:bgNode];

Но после обновления получил вот это:

введите здесь описание изображения

Если это поможет, вот что я делаю, чтобы представить сцену:

SKView * skView = (SKView *)self.view;
skView.showsFPS = YES;
skView.showsNodeCount = YES;
/* Sprite Kit applies additional optimizations to improve rendering performance */
skView.ignoresSiblingOrder = YES;
scene = [GameOverScene sceneWithSize:self.view.frame.size];
[(GameOverScene*)scene setGameEndingSceneDelegate:self];
[(GameOverScene*)scene setScaleMode: SKSceneScaleModeAspectFill];
[(GameOverScene*)scene showGameEndingWithGameInformation:self.gameEndingInfo];

// Present the scene.
[skView presentScene:scene transition:sceneTransition];

Кроме того, это вывод моего NSLog:

размеры воспроизведения: {{221, 91}, {127, 25}

У меня такое ощущение, что из-за того, что я установил setScaleMode для своей сцены, это становится странным, но в остальном ничего необычного, поэтому я не знаю, что делать. Я думаю, может быть, просто создать изображение для моей метки и изменить SKLabelNode на SKSpriteNode и установить изображение, поэтому я пропускаю добавление красного прямоугольника в качестве фона для узла метки. Причина, по которой я хотел добавить прямоугольник, на самом деле состоит в том, чтобы обеспечить большую цель при нажатии «Кнопки», поэтому, если кто-нибудь знает более простой и простой способ, я был бы очень признателен.

ОБНОВЛЕНИЕ 3:

Я также попытался установить положение прямоугольника в соответствии с положением родительского узла метки:

bgNode.position = [replayButton convertPoint:CGPointMake(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame)- self.frame.size.height/5) fromNode:self];

прямоугольник заканчивается в том же месте, что и последнее обновление (вплоть до правой части экрана)


person Septronic    schedule 23.01.2016    source источник
comment
@originaluser2 Я пробовал оба, setupView вызывается только один раз, а с обновленным кодом происходят более странные вещи! Я обновил исходный пост с обновлением кода. Это довольно странно!   -  person Septronic    schedule 23.01.2016
comment
@originaluser2 При добавлении SKLabelNode в симуляторе iOS 9 количество узлов увеличивается на два. Так что это не ошибка ОП.   -  person Whirlwind    schedule 23.01.2016
comment
@Whirlwind Дело в том, что я запускаю его на устройстве.   -  person Septronic    schedule 23.01.2016
comment
@Septronic Очевидно, что нет никакой разницы, я просто говорю, что это не проблема логики кода.   -  person Whirlwind    schedule 23.01.2016
comment
@Whirlwind О, круто. Спасибо что подметил это. Любые предложения для меня попробовать?   -  person Septronic    schedule 23.01.2016
comment
Не могу попробовать ваш код прямо сейчас, но когда я сяду за компьютер, я дам вам знать, если придумаю что-нибудь полезное :)   -  person Whirlwind    schedule 23.01.2016
comment
@Whirlwind Хорошо, большое спасибо. Если вы предпочитаете перейти в чат, дайте мне знать.   -  person Septronic    schedule 23.01.2016


Ответы (1)


Есть несколько проблем с вашим кодом:

  1. lineWidth и его значение по умолчанию равно 1,0. Должно быть 0.0f

  2. verticalAlignmentMode и его базовое выравнивание по умолчанию. Это должно быть SKLabelVerticalAlignmentModeCenter.

  3. Неправильное расположение узла формы. Должно быть (0,0)

Чтобы исправить это, измените вертикальное выравнивание метки:

replayButton.verticalAlignmentMode = SKLabelVerticalAlignmentModeCenter;

установите для свойства lineWidth shapenode значение 0.0f:

bgNode.lineWidth = 0.0f;

и удалите эту строку:

//bgNode.position should be CGPointZero which is (0,0)
bgNode.position = replayButton.position; 

Тем не менее, я бы воздержался от такого подхода. SKShapeNode в данной ситуации не нужен. Вы можете сделать то же самое с SKSpriteNode. Важно то, что и SKShapeNode, и SKLabelNode не могут быть отрисованы в пакетном режиме, что означает, что они не могут быть отрисованы за один проход при рендеринге как SKSpriteNode. Взгляните на это. Ваш пример слишком прост, чтобы создавать проблемы с производительностью, но в целом вы должны все это иметь в виду.

Если текст вашей кнопки никогда не меняется во время игры, вам следует подумать об использовании SKSpriteNode, инициализированного текстурой. Если вас интересуют готовые кнопки для SpriteKit, взгляните на SKAButton.

Надеюсь это поможет!

person Whirlwind    schedule 23.01.2016
comment
ФАНТАСТИЧЕСКИЙ! Это попало в точку (ну, заполнило место за текстом метки! ) :) Упомянутый вами SKAButton выглядит действительно хорошо, но у меня всего несколько кнопок, и я не уверен, что есть смысл использовать стороннюю библиотеку. Но я взял это на заметку для будущих проектов!! Большое спасибо! - person Septronic; 23.01.2016