これに丸一日費やしました。これは、iOS ドキュメントや SO では見つかりません。
SKShapeNode*
アプリのウィンドウのような があり、 である背景を追加します。背景には、子としてSKSpriteNode
別の 10SKSpriteNode
があります。したがって、ノード ツリーは次のようになります。
SKScene -> window -> background -> (child1, ..., child10)
寸法は、背景がウィンドウのサイズと一致し、背景のすべての子が背景内に収まるようになっています。
ウィンドウ内をクリックしたときにズームしたい (背景と 10 人の子供をすべて一緒にズームする)。背景の xScale と yScale を設定することでこれを実現し、子はこのスケーリングを継承します。しかし、ウィンドウの境界の外にこぼしたくないので、SKCropNode を作成し、その子として背景を追加しました。背景がこぼれなくなりました。
SKScene -> window -> SKCropNode -> background -> (child1, ..., child10)
問題は、ズーム時に背景の子がこぼれることです。これは私にとって直感に反することです。オンラインで検索してドキュメントを調べてみましたが、「SKCropNode はその子とすべての子孫をトリミングしますか?」答えはノーのように見えるので、10 人の子の親すべてをバックグラウンドから SKCropNode に変更することを考えました。
SKScene -> window -> SKCropNode -> (background, child1, ..., child10)
次に、SKCropNode をスケーリングします。これにより、背景とすべての子がスケーリングされますが、再びウィンドウの外にこぼれます。(ゲームの後半で、子の数が 10 から 300 に増える可能性があります。300 のアイテムに対して for ループを実行したくありません。そのため、1 つの親だけにスケールを設定できるようにしたいと考えています。)
私は最終的に、少し「ハッキー」なことを試すことにしました。これはオンラインのどこにも見つからなかったので、「未定義の動作」の領域にいるかどうか疑問に思っています。
SKScene -> window -> SKCropNode1 -> SKCropNode2 -> (background, child1, ..., child10)
元の SKCropNode の上に別の SKCropNode を追加しました。ここでは、SKCropNode2 のみをスケーリングします。これは機能します。しかし、今、私は非常に奇妙な振る舞いをしています。私の SKShapeNode ボタン (完全にウィンドウの外側) は、1 つずつ消えてから戻ってきて、このように循環します。また、右下の「nodes: 10, 60.0 fps」も消えて周期に戻ります。サイクルとは、ウィンドウのズーム内をクリックすることを意味します。SpriteKit でバグに遭遇したようですか? ボタンの zPosition を 20 に設定し、他の何よりも高く設定しました (5 以下)。またskview.ignoresSiblingOrder = false;
、これを達成する方法についてのヘルプやアドバイスに感謝します!
編集:コメントへの返信で、シミュレーターは使用しませんでした。iOS 9.2 を実行している iPad Pro と iPhone 6+ でこれをテストしました。以下は、動作をコンパイルして再現する私のコードです。ズームコードも取り出しましたが、まだ再現可能です。宇宙船(Appleのサンプル画像)を30回程度タップしてみてください。
MainScene.h
#import <UIKit/UIKit.h>
#import <SpriteKit/SpriteKit.h>
@interface MainScene : SKScene<NSStreamDelegate>
@property (strong, nonatomic) SKCropNode* skcrop;
@end
MainScene.m
#import "MainScene.h"
@implementation MainScene
- (void)didMoveToView: (SKView*)view { }
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if ((int)[touches count] != 1) return;
UITouch* touch = [touches anyObject];
const CGPoint location = [touch locationInNode:self];
{ // without the 6 lines below, the disappearing-sprites behavior is gone
SKShapeNode* newshape = [SKShapeNode shapeNodeWithRectOfSize:
CGSizeMake(10.0, 10.0) cornerRadius:1.0];
newshape.position = location;
newshape.zPosition = 5;
newshape.fillColor = [UIColor purpleColor];
[self.skcrop addChild:newshape];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { }
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { }
@end
GameViewController.m:
#import "GameViewController.h"
#import "MainScene.h"
#import <CoreFoundation/CoreFoundation.h>
@implementation GameViewController
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskLandscapeLeft
| UIInterfaceOrientationMaskLandscapeRight;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Configure SKView
SKView* skview = (SKView*)self.view;
skview.showsFPS = true;
skview.showsNodeCount = true;
skview.ignoresSiblingOrder = false;
skview.multipleTouchEnabled = false;
// Get Screen Size
// IPad Pro prints: screen size 768 1024
// IPhone 6+ prints: screen size 375 667
const int screenWidth = floor(0.5+skview.bounds.size.width);
const int screenHeight = floor(0.5+skview.bounds.size.height);
NSLog(@"screen size %d %d", screenWidth, screenHeight);
const double width = (screenWidth < 375) ? 360 : 720;
// Configure SKScene
MainScene *skscene = [[MainScene alloc]
initWithSize:CGSizeMake(screenWidth, screenHeight)];
skscene.scaleMode = SKSceneScaleModeFill;
skscene.backgroundColor = [UIColor whiteColor];
[skview presentScene:skscene];
// Set up window's crop mask
const CGSize winSurface = CGSizeMake(width, width);
const CGPoint winPosition = CGPointMake(
CGRectGetMidX(skscene.frame), CGRectGetMidY(skscene.frame));
NSLog(@"pos %f %f", winPosition.x, winPosition.y);
SKSpriteNode* winMaskParent = [[SKSpriteNode alloc]
initWithColor:[UIColor redColor] size:winSurface];
[winMaskParent retain];
winMaskParent.position = winPosition;
SKCropNode* scnParent = [SKCropNode node];
scnParent.zPosition = 1;
scnParent.maskNode = winMaskParent;
[skscene addChild:scnParent];
SKSpriteNode* winMask = [[SKSpriteNode alloc]
initWithColor:[UIColor blueColor] size:winSurface];
[winMask retain];
winMask.position = winPosition;
SKCropNode* scn = [SKCropNode node];
scn.zPosition = 1;
scn.maskNode = winMask;
[scnParent addChild:scn];
// Add window sprite
SKSpriteNode* win =
[SKSpriteNode spriteNodeWithImageNamed:@"Spaceship.png"];
win.zPosition = 2;
win.position = winPosition;
[scn addChild:win];
for (int i = 0; i < 5; ++i) {
const double height = 30.0;
const double width = 50.0;
const double posY = screenHeight - (1+i)*100.0;
const double posX = screenWidth - width - 10.0;
SKShapeNode* button = [SKShapeNode shapeNodeWithRectOfSize:
CGSizeMake(width, height) cornerRadius:1.0];
button.position = CGPointMake(posX, posY);
button.zPosition = 15;
button.fillColor = [UIColor greenColor];
button.lineWidth = 1.0;
button.glowWidth = 0.0;
[skscene addChild:button];
}
skscene.skcrop = scn;
return;
}
@end
編集 2:SKCropNode
SKCropNode のレイヤーが 1 つだけになるように、ネストされたものを削除しました。宇宙船を数回クリックすると、ボタンのスプライトが消えます。