五、射击子弹
首先,我们先让这游戏里唯一的图层可以支持触摸。添加下面一行到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 voidHelloWorld::ccTouchesEnded(NSSettouches, UIEventevent) { //Choose one of the touches to work with CCTouchtouch=(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(); CCSpriteprojectile=CCSprite::spriteWithFile("Projectile.png", CGRectMake(0,0,20,20)); projectile->setPosition( ccp(20, winSize.height/2) ); //Determinie offset of location to projectile intoffX=location.x-projectile->getPosition().x; intoffY=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 intrealX=winSize.width+(projectile->getContentSize().width/2); floatratio=(float)offY/(float)offX; intrealY=(realXratio)+projectile->getPosition().y; CGPoint realDest=ccp(realX, realY); //Determine the length of how far we're shooting intoffRealX=realX-projectile->getPosition().x; intoffRealY=realY-projectile->getPosition().y; floatlength=sqrtf((offRealXoffRealX)+(offRealYoffRealY)); floatvelocity=480/1;//480pixels/1sec floatrealMoveDuration=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 UITouchtouch=[touches anyObject]; CGPoint location=[touch locationInView:[touch view]]; location=[[CCDirector sharedDirector]convertToGL:location]; //Set up initial location of projectile CGSize winSize=[[CCDirector sharedDirector] winSize]; CCSpriteprojectile=[CCSprite spriteWithFile:@"Projectile.png" rect:CGRectMake(0,0,20,20)]; projectile.position=ccp(20, winSize.height/2); //Determine offset of location to projectile intoffX=location.x-projectile.position.x; intoffY=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 intrealX=winSize.width+(projectile.contentSize.width/2); floatratio=(float) offY/(float) offX; intrealY=(realXratio)+projectile.position.y; CGPoint realDest=ccp(realX, realY); //Determine the length of how far we're shooting intoffRealX=realX-projectile.position.x; intoffRealY=realY-projectile.position.y; floatlength=sqrtf((offRealXoffRealX)+(offRealY*offRealY)); floatvelocity=480/1;//480pixels/1sec floatrealMoveDuration=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::NSMutableArray |
//objc with cocos2d-iphone NSMutableArray*_targets; NSMutableArray*_projectiles; |
在这里,cocos2d-x模拟iOS的SDK实现了NSMutableArray,里面只能放NSObject及其子类。但不同的是,你必须告诉他里面要放的是哪种具体类型。
然后在init方法中初始化这两个数组
//cpp with cocos2d-x //Initialize arrays _targets=newNSMutableArray _projectiles=newNSMutableArray |
//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 voidHelloWorld::spriteMoveFinished(CCNode*sender) { CCSprite*sprite=(CCSprite*)sender; this->removeChild(sprite,true); if(sprite->getTag()==1)//target { _targets->removeObject(sprite); } elseif(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]; } elseif(sprite.tag==2)//projectile { [_projectiles removeObject:sprite]; } } |
编译并运行项目以确保一切正常。此时还看不出什么明显不同,但我们可以利用前面加的tag标记来实现碰撞检测
现在往class HelloWorld里添加一个update方法,计算碰撞,并让碰撞了的飞镖和小杂兵同时从屏幕消失
//cpp with cocos2d-x voidHelloWorld::update(ccTime dt) { NSMutableArray newNSMutableArray NSMutableArray 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 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*projectilein_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*targetin_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*targetintargetsToDelete) { [_targets removeObject:target]; [self removeChild:target cleanup:YES]; } if(targetsToDelete.count>0) { [projectilesToDelete addObject:projectile]; } [targetsToDelete release]; } for(CCSprite*projectileinprojectilesToDelete) { [_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的提示界面。
著作权声明:本文由http://www.walzer.cn/原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!
原文链接: https://www.cnblogs.com/walzer/archive/2010/10/11/1848106.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/16007
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!