【问题标题】:Why [SKAction runBlock:^(void){}] never works?为什么 [SKAction runBlock:^(void){}] 从不工作?
【发布时间】:2016-02-26 01:36:31
【问题描述】:

我正在尝试制作无限数量的硬币,这些硬币会一一掉落(waitforduration: 方法制作的空间相等),由于某些原因我无法弄清楚,[NSTread sleepForTimeInterval:] 在sprite kit(第一枚硬币和第二枚硬币之间的差距总是与其他相同的差距不同)所以我尝试使用这段代码,但事实是,它也从来没有用过,我做错了什么?但是我的代码适用于dispatch_queue_t fallingCoinsQueue = dispatch_queue_create("falling coins", nil); dispatch_async(fallingCoinsQueue, ^{ //Do Whatever }); ,但我想使用SKAction runBlock^(void){} 来代替,非常感谢任何帮助。

@interface MyScene()
{
    SKTexture* goldenCoin;
    SKTexture* blackCoin;
}
@property (nonatomic,strong) SKSpriteNode * randomCoinNode;
@end

-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        [self AddRightColumnCoins:self.size];
    }
    return self;
}

-(void)AddRightColumnCoins:(CGSize)size{

   __block int counter = 0;

   _randomCoinNode = [SKSpriteNode new];

   SKAction *run = [SKAction runBlock:^(void){

            NSArray * coinArray= [[NSArray alloc] initWithObjects:goldenCoin,blackCoin,nil];
            NSUInteger randomIndex = arc4random() % [coinArray count];
            _randomCoinNode =[SKSpriteNode spriteNodeWithTexture:coinArray[randomIndex]];
            _randomCoinNode.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius: _randomCoinNode.size.width/2];
            CGFloat x = self.view.frame.size.width - ( _randomCoinNode.frame.size.width - 10 );
            CGFloat y = self.view.frame.size.height;
            _randomCoinNode.position = CGPointMake(x , y);
            _randomCoinNode.physicsBody.dynamic = NO;

            if( _randomCoinNode.texture == goldenCoin){
                _randomCoinNode.physicsBody.categoryBitMask = goldenCoinCategory;
            }else{
                _randomCoinNode.physicsBody.categoryBitMask = blackCoinCategory;
            }
            _randomCoinNode.physicsBody.contactTestBitMask = flappyCategory;
            counter++;
            [self addChild: _randomCoinNode];
            _fall = [SKAction moveToY:-50.0f duration:2];
            [_randomCoinNode runAction:_fall];

    }];

    SKAction *wait = [SKAction waitForDuration:0.6];
    SKAction *sequence = [SKAction sequence:@[run, wait]];
    SKAction *repeat = [SKAction repeatActionForever:sequence];
    [_randomCoinNode runAction: repeat];   
}

【问题讨论】:

  • 在提问之前先搜索一下这个网站。有很多答案涵盖了使用 SKAction 无限生成对象。我写了几次,以及其他人,所以只需搜索。关于使用 GCD 来实现这一点 - 这是一种糟糕的方式。不是因为 GCD 本身,而是因为它是不必要的。关于使用 NSThread 及其 sleep 方法 - 这是一种糟糕的方法 :) 所以坚持使用 SKActions 或 update: 方法。
  • 另外,请记住,在块内使用 self ,就像您现在正在做的那样,可能很容易导致强引用周期,然后您将遇到内存问题,或者更准确地说 - 泄漏.. . 管理对象之间的“关系”(并在需要时使用弱引用)是您的责任。
  • 我搜索了很多,我尝试以多种不同的方式使用 GDC,但我总是遇到 [NSTread sleepforduration] 的相同问题,我尝试以多种不同的方式使用 waitforduration,但实际上它从未奏效,我唯一想知道的是为什么我的代码永远不会在运行块内工作。对不起
  • 你正在创建一个新的精灵,但不要将它添加到这里的场景中
  • 我愿意[self addChild: _randomCoinNode];

标签: ios objective-c sprite-kit skscene


【解决方案1】:

就个人而言,当涉及到一些事情时,我可能会以不同的方式执行此操作,例如命名硬币纹理,或使用属性与实例变量等。但是,为了保持我的示例,类似于您的代码,这就是您的方式可以做到(复制粘贴看看效果如何):

#import "GameScene.h"

@interface GameScene()
{
    SKTexture* goldenCoin;
    SKTexture* blackCoin;
}
@end


@implementation GameScene

-(instancetype)initWithSize:(CGSize)size {

    if (self = [super initWithSize:size]) {

        SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:@"coins"];

        goldenCoin = [atlas textureNamed:@"goldenCoin"];
        blackCoin = [atlas textureNamed:@"blackCoin"];

    }
    return self;
}

-(void)didMoveToView:(SKView *)view{

    //use  withRange: parameter if you want to randomize a delay
    SKAction *wait = [SKAction waitForDuration:1];

    __weak typeof(self) weakSelf = self;

    SKAction *block = [SKAction runBlock:^{

        SKSpriteNode *coin = [weakSelf spawnRandomCoin];
        [weakSelf addChild:coin];
    }];

    SKAction *sequence = [SKAction sequence:@[wait, block]];

    SKAction *loop = [SKAction repeatActionForever:sequence];

    //access this key later to stop spawning
    [self runAction:loop withKey:@"spawning"];
}

-(SKSpriteNode*)spawnRandomCoin {

    NSArray * coinArray= [[NSArray alloc] initWithObjects:goldenCoin,blackCoin,nil];
    NSUInteger randomIndex = arc4random() % [coinArray count];
    NSLog(@"random index : %lu", randomIndex);
    //Create and setup a coin
    SKSpriteNode *coin = [SKSpriteNode spriteNodeWithTexture:coinArray[randomIndex]];

    coin.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius: coin.size.width/2.0f];
    CGFloat x = self.view.frame.size.width - ( coin.frame.size.width - 10.0f );
    CGFloat y = self.view.frame.size.height;
    coin.position = CGPointMake(x , y);
    coin.physicsBody.dynamic = NO;


    //setup coin's category here
    if (coin.texture == blackCoin){

    }else{

    }

    //setup moving action
    SKAction *move = [SKAction moveToY:-coin.size.width duration:5];
    SKAction *moveAndRemove = [SKAction sequence:@[move, [SKAction removeFromParent]]];

    [coin runAction:moveAndRemove withKey:@"moving"];

    return coin;
}
@end

关于您的代码:

  • _randomCoinNode,在最好的情况下将存储对添加到场景中的最后一个硬币的引用。这没有多大意义,我想这不是你想要的。

  • 在初始化程序、反初始化程序和覆盖的访问器方法(getter 和 setter)之外的任何地方,您都应该使用访问器方法或点语法来访问实例变量(根据文档的建议)。意味着,在你的方法中,你应该使用self.randomCoinNode 而不是_randomCoinNode

  • 我已经在我的 cmets 中提到过其他问题(强引用循环和在块内捕获自我)。

【讨论】:

  • 非常感谢,我会尽快尝试。
  • 只是想知道为什么coin.physicsBody 被初始化了两次。不过还是谢谢你。 @旋风
  • @ConnorT 复制/粘贴错误:)。您可以毫无顾虑地删除一条语句。感谢您指出这一点。
猜你喜欢
  • 1970-01-01
  • 2011-08-20
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-23
相关资源
最近更新 更多