五、射击子弹

首先,我们先让这游戏里唯一的图层可以支持触摸。添加下面一行到init方法:

// cpp with cocos2d-x
this->setIsTouchEnabled(true);
// objc with cocos2d-iphone
self.isTouchEnabled = YES;

因为图层已经支持触摸,所以我们可以收到触摸事件的回调。现在我们实现ccTouchesEnded方法,只要用户完成触摸,该方法就会被调用。

先在HelloWorldScene.h里增加函数声明 void ccTouchesEnded(cocos2d::NSSet* touches, cocos2d::UIEvent* event);

然后到HelloWorldScene.cpp里增加函数实现

// cpp with cocos2d-x
void HelloWorld::ccTouchesEnded(NSSet* touches, UIEvent* event)
{
  // Choose one of the touches to work with
  CCTouch* touch = (CCTouch*)( touches->anyObject() );
  CGPoint location = touch->locationInView(touch->view());
  location = CCDirector::getSharedDirector()->convertToGL(location);

// Set up initial location of projectile
  CGSize winSize = CCDirector::getSharedDirector()->getWinSize();
  CCSprite *projectile = CCSprite::spriteWithFile("Projectile.png", 
                                              CGRectMake(0, 0, 20, 20));
  projectile->setPosition( ccp(20, winSize.height/2) );

// Determinie offset of location to projectile
  int offX = location.x - projectile->getPosition().x;
  int offY = location.y - projectile->getPosition().y;

// Bail out if we are shooting down or backwards
  if (offX <= 0) return;

// Ok to add now - we've double checked position
  this->addChild(projectile);

// Determine where we wish to shoot the projectile to
  int realX = winSize.width + (projectile->getContentSize().width/2);
  float ratio = (float)offY / (float)offX;
  int realY = (realX * ratio) + projectile->getPosition().y;
  CGPoint realDest = ccp(realX, realY);

// Determine the length of how far we're shooting
  int offRealX = realX - projectile->getPosition().x;
  int offRealY = realY - projectile->getPosition().y;
  float length = sqrtf((offRealX * offRealX) + (offRealY*offRealY));
  float velocity = 480/1; // 480pixels/1sec
  float realMoveDuration = length/velocity;

// Move projectile to actual endpoint
  projectile->runAction( CCSequence::actions(
      CCMoveTo::actionWithDuration(realMoveDuration, realDest),
      CCCallFuncN::actionWithTarget(this,

callfuncN_selector(HelloWorld::spriteMoveFinished)), 
      NULL) );
}

// objc with cocos2d-iphone
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
  // Choose one of the touches to work with
  UITouch *touch = [touches anyObject];
  CGPoint location = [touch locationInView:[touch view]];
  location = [[CCDirector sharedDirector] convertToGL:location];
    
  // Set up initial location of projectile
  CGSize winSize = [[CCDirector sharedDirector] winSize];
  CCSprite *projectile = [CCSprite spriteWithFile:@"Projectile.png" 
                                         rect:CGRectMake(0, 0, 20, 20)];
  projectile.position = ccp(20, winSize.height/2);
    
  // Determine offset of location to projectile
  int offX = location.x - projectile.position.x;
  int offY = location.y - projectile.position.y;
    
  // Bail out if we are shooting down or backwards
  if (offX <= 0) return;
    
  // Ok to add now - we've double checked position
  [self addChild:projectile];

// Determine where we wish to shoot the projectile to
  int realX = winSize.width + (projectile.contentSize.width/2);
  float ratio = (float) offY / (float) offX;
  int realY = (realX * ratio) + projectile.position.y;
  CGPoint realDest = ccp(realX, realY);
    
  // Determine the length of how far we're shooting
  int offRealX = realX - projectile.position.x;
  int offRealY = realY - projectile.position.y;
  float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY));
  float velocity = 480/1; // 480pixels/1sec
  float realMoveDuration = length/velocity;
    
  // Move projectile to actual endpoint
  [projectile runAction:[CCSequence actions:
    [CCMoveTo actionWithDuration:realMoveDuration position:realDest],
    [CCCallFuncN actionWithTarget:self

selector:@selector(spriteMoveFinished:)],
    nil]];    
}

编译后,带头大哥就可以BIU~BIU~地扔飞镖出去了。这里会产生一些float和int隐式转换导致的warning,我们为了和objc代码保持一致而在坐标计算里使用了不少int变量,实际上全部用float会更合适。

六、碰撞检测

光扔飞镖是杀不死人的,我们还需要加入碰撞检测。要做到这一点,首先得在场景中更好地跟踪目标和子弹。

在这个游戏中,我们得为小怪和飞镖两种sprite加入一个tag成员变量,以区分两种不同的游戏物体。tag=1的时候这个CCSprite对象为小怪,tag=2的时候则为飞镖。由于在CCNode里面有m_nTag这个成员变量,并且有setTag和getTag方法,因此CCSprite就继承了这些方法,我们可以利用之。

修改完毕,现在可以专心地跟踪小怪和飞镖了。把以下代码添加到class HelloWorld的声明中

// cpp with cocos2d-x
protected:
  cocos2d::NSMutableArray<cocos2d::CCSprite*> *_targets;
  cocos2d::NSMutableArray<cocos2d::CCSprite*> *_projectiles;
// objc with cocos2d-iphone

NSMutableArray *_targets;
  NSMutableArray *_projectiles;

在这里,cocos2d-x模拟iOS的SDK实现了NSMutableArray,里面只能放NSObject及其子类。但不同的是,你必须告诉他里面要放的是哪种具体类型。

然后在init方法中初始化这两个数组

// cpp with cocos2d-x
// Initialize arrays
_targets = new NSMutableArray<CCSprite*>;
_projectiles = new NSMutableArray<CCSprite*>;
// objc with cocos2d-iphone
// Initialize arrays
_targets = [[NSMutableArray alloc] init];
_projectiles = [[NSMutableArray alloc] init];

同时在类的析构函数里释放之. 严谨地说,我们还应在class HelloWorld的构造函数里初始化_targets和_projectiles两个指针为NULL

// cpp with cocos2d-x
HelloWorld::~HelloWorld()
{
  if (_targets)
  {
    _targets->release();
    _targets = NULL;
  }

if (_projectiles)
  {
    _projectiles->release();
    _projectiles = NULL;
  }
  
  // cpp don't need to call super dealloc
  // virtual destructor will do this
}

HelloWorld::HelloWorld()
:_targets(NULL)
,_projectiles(NULL)
{
}

// objc with cocos2d-iphone
- (void) dealloc
{
  [_targets release];
  _targets = nil;

[_projectiles release];
  _projectiles = nil;

// don't forget to call "super dealloc"
  [super dealloc];
}

现在修改addTarget方法,添加新目标到目标数组中,并给它设置Tag标记以和飞镖sprite区分开来

// cpp with cocos2d-x
// Add to targets array
taget->setTag(1);
_targets->addObject(target);
// objc with cocos2d-iphone
// Add to targets array
target.tag = 1;
[_targets addObject:target];

然后,修改spriteMoveFinished方法,根据标记的不同,在对应的数组中移除精灵

// cpp with cocos2d-x
void HelloWorld::spriteMoveFinished(CCNode* sender)
{
  CCSprite *sprite = (CCSprite *)sender;
  this->removeChild(sprite, true);

if (sprite->getTag() == 1)  // target
  {
    _targets->removeObject(sprite);
  }
  else if (sprite->getTag() == 2) // projectile
  {
    _projectiles->removeObject(sprite);
  }
}

// objc with cocos2d-iphone
-(void)spriteMoveFinished:(id)sender 
{
  CCSprite *sprite = (CCSprite *)sender;
  [self removeChild:sprite cleanup:YES];
    
  if (sprite.tag == 1) // target
  {
    [_targets removeObject:sprite];
  } 
  else if (sprite.tag == 2) // projectile
  { 
    [_projectiles removeObject:sprite];
  }
}

编译并运行项目以确保一切正常。此时还看不出什么明显不同,但我们可以利用前面加的tag标记来实现碰撞检测

现在往class HelloWorld里添加一个update方法,计算碰撞,并让碰撞了的飞镖和小杂兵同时从屏幕消失

// cpp with cocos2d-x
void HelloWorld::update(ccTime dt)
{
  NSMutableArray<CCSprite*> *projectilesToDelete =        

new NSMutableArray<CCSprite*>;
  NSMutableArray<CCSprite*>::NSMutableArrayIterator it, jt;

for (it = _projectiles->begin(); it != _projectiles->end(); it++)
  {
    CCSprite *projectile =*it;
    CGRect projectileRect = CGRectMake(
     projectile->getPosition().x - (projectile->getContentSize().width/2),
     projectile->getPosition().y - (projectile->getContentSize().height/2),
     projectile->getContentSize().width,
     projectile->getContentSize().height);

NSMutableArray<CCSprite*>*targetsToDelete =new NSMutableArray<CCSprite*>;
                
    for (jt = _targets->begin(); jt != _targets->end(); jt++)
    {
      CCSprite *target =*jt;
      CGRect targetRect = CGRectMake(
     target->getPosition().x - (target->getContentSize().width/2),
     target->getPosition().y - (target->getContentSize().height/2),
     target->getContentSize().width,
     target->getContentSize().height);
                        
      if (CGRect::CGRectIntersectsRect(projectileRect, targetRect))
      {
        targetsToDelete->addObject(target);
      }
    }

for (jt = targetsToDelete->begin(); jt != targetsToDelete->end(); jt++)
    {
      CCSprite *target =*jt;
      _targets->removeObject(target);
      this->removeChild(target, true);
    }

if (targetsToDelete->count() >0)
    {
      projectilesToDelete->addObject(projectile);
    }
    targetsToDelete->release();
  }

for (it = projectilesToDelete->begin(); it != projectilesToDelete->end(); it++)
  {
    CCSprite* projectile =*it;
    _projectiles->removeObject(projectile);
    this->removeChild(projectile, true);
  }
  projectilesToDelete->release();
}

// objc with cocos2d-iphone
- (void)update:(ccTime)dt 
{
  NSMutableArray *projectilesToDelete =  

[[NSMutableArray alloc] init];

for (CCSprite *projectile in _projectiles) 
  {

CGRect projectileRect = CGRectMake(
     projectile.position.x - (projectile.contentSize.width/2), 
     projectile.position.y - (projectile.contentSize.height/2), 
     projectile.contentSize.width, 
     projectile.contentSize.height);

NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];

for (CCSprite *target in _targets) 
    {
      
      CGRect targetRect = CGRectMake(
     target.position.x - (target.contentSize.width/2), 
     target.position.y - (target.contentSize.height/2), 
     target.contentSize.width, 
     target.contentSize.height);
    
      if (CGRectIntersectsRect(projectileRect, targetRect)) 
      {
        [targetsToDelete addObject:target];                
      }                        
    }
        
    for (CCSprite *target in targetsToDelete) 
    {

[_targets removeObject:target];
      [self removeChild:target cleanup:YES];                                    
    }
        
    if (targetsToDelete.count >0) 
    {
      [projectilesToDelete addObject:projectile];
    }
    [targetsToDelete release];
  }
    
  for (CCSprite *projectile in projectilesToDelete) 
  {

[_projectiles removeObject:projectile];
    [self removeChild:projectile cleanup:YES];
  }
  [projectilesToDelete release];
}

上面有个注意点,我们用来检查矩形交叉的函数。实际上各平台都有用来检查矩形相交的函数,我们这里为了方便iphone开发者转换代码,实现了静态的CGRect::CGRectInterestcRect方法。上面的代码大致就是,遍历小怪和飞镖数组,一旦发现有矩形相交(碰撞),就把他们分别添加到targetsToDelete和projectileToDelete数组中,然后删除之

在运行之前,你还需要让这个update方法不断地被调用,可以在init方法中添加如下代码达成这个目的

// cpp with cocos2d-x
this->schedule( schedule_selector(HelloWorld::update) );
// objc with cocos2d-iphone
[self schedule:@selector(update:)];

编译运行,你就可以看到飞镖和小怪碰撞时,它们同时从屏幕消失了。

至此,一个简单cocos2d游戏的雏形就已经完成了。在下一篇里,我们会对这个游戏进行最后的润色,添加背景音乐和音效,已经过关和GAME OVER的提示界面。

本文转自Walzer博客园博客,原文链接:http://www.cnblogs.com/walzer/archive/2010/10/11/1848106.html,如需转载请自行联系原作者

如何用cocos2d-x来开发简单的Uphone游戏:(三) 射击子弹 碰撞检测相关推荐

  1. 如何用cocos2d-x来开发简单的Uphone游戏:(二) 移动的精灵

    三.添加一个精灵 我们先用个简单的方式,把player, projectile, target三个PNG文件拷贝到 D:\Work7\NEWPLUS\TDA_DATA\UserData 目录下,这使其 ...

  2. [20110209]Cocos2dSimpleGame入门系列《如何用cocos2d-x来开发简单的Uphone游戏》学习小记

    原文: http://www.cnblogs.com/walzer/archive/2010/10/10/1847089.html 拜读王哲王总的cocos2d-x入门教程,将学习过程中对C++或co ...

  3. 翻译:如何用Cocos2d来开发简单的IPhone游戏教程

    这一周接触到Cocos2D开发,在它的官网上看到Ray Wenderlic写的关于cocos2d开发的文章,感觉写的挺好,翻译了一下.  原文链接地址大家可以在上面看到作者的更多内容 初次翻译文章,望 ...

  4. Cocos2D教程:使用SpriteBuilder和Cocos2D 3.x开发横版动作游戏——Part 2

    本文是"使用Cocos2D 3.x开发横版动作游戏"系列教程的第二篇,同时也是最后一篇.是对How To Make A Side-Scrolling Beat Em Up Game ...

  5. Cocos2D教程:使用SpriteBuilder和Cocos2D 3.x开发横版动作游戏——Part 1

    本文是对教程How To Make A Side-Scrolling Beat Em Up Game Like Scott Pilgrim with Cocos2D – Part 1的部分翻译,加上个 ...

  6. 如何使用cocos2d-x 3.0来做一个简单的iphone游戏教程(第一部分)

    游戏截图: cocos2d-x 是一个支持多平台的开源框架,用于构建游戏.应用程序和其他图形界面交互应用.Cocos2d-x项目可以很容易地建立和运行在iOS,Android的三星Bada,黑莓Bla ...

  7. HiLink LiteOS IoT芯片 让IoT开发简单高效

    HiLink & LiteOS & IoT芯片 让IoT开发简单高效 华为HiLink & LiteOS & IoT芯片使能三件套,让IoT开发更简单高效.下一代智能手 ...

  8. Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏

    Unity 2D游戏开发快速入门第1章创建一个简单的2D游戏 即使是现在,很多初学游戏开发的同学,在谈到Unity的时候,依然会认为Unity只能用于制作3D游戏的.实际上,Unity在2013年发布 ...

  9. 记事本写python怎么运行-Python开发简单记事本

    摘要: 本文是使用Python,结合Tkinter开发简单记事本. 本文的操作环境:ubuntu,Python2.7,采用的是Pycharm进行代码编辑,个人很喜欢它的代码自动补齐功能. 最近很想对p ...

  10. python一般用来开发什么-python主要用来做什么?Python开发简单吗?

    python主要用来做什么?Python开发简单吗?Python技术可做web开发.Python技术可做数据分析.Python技术可做人工智能.将Python用于机器学习,流行的Python机器学习库 ...

最新文章

  1. 硬科技凭什么产业化?
  2. 问得最多的十个JavaScript前端面试问题
  3. 牛顿迭代法(Newton's Method)
  4. MySQL数据库Innodb储存引擎----储存页的结构
  5. OpenCASCADE:形状愈合之用于修复、分析和升级的辅助工具
  6. 政企边缘安全,如何助您提升企业免疫力?
  7. Android异步处理:Handler+Looper+MessageQueue深入详解
  8. python里如何计算大文件的md5
  9. Linux 5.10 LTS 发布,支持到 2026 年
  10. JavaWab项目1 ---- 技术架构
  11. 信么?PrintDemon 漏洞影响自1996年起发布的所有 Windows 版本
  12. 鸿蒙os2.0官网公测报名,鸿蒙OS2.0公测版测试资格报名-鸿蒙OS2.0公测版测试资格报名官网地址预约 -友情手机站...
  13. 烧录工具Android Tool的使用
  14. 微信小程序tab切换,可滑动切换,导航栏跟随页面滚动
  15. QOne、QData开关机操作
  16. maven Web项目中POM的配置信息
  17. 【缓存】@CacheEvict
  18. Redis之EXPIRE
  19. 如何查看.o和.exe文件
  20. Windows 源码编译 nginx (加入nginx-http-flv-module)

热门文章

  1. 英国正在大举进军AI,看懂其三大投资走向
  2. c#文件排序和文件夹排序
  3. 【JavaWeb】用监听器实现单一登录
  4. 用简单易懂的话语来快速入门windows缓冲区溢出
  5. 生信学习笔记:利用GATK call SNP
  6. 多媒体计算机的媒体信息包括文字,多媒体计算机中的媒体信息是指什么
  7. 终于稳了!2020年8月程序员工资最新统计
  8. 计算机搜索栏打字不显示,win7系统电脑使用搜狗输入法打字看不到选字框的解决方法...
  9. 方差分析表和回归分析表的那些浆糊糊
  10. win10电脑显示未安装任何音频输出设备问题解决记录