尝试添加一个已经有父节点的 SKNode

Posted

技术标签:

【中文标题】尝试添加一个已经有父节点的 SKNode【英文标题】:Attemped to add a SKNode which already has a parent 【发布时间】:2014-04-28 00:11:36 【问题描述】:

目前正在尝试找到一个解决方案来解决目前正在损害我的应用的问题。我想看看我是否可以更改以下代码以减少内存。现在,我有五种方法,它们都执行以下操作,

-(void)createObstacle0 
  int yMin = (CGRectGetMidY(self.frame)+190);
  int yMax = (CGRectGetMidY(self.frame)+270);
  CGPoint startPoint = CGPointMake(-20, yMin + arc4random_uniform(yMax - yMin));

  SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithImageNamed:@"obstacle"];
  obstacle.position = CGPointMake(startPoint.x, startPoint.y);
  obstacle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:21.5];
  obstacle.physicsBody.categoryBitMask = enemyCategory;
  obstacle.physicsBody.contactTestBitMask = playerCategory;
  obstacle.physicsBody.dynamic = NO;
  obstacle.name = @"obstacle0";
  [self addChild:obstacle];

  [obstacle runAction:[SKAction moveTo:CGPointMake(340, startPoint.y) duration:minTime + arc4random_uniform(maxTime - minTime)]];
  float randomNum = arc4random_uniform(3.0) + 0.1;
  [self performSelector:@selector(createObstacle0) withObject:nil afterDelay:randomNum];

我尝试在我的 .h 文件中声明一个 SKSpriteNode,并让每个方法都使用它而不是在其中声明的 SKSpriteNode,但我得到了上述错误。有人可以告诉我如何更改我的代码,以便图像“障碍”只加载一次。

【问题讨论】:

【参考方案1】:

从您发布的那段代码看来,您正在运行一个无休止的循环来创建障碍物对象。

尝试删除代码行[self performSelector:@selector(createObstacle0) withObject:nil afterDelay:randomNum];

像这样添加一个定时器函数:

- (void)startTimer

[NSTimer scheduledTimerWithTimeInterval:1
                                 target:self
                               selector:@selector(timerAction)
                               userInfo:nil
                                repeats:YES];


-(void)timerAction

    NSLog(@"do something");

您可以通过像这样调用[self startTimer]; 来启动startTimer 方法

您可以从您的 init 方法或您需要的任何其他地方执行此操作。

【讨论】:

是的,我知道,对象会不断生成,直到玩家击中其中一个并且场景转换,这是故意的。 @user3552678 - 删除线路后是否有效? 它可以工作,没有崩溃或任何问题,但我的游戏有很多物体从侧面冒出来,没有那条线,它们不会继续出现,只有一个会。 @user3552678 - 我已经修改了代码示例,添加了一个计时器,供您用来替换您删除的计时器。 这与我所拥有的有何不同?当我尝试运行其中一个以上时,它会运行数百次【参考方案2】:

这里可能有更多类似“SpriteKit”的答案。您还可以将大部分创建过程放入后台线程中的块中,然后在主线程中执行添加和操作,具体取决于您的应用程序中其他事情的强度。下面这个例子的关键是它使用了动作,并且序列有一个键。

-(void)createObstacleRepeatingMethod 

int yMin = (CGRectGetMidY(thingShowingObstacles.frame)+190);
int yMax = (CGRectGetMidY(thingShowingObstacles.frame)+270);

CGPoint startPoint = CGPointMake(-20, yMin + arc4random_uniform(yMax - yMin));
SKSpriteNode *obstacle = [SKSpriteNode spriteNodeWithImageNamed:@"obstacle"];

obstacle.position = CGPointMake(startPoint.x, startPoint.y);

obstacle.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:21.5];
obstacle.physicsBody.categoryBitMask = obstacleCategory;
obstacle.physicsBody.contactTestBitMask = playerCategory;
obstacle.physicsBody.dynamic = NO;
obstacle.name = @"obstacle0";

[thingShowingObstacles addChild:obstacle];
[obstacle runAction:[SKAction moveTo:CGPointMake(340, startPoint.y) duration:minTime + arc4random_uniform(maxTime - minTime)]];

SKAction *waitAction = [SKAction waitForDuration:1.5 withRange:1.4];
SKAction *callCreateObstacleAgain = [SKAction runBlock:^
    [thingShowingObstacles createObstacleRepeatingMethod];
];

SKAction *theSequenceForWaitThenCall = [SKAction sequence:@[waitAction, callCreateObstacleAgain]];

[thingShowingObstacles runAction:theSequenceForWaitThenCall withKey:@"createObstacleSequence"];

//the sequence having a key also ensures that there will only ever be one of the sequence actions running
//it also ensures that you have fine grained control over removing the action by calling
[thingShowingObstacles removeActionForKey:@"createObstacleSequence"]; 

【讨论】:

以上是关于尝试添加一个已经有父节点的 SKNode的主要内容,如果未能解决你的问题,请参考以下文章

错误:尝试添加已经有父节点的 SKNode

尝试添加已经有父节点的 SKNode

Swift:尝试添加一个已经有父节点的 SKNode:

Swift SpriteKit - “尝试添加一个已经有父节点的 SKNode”,同时添加关节

SpriteKit: NSInvalidArgumentException - 试图添加一个已经有父节点的 SKNode

尝试添加一个已经有父错误的 SKNode