为什么 [SKAction runBlock:^(void){}] 永远不起作用?
Why [SKAction runBlock:^(void){}] never works?
我正在尝试制作无限数量的硬币,这些硬币会一枚一枚地掉落(使用 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];
}
就我个人而言,当涉及到一些事情时,我可能会以不同的方式做到这一点,比如命名硬币纹理,或者使用属性与实例变量等。但是,为了保持我的例子,类似于你的代码,这是如何操作(复制并粘贴以查看其工作原理):
#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
.
其他问题(强引用循环和在块内捕获自我)我已经在我的评论中提到了。
我正在尝试制作无限数量的硬币,这些硬币会一枚一枚地掉落(使用 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];
}
就我个人而言,当涉及到一些事情时,我可能会以不同的方式做到这一点,比如命名硬币纹理,或者使用属性与实例变量等。但是,为了保持我的例子,类似于你的代码,这是如何操作(复制并粘贴以查看其工作原理):
#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
.其他问题(强引用循环和在块内捕获自我)我已经在我的评论中提到了。