Можно ли использовать круг (SKShapeNode) в качестве маски в Sprite Kit?

Я пытаюсь создать круговую маску в проекте Sprite Kit. Я создаю круг таким образом (позиционируя его в центре экрана):

SKCropNode *cropNode = [[SKCropNode alloc] init];

SKShapeNode *circleMask = [[SKShapeNode alloc ]init];
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, CGRectGetMidX(self.frame), CGRectGetMidY(self.frame), 50, 0, M_PI*2, YES);
circleMask.path = circle;
circleMask.lineWidth = 0;
circleMask.fillColor = [SKColor blueColor];
[email protected]"circleMask";

и далее вниз код, я установил его как маску для cropNode:

[cropNode setMaskNode:circleMask];

... но вместо содержимого, отображаемого внутри круга, маска отображается как квадрат.

Можно ли использовать SKShapeNode в качестве маски, или мне нужно использовать изображение?

Ответ 1

После долгих ругательств, чистки веб-страниц и экспериментов в Xcode у меня есть действительно хакерское исправление.

Имейте в виду, что это действительно неприятный взлом, но вы можете обвинить его в реализации Sprite Kit SKShapeNode. Добавление заливки в путь вызывает следующее:

  • добавляет дополнительный node к вашей сцене
  • путь становится немасштабируемым - он отображается над маской
  • делает невозможным доступ к нескольким узлам не-t21 > (например, SKLabelNode s)

Не идеальное положение дел.

Вдохновленный Тоном прогресса Tony Chamblee, 'fix' состоит в том, чтобы обойтись без заполнения и просто использовать ход пути:

SKCropNode *cropNode = [[SKCropNode alloc] init];

SKShapeNode *circleMask = [[SKShapeNode alloc ]init];
CGMutablePathRef circle = CGPathCreateMutable();
CGPathAddArc(circle, NULL, CGRectGetMidX(self.frame), CGRectGetMidY(self.frame), 50, 0, M_PI*2, YES); // replace 50 with HALF the desired radius of the circle
circleMask.path = circle;
circleMask.lineWidth = 100; // replace 100 with DOUBLE the desired radius of the circle
circleMask.strokeColor = [SKColor whiteColor];
[email protected]"circleMask";

[cropNode setMaskNode:circleMask];

Как прокомментировано, вам нужно установить радиус на половину того, что вы обычно имели, и ширину линии, чтобы удвоить радиус.

Надеюсь, Apple будет смотреть на это в будущем; на данный момент этот хак - лучшее решение, которое я нашел (кроме использования изображения, которое на самом деле не работает, если ваша маска должна быть динамичной).

Ответ 2

Да, в текущей реализации Sprite-Kit невозможно использовать полноцветный шейенид. Думаю, это ошибка.

Но!

Вы всегда можете сделать фигуру текстурой и использовать ее как маску!

Для примера, пусть edge - это SKShapeNode, созданный ранее.

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

SKTexture *Mask = [self.view textureFromNode:edge];
[self addChild:edge]; //if you need physics borders

Во-вторых,

SKCropNode *cropNode = [[SKCropNode alloc] init];
[cropNode setMaskNode:[SKSpriteNode spriteNodeWithTexture:Mask]];
[cropNode addChild: [SKSpriteNode spriteNodeWithTexture:rocksTiles size:CGSizeMake(w,h)]];
cropNode.position = CGPointMake(Mask.size.width/2,Mask.size.height/2);
//note, anchorpoint of shape in 0,0, but rendered texture is in 0.5,0.5, so we need to dispose it
[self addChild:cropNode];

Ответ 3

Поскольку я не могу использовать SKShapeNode как маску, я решил преобразовать ее в SKSpriteNode.

Вот мой код Swift:

let shape : SKShapeNode = ... // create your SKShapeNode
var view : SKView = ... // you can get this from GameViewController

let texture = view.textureFromNode(shape)
let sprite = SKSpriteNode(texture: texture)
sprite.position = ...

cropNode.mask = sprite

И он работает:)

Ответ 4

Есть немного неудобное решение этой проблемы, которое, по моему мнению, немного менее противное, чем любой из обсуждаемых хаков по этой проблеме. Просто оберните SKShapeNode в SKNode. Я не тестировал, какую производительность может вызвать это, но учитывая, что SKNode не является чертежом, я надеюсь, что это не будет слишком значительным.

то есть.

let background = SKSpriteNode(imageNamed: "Background")
let maskNode = SKShapeNode(path: MyPath)
let wrapperNode = SKNode()
let cropNode = SKCropNode()

wrapperNode.addChild(maskNode)
cropNode.maskNode = wrapperNode
cropNode.addChild(background)

Ответ 5

Настройка альфы маски node на .0 делает трюк:

circleMask.alpha = .0;

EDIT: Кажется, работает только для Mac OS.