7

以下の問題についてバグを報告しました。良い回避策を持っている人はいますか?

ファイルに保存しSKTextureて再度ロードしようとしましたが、成功しません。次のコード スニペットは、Xcode スタートアップ プロジェクトのGameScene.mにコピーできます。

で使用textureFromNodeしていますがgenerateTexture、それが問題の根本原因のようです。スプライトのテクスチャを使用すると、コードが機能し、2 つの宇宙船が表示されます。

このコードは iOS 8 では機能しましたが、Xcode7 と iOS 9 では機能しなくなりました。バグ レポートを提出する前に、これがバグであることを確認したいだけです。私の心配は、私が何か悪いことをしたことですNSKeyedArchiver

シミュレーターとデバイスの両方で発生します。

#import "GameScene.h"

@implementation GameScene

// Generates a texture
- (SKTexture *)generateTexture
{
    SKScene *scene = [[SKScene alloc] initWithSize:CGSizeMake(100, 100)];

    SKShapeNode *shapeNode = [SKShapeNode shapeNodeWithRectOfSize:CGSizeMake(50, 50)];
    shapeNode.position = CGPointMake(50, 50);
    shapeNode.strokeColor = SKColor.redColor;
    shapeNode.lineWidth = 10;
    [scene addChild:shapeNode];

    SKTexture *texture = [self.view textureFromNode:scene];
    //SKTexture *texture = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"].texture; // This works!

    return texture;
}

// Just generate a path
- (NSString *)fullDocumentsPath
{
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *yourFileName = [documentsDirectory stringByAppendingPathComponent:@"fileName"];

    return yourFileName;
}

- (void)didMoveToView:(SKView *)view
{    
    self.scaleMode = SKSceneScaleModeResizeFill;

    // Verify that the generateTexture method indeed produces a valid texture.
    SKSpriteNode *s1 = [SKSpriteNode spriteNodeWithTexture:[self generateTexture]];
    s1.position = CGPointMake(100, 100);
    [self addChild:s1];

    // Start with saving the texture.
    NSString *fullName = [self fullDocumentsPath];
    NSError *error;
    NSFileManager *fileMgr = [NSFileManager defaultManager];
    if ([fileMgr fileExistsAtPath:fullName])
    {
        [fileMgr removeItemAtPath:fullName error:&error];
        assert(error == nil);
    }
    NSDictionary *dict1 = [NSDictionary dictionaryWithObject:[self generateTexture] forKey:@"object"];
    bool ok = [NSKeyedArchiver archiveRootObject:dict1 toFile:fullName];
    assert(ok);

    // Read back the texture and place it in a sprite. This sprite is not shown. Why?
    NSData *data = [NSData dataWithContentsOfFile:fullName];
    NSDictionary *dict2 = [NSKeyedUnarchiver unarchiveObjectWithData:data];
    SKTexture *loadedTexture = [dict2 objectForKey:@"object"];
    SKSpriteNode *s2= [SKSpriteNode spriteNodeWithTexture:loadedTexture];
    NSLog(@"t(%f, %f)", loadedTexture.size.width, loadedTexture.size.height); // Size of sprite & texture is zero. Why?
    s2.position = CGPointMake(200, 100);
    [self addChild:s2];
}

@end

Yudongの更新:

これはより適切な例かもしれませんが、シーンが 4 つのレイヤーで構成され、多くのスプライトがあると想像してください。ゲームプレイが終わったら、試合終了シーンのサムネイル画像を保存したいです。画像はボタンのテクスチャとして使用されます。そのボタンを押すと、試合のリプレイ ムービーが開始されます。古いゲームの画像のボタンがたくさんあるので、各画像をファイルに保存する必要があります。

-(SKTexture*)generateTexture
{
  SKScene *scene = [[SKScene alloc] initWithSize:CGSizeMake(100, 100)];

  SKSpriteNode *ship = [SKSpriteNode spriteNodeWithImageNamed:@"Spaceship"];
  ship.position = CGPointMake(50, 50);
  [scene addChild:ship];

  SKTexture *texture = [self.view textureFromNode:scene];

  NSLog(@"texture: %@", texture);

  return texture;
}

解決策/回避策:

ラッセルズ コードに触発されて、次のことを行いました。できます!

CGImageRef  cgImg = texture.CGImage;
SKTexture *newText = [SKTexture textureWithCGImage:cgImg];
4

2 に答える 2

8

私は SKTextures を使って多くの実験/ハッキングを行ってきました。私のゲームは SKTextures を利用しています。スイフトで書かれています。具体的には、textureFromNode と textureFromNode:crop:、およびテクスチャから SKPhysicsBodies を作成する際に多くの問題がありました。これらの方法は ios 8 では正常に機能しましたが、Apple は ios 9.0 をリリースしたときにそれらを完全に壊しました。iOS 9.0 では、テクスチャがゼロに戻っていました。これらの nil テクスチャは、テクスチャから SKPhysicsBodies を壊しました。

私は最近、SKTextures のシリアル化/逆シリアル化に取り組みました。

調査する可能性のある重要なアイデア/手がかりは次のとおりです。

  1. iOS 9.2 を実行します。Apple スタッフは、多くの問題が修正されたと述べています。https://forums.developer.apple.com/thread/17463 iOS 9.2 が SKTextures に役立つことがわかりましたが、すべての問題、特にシリアライゼーションの問題は解決されませんでした。

  2. PrefersOpenGL を試してください (設定でブール値のカスタム プロパティとして "YES" に設定してください)。これは、Apple スタッフによる Apple Dev Forums の PrefersOpenGL に関する投稿です。https://forums.developer.apple.com/thread/19683 iOS 9.x はデフォルトで OpenGL ではなく Metal を使用しているようです。PrefersOpenGL が SKTexture の問題に役立つことがわかりましたが、まだ SKShaders が機能しません (GLSL で記述されています)。

  3. iOS 9.2 で SKTextures を使用してノードをシリアライズ/デシリアライズしようとすると、目に見えるテクスチャではなく白いボックスが表示されました。Apple SKTexture ドキュメントに触発され、「テクスチャ データは次の場合に読み込まれます。

テクスチャ オブジェクトの size メソッドが呼び出されます。

テクスチャ オブジェクトを使用する新しい SKSpriteNode オブジェクトの作成など、テクスチャのサイズを必要とする別のメソッドが呼び出されます。

プリロード メソッドの 1 つが呼び出されます (テクスチャ データのプリロードを参照してください)。

テクスチャ データは、次の場合にレンダリング用に準備されます。

テクスチャを使用するスプライトまたはパーティクルは、レンダリングされるノード ツリーの一部です。」

... CGImage() 呼び出しからセカンダリ テクスチャを作成する回避策をハックしました。

        // ios 9.2 workaround for white boxes on serialization
        let img = texture!.CGImage()
        let uimg = UIImage(CGImage: img)
        let ntex = SKTexture(image: uimg)
        let sprite = SKSpriteNode(texture: ntex, size: texture!.size())

したがって、この方法で作成された SKSpriteNodes は、正常にシリアル化/逆シリアル化されているようです。ところで、 size() を呼び出すか、元のテクスチャを使用して SKSpriteNode を作成するだけでは、テクスチャをメモリに具体化するのに十分ではないようです。

  1. textureFromNode:crop: については質問しませんでしたが、役立つ場合に備えて、とにかく観察を追加しています: iOS 8 でこのメソッドが機能することがわかりました (ただし、トリミングパラメーターは非常にトリッキーで、UIScreen での正規化が必要なようでした. mainScreen().scale) iOS 9.0 では、このメソッドはまったく機能しませんでした (nil が返されました)。iOS 9.2 では、このメソッドは機能するようになりました (非 nil テクスチャを返すようになりました) が、その後のテクスチャからのノードの作成では、サイズの正規化は必要ありません。さらに、シリアライゼーション/デシリアライゼーションを機能させるには、最終的に上記の #3 を実行する必要があることがわかりました。

これがお役に立てば幸いです。私のアプリは SKTextures に大きく依存しているため、SKTextures で最も苦労したと思います。

于 2015-11-06T08:40:42.753 に答える
2

あなたのコードを Xcode 7 でテストしたところ、 nullがtexture返されることがわかりました。generateTextureこれが、ファイルから何もロードできず、何も保存していない理由です。

NSLogテクスチャまたはスプライトの説明をログに記録するために使用してみてください。たとえば、次の行を に追加しgenerateTextureます。

NSLog(@"texture: %@", texture);

コンソールで得られるもの:

texture: '(null)' (300 x 300)

そして、あなたのコードでs1も同じです:dict1

s1: name:'(null)' texture:[ '(null)' (300 x 300)] position:{100, 100} scale:{1.00, 1.00} size:{100, 100} anchor:{0.5, 0.5回転:0.00

dict1: { object = " '(null)' (300 x 300)"; }

iOS 8 と iOS 9 の両方でこれらのテストを実行すると、異なる結果が得られる可能性があります。

SKShapeNodeを に追加して、sceneからテクスチャを保存する理由がわかりませんscene。1 つの回避策は、 のテクスチャを設定することSKShapeNodeです。コードは正常に動作するはずです。

shapeNode.fillTexture = [SKTexture textureWithImageNamed:@"Spaceship"];
SKTexture *texture = shapeNode.fillTexture;
return texture;

アップデート:

iOS 9 で思うように動かないのはかなりtextureFromNode困ります。試行錯誤して解決しようとしましたが、結局うまくいきませんでした。そのため、画面全体のスナップショットを作成し、それをサムネイルとして設定することを検討していただけないでしょうか。これが私が今日行った進歩であり、あなたがそこからインスピレーションを得ることを願っています.

SKLabelNodeとを含むシーンを作成しSKSpriteNodeましたdidMoveToView。画面上の任意の場所をクリックsnapshotすると、 が呼び出され、縮小されたスクリーンショットがドキュメント フォルダーに保存されます。ここでコードを使用しました。

- (UIImage *)snapshot
{
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.5);
    [self.view drawViewHierarchyInRect:self.view.bounds afterScreenUpdates:YES];
    UIImage *snapshotImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return snapshotImage;
}

サムネイルは として保存されるUIImageため、スプライトのテクスチャ用にロードし直すのは簡単です。サンプル プロジェクトはプロセス全体を示しており、iOS 8 と 9 の両方で動作します。

于 2015-10-01T05:35:33.563 に答える