使 CCSprite 向其他 CCSprite 移动

Posted

技术标签:

【中文标题】使 CCSprite 向其他 CCSprite 移动【英文标题】:Make CCSprite move towards other CCSprite 【发布时间】:2014-01-04 16:15:36 【问题描述】:

我知道以前有人问过这个问题,但我找不到解决方案。我在屏幕上有一个CCSprite,播放器,它由加速度计控制。然后在屏幕顶部每隔 2 秒生成另一个 CCSprites,即敌人。我希望所有的敌人都跟随玩家,如果玩家移动玩家,敌人应该改变方向并朝着CCSprite 前进。到目前为止,这是我的代码:

- (void)spawnEnemies

    monsterTxt = [[CCTexture2D alloc] initWithCGImage:[UIImage imageNamed:@"obj.png"].CGImage resolutionType:kCCResolutionUnknown];
    monster = [CCSprite spriteWithTexture:monsterTxt];

    ... 
    //random spawn position etc.


     CCMoveTo *movemonster = [CCMoveTo actionWithDuration:7.0 position:ccp(_rocket.boundingBox.origin.x, _rocket.boundingBox.origin.y)];
    [monster runAction:[CCSequence actions:movemonster, nil]];

    [_monsters addObject:monster];  //adds the sprite to a mutable array                


- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration

    ...
    //determines new position and move sprite there

    [monster stopAllActions];

    CCMoveTo *movemonster = [CCMoveTo actionWithDuration:7.0 position:ccp(_rocket.boundingBox.origin.x, _rocket.boundingBox.origin.y)];
    [monster runAction:[CCSequence actions:movemonster, nil]];


现在,当我开始游戏时,精灵会朝玩家移动,但是当玩家移动敌人时,它们不会更新他们的目的地,它们只会继续向下并停在玩家的 y 坐标处。过了一会儿,应用程序崩溃了。我做错了什么?

【问题讨论】:

1.你确定你的 didAccelerate 方法被调用了吗? 2. 您真的应该对 Update 函数中的操作进行更改...将 didAccelerate 回调中的数据保存在类变量中。你可能会接到很多关于 didAccelerate 的电话。 如果您的 CCCallBlockN 块在“一段时间后”执行,您从 didAccelerate 方法中从哪里获得“怪物”。看起来该块正在从父级中删除它......这将释放它。如果您然后在 didAccelerate 中访问它,它是否仍然存在(从我在这里看到的无法判断)。 对不起,我粘贴了旧代码。那个块根本不应该在那里。但这并没有真正改变任何东西,只是敌人停在了玩家的 y 值处。 你接到了 didAccelerate 的电话吗?您指定的行为将与未被调用的行为一致... 不,它必须被调用,因为当 iphone 倾斜时播放器精灵会被移动,这是在 didAccelerate 方法中指定的 【参考方案1】:

我的猜测是问题可能出在您没有发布的那段代码中。

在 Cocos2d 的 v2.1 中,在您的层中接收加速度计测量值:

在您的 init 或 onEnterTransitionDidFinish 调用中执行此操作:

   self.accelerometerEnabled = YES;

并重载is方法:

-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration

   CCLOG(@"Acceleration (%f,%f,%f)",
         acceleration.x,
         acceleration.y,
         acceleration.z);
   // Do something meaningful...you probably want to send a notification to
   // some other scene/layer/logic.  It should cache that the acceleration value
   // and then do something on an update(...) call with it.  Then reset it so that
   // it does not get used the next update cycle untila new value comes in (here).

看来你有这个......而且你已经表明你正在收到它们......所以我有点困惑。

SO(健全性检查时间)...

我创建了一个示例项目 (here),其中一个玩家精灵被多个怪物精灵追逐。当用户触摸屏幕(我没有使用加速度计)时,玩家精灵改变位置并且精灵“追逐”他。我为它们的目标位置添加了一些随机偏移量,这样它们就不会全部聚集在播放器的顶部。

这是文件(最重要的部分)的代码,它是随 cocos2d v2.1 项目(我从模板创建的)附带的 HellowWorldLayer 的修改版本:

-(void)createPlayer

   playerMoved = NO;

   if(self.player != nil)
   
      [self removeChild:player];
      self.player = nil;
   
   CGSize scrSize = [[CCDirector sharedDirector] winSize];
   CCSprite* playerSprite = [CCSprite spriteWithFile:@"Icon.png"];
   playerSprite.scale = 2.0;
   playerSprite.position = ccp(scrSize.width/2,scrSize.height/2);
   [self addChild:playerSprite];
   self.player = playerSprite;


-(void)createMonsters

   const int MAX_MONSTERS = 4;
   if(self.monsters.count > 0)
     // Get rid of them
      for(CCSprite* sprite in monsters)
      
         [self removeChild:sprite];
      
      [self.monsters removeAllObjects];
   
   CGSize scrSize = [[CCDirector sharedDirector] winSize];
   for(int idx = 0; idx < MAX_MONSTERS; idx++)
   
      CCSprite* sprite = [CCSprite spriteWithFile:@"Icon.png"];
      float randomX = (arc4random()%100)/100.0;
      float randomY = (arc4random()%100)/100.0;
      sprite.scale = 1.0;
      sprite.position = ccp(scrSize.width*randomX,scrSize.height*randomY);
      [self addChild:sprite];
      [monsters addObject:sprite];
   


-(void)update:(ccTime)delta

   if(playerMoved)
     // Modify all the actions on all the monsters.
      CGPoint playerPos = player.position;
      for(CCSprite* sprite in monsters)
      
         float randomX = (1.0)*(arc4random()%50);
         float randomY = (1.0)*(arc4random()%50);
         CGPoint position = ccp(playerPos.x+randomX,playerPos.y+randomY);
         [sprite stopAllActions];
         [sprite runAction:[CCMoveTo actionWithDuration:3.0 position:position]];
      
      playerMoved = NO;
   

我有一个保留的 CCSprite* 对象(怪物)数组和一个用于播放器的 CCSprite*。我有一面旗帜告诉我玩家是否改变了位置(玩家移动了)。在更新循环中,如果玩家移动了,停止对怪物的所有动作并更新它们。

在屏幕上是这样的:

然后当我移动主精灵时...

他们跟着它...

这有帮助吗?

【讨论】:

这行得通,但我想用操纵杆(偷偷摸摸/偷偷输入)操纵可移动的精灵。我已经删除了触摸层,而 helloWorldLayer.m och 中的最后两个方法将精灵连接到了操纵杆。现在敌人只是移动到第一个位置,然后他们就不动了。我尝试将playerMoved 设为布尔属性并将其设置为YESccTouchesBegan 的操纵杆类中,但敌人仍然没有比第一次更生动。 @user3139210 如果您使用我发布的代码并对其进行修改,以便使用偷偷摸摸的输入而不是手指敲击来改变位置,它应该可以工作。在您的“更新”方法中,如果操纵杆向上,则将 y 位置增加 N 个单位并设置它。其他方向也是如此。 好的,但是我应该把playerMoved = YES放在哪里?感谢您的耐心 我更新了代码 (github.com/NonlinearIdeas/CC2DSpriteTest) 来展示如何处理这个问题。我用浮点值 secondsSinceLastUpdate 替换了 playerMoved 标志。现在,无论玩家发生什么,怪物都会更新他们的行动。查看 HelloWorldLayer.m/.h 中的变化。 啊,现在我搞定了。非常感谢你的一切!非常感谢您的帮助!

以上是关于使 CCSprite 向其他 CCSprite 移动的主要内容,如果未能解决你的问题,请参考以下文章

设置 CCSprite 的框架?

CCSprite 带有图像文件和声音文件

在 CCSprite 中淡入图像?

cocos2d CCSprite 碰撞问题

CGRect 随 CCSprite 旋转而变化?

将 UIScrollView 添加到 CCSprite