[cocos2d-x]躲蜘蛛游戏设计[进阶]
1.玩家精灵在游戏的最下方。
2.蜘蛛精灵在游戏的最上方,并且从上往下掉落。
3.手动控制玩家精灵。
4.碰撞检测,如果玩家精灵碰到蜘蛛则重玩。
5.音效的设置。
6.Loading界面
7.暂停和开始的设计
效果图:
代码实现:
1.创建默认的HelloWorld项目,屏幕默认的是横屏的,如何设置屏幕为竖屏?
找到RootViewController.mm文件,修改相应的代码即可:
// For ios6, use supportedInterfaceOrientations & shouldAutorotate instead - (NSUInteger) supportedInterfaceOrientations{ #ifdef __IPHONE_6_0 return UIInterfaceOrientationMaskPortrait; #endif }
2.HelloWorldScene.h:
#ifndef __HELLOWORLD_SCENE_H__ #define __HELLOWORLD_SCENE_H__ #include "cocos2d.h" using namespace cocos2d; class HelloWorld : public cocos2d::CCLayer { public: // Method 'init' in cocos2d-x returns bool, instead of 'id' in cocos2d-iphone (an object pointer) virtual bool init(); // there's no 'id' in cpp, so we recommend to return the class instance pointer static cocos2d::CCScene* scene(); // a selector callback //void menuCloseCallback(CCObject* pSender); // preprocessor macro for "static create()" constructor ( node() deprecated ) CREATE_FUNC(HelloWorld); ~HelloWorld(); //计分 int count; CCLabelBMFont * scoreLabel; //玩家自己的精灵 CCSprite*player; //位置 CCPoint playerVelocity; //蜘蛛精灵 CCArray *spiders; //时间间隔 float spiderMoveDuration; //蜘蛛移动的数量 int numSpidersMoved; //初始化蜘蛛 void initSpiders(); //重新布局蜘蛛精灵 void resetSpiders(); //蜘蛛更新 void spidersUpdate(CCTime delta); //蜘蛛移动 void runSpiderMoveSequence(CCSprite * spider); //往下移动 void spiderBelowSceen(void * sender); //碰撞检测 void update(float delta); //触摸控制主角精灵 virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent); virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent); //触摸注册 void registerWithTouchDispatcher(); //showGameOver void showGameOver(const char *str); //重新开始 void resetGame(); //开始按钮 void menuCloseCallback(CCObject* pSender); //返回上一级选择菜单 void returnView(); bool flag = true; void pauseOrStart(); }; #endif // __HELLOWORLD_SCENE_H__
3.HelloWorldScene.cpp:
#include "HelloWorldScene.h" //音乐的类 #include "SimpleAudioEngine.h" #include "Loading.h" using namespace cocos2d; using namespace CocosDenshion; CCScene* HelloWorld::scene() { // 'scene' is an autorelease object CCScene *scene = CCScene::create(); // 'layer' is an autorelease object HelloWorld *layer = HelloWorld::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool HelloWorld::init() { // 1. super init first if ( !CCLayer::init() ) { return false; } CCSize screenSize = CCDirector::sharedDirector()->getWinSize(); CCSprite *background = CCSprite::create("bg.png"); background->setPosition(ccp(screenSize.width/2, screenSize.height/2)); this->addChild(background); count =0; //字体文理贴图 scoreLabel = CCLabelBMFont::create("0", "testBMFont.fnt"); scoreLabel->setPosition(ccp(screenSize.width * 0.5,screenSize.height * 0.5)); this->addChild(scoreLabel); //放大两倍 //scoreLabel->getChildByTag(0)->setScale(2.0); //背景音效 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("blues.mp3", true); //打开加速计 this->setAccelerometerEnabled(true); this->setTouchEnabled(true); //获取自身的精灵 player = CCSprite::create("alien.png"); this->addChild(player, 0,1); float imageHeight = player->getTexture()->getContentSize().height; //将玩家精灵添加到屏幕的下方正* player->setPosition(CCPointMake(screenSize.width/2, imageHeight/2)); //调用加载蜘蛛精灵的方法 this->initSpiders(); //this->scheduleUpdate(); return true; } //初始化蜘蛛 void HelloWorld::initSpiders() { CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite *tempSpider = CCSprite::create("spider.png"); //获取蜘蛛贴图的宽度 float imageWidth = tempSpider->getContentSize().width; //计算一行能显示几个蜘蛛 int numSpiders = size.width / imageWidth; spiders = new CCArray(); //设置一个断言 CCAssert(spiders -> init(), "spiders array is already initialized!"); // spiders = CCArray::createWithCapacity(numSpiders); //数组重复初始化了 for (int i = 0 ; i < numSpiders; i++) { CCSprite *spider = CCSprite::create("spider.png"); this->addChild(spider, 0, 2); spiders->addObject(spider); } //暂停按钮 CCMenuItemImage *pPauseItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::pauseOrStart)); pPauseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) ); CCMenu* pMenu = CCMenu::create(pPauseItem, NULL); pMenu->setPosition( CCPointZero ); // pMenu->alignItemsHorizontally(); this->addChild(pMenu, 1,105); //写一个方法,将蜘蛛移动到其他位置,不然默认的创建的几个蜘蛛精灵就是创建在原点上 this->resetSpiders(); this->scheduleUpdate(); } //重新布局蜘蛛代码 void HelloWorld::resetSpiders() { //分数清0 count = 0; //获取屏幕尺寸 CCSize size = CCDirector::sharedDirector()->getWinSize(); //获取蜘蛛尺寸 CCSprite *tempSpider = (CCSprite *)spiders->lastObject(); CCSize imageSize = tempSpider->getContentSize(); int numSpiders = spiders->count(); for (int i=0; i<numSpiders; i++) { CCSprite *spider = (CCSprite *)spiders->objectAtIndex(i); spider->setPosition(CCPointMake(imageSize.width * i + imageSize.width *0.5f,size.height + imageSize.height)); //将所有的蜘蛛的动作都停止 spider->stopAllActions(); } this->unschedule(schedule_selector(HelloWorld::spidersUpdate)); this->schedule(schedule_selector(HelloWorld::spidersUpdate), 0.6f); //this->schedule(schedule_selector(HelloWorld::spidersUpdate), 0.6f); numSpidersMoved = 0; spiderMoveDuration = 3.0f; //从上到下多长时间运行结束 //this->scheduleUpdate(); } //更新蜘蛛 void HelloWorld::spidersUpdate(cocos2d::CCTime delta) { for (int i=0; i < spiders->count(); i++) { int randomSpiderIndex = CCRANDOM_0_1()*spiders->count(); CCSprite * spider = (CCSprite *)spiders->objectAtIndex(randomSpiderIndex); //注意:这个方法表示当前对象是否有动作正在执行 if (spider->numberOfRunningActions() == 0) { if (i > 0) { CCLog("Dropping a Spider after %d retries.",i); } this->runSpiderMoveSequence(spider); break; } } } //蜘蛛移动 void HelloWorld::runSpiderMoveSequence(cocos2d::CCSprite *spider) { numSpidersMoved++; //控制难度 if (numSpidersMoved %8 == 0 && spiderMoveDuration > 2.0f) { spiderMoveDuration -= 0.1f; } CCPoint belowScreenPosition = CCPointMake(spider->getPosition().x, -(spider->getTexture()->getContentSize().height)); CCMoveTo *move = CCMoveTo::create(spiderMoveDuration, belowScreenPosition); CCCallFuncN *call = CCCallFuncN::create(this,callfuncN_selector(HelloWorld::spiderBelowSceen)); CCSequence *sequence = CCSequence::create(move,call,NULL); spider->runAction(sequence); } //作为回调方法,当蜘蛛运动到屏幕下方的时候,从新返回到顶部 void HelloWorld::spiderBelowSceen(void *sender) { //断言 //CCAssert(dynamic_cast<CCSprite *>(this->getChildByTag(3))!=NULL, "非法类型"); CCSprite * spider = (CCSprite*)sender; CCPoint pos = spider->getPosition(); CCSize size = CCDirector::sharedDirector()->getWinSize(); pos.y = size.height+spider->getTexture()->getContentSize().height; spider->setPosition(pos); } HelloWorld::~HelloWorld() { spiders->release(); CCLog("资源已经回收"); } //参数是固定的是每隔一桢间隔的时间的意思,也就是update函数每针都会调用 void HelloWorld::update(float delta) { float playerImageSize = player->getContentSize().width; CCSprite *sp = (CCSprite *)spiders->lastObject(); float spiderImageSize = sp->getContentSize().width; float playerCollisionRadius = playerImageSize * 0.4f; float spiderCollisionRadius = spiderImageSize * 0.4f; float maxCollisionDistance = playerCollisionRadius + spiderCollisionRadius; int numSpiders = spiders->count(); //显示分数 scoreLabel->setString(CCString::createWithFormat("%d",count)->getCString()); for (int i = 0; i< numSpiders; i++) { CCSprite * spider = (CCSprite *)spiders->objectAtIndex(i); if (spider->numberOfRunningActions()==0) { continue; } //ccpDistance计算两点之间的距离函数 float actualDistance = ccpDistance(player->getPosition(), spider->getPosition()); if (actualDistance< maxCollisionDistance) { //主角精灵死亡音效 SimpleAudioEngine::sharedEngine()->playEffect("alien-sfx.caf"); //重新加载 this->resetSpiders(); const char *str = "GameOver!"; this->showGameOver(str); //CCDirector::sharedDirector()->stopAnimation(); CCSprite *sprider; //让屏幕停止 除了GameOver字体 this->unschedule(schedule_selector(HelloWorld::spidersUpdate)); this->unscheduleUpdate(); break; } } count++; } //单点触摸 bool HelloWorld:: ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { return true; } //触摸移动 void HelloWorld:: ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { player->setPosition(pTouch->getLocation()); } void HelloWorld:: ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent) { //this->resetGame(); //CCDirector::sharedDirector()->startAnimation(); } //触摸注册事件 void HelloWorld:: registerWithTouchDispatcher() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true); } //显示游戏结束 void HelloWorld::showGameOver(const char *str) { //清除暂停按钮 this->removeChildByTag(105, true); CCSize screenSize = CCDirector::sharedDirector()->getWinSize(); CCLabelTTF * gameOver = CCLabelTTF::create(str, "Marker Felt", 60); gameOver->setPosition(ccp(screenSize.width / 2, screenSize.height / 3)); this->addChild(gameOver,100,100); // game over label runs 3 different actions at the same time to create the combined effect // 1) 颜色渐变 CCTintTo * tint1 = CCTintTo::create(2, 255, 0, 0); CCTintTo * tint2 = CCTintTo::create(2, 255, 255, 0); CCTintTo * tint3 = CCTintTo::create(2, 0, 255, 255); CCTintTo * tint4 = CCTintTo::create(2, 0, 0, 255); CCTintTo * tint5 = CCTintTo::create(2, 255, 0, 255); CCTintTo * tint6 = CCTintTo::create(2, 0, 255, 0); CCSequence* tintSequence = CCSequence::create(tint1,tint2,tint3,tint4,tint5,tint6,NULL); CCRepeatForever* repeatTint = CCRepeatForever::create(tintSequence); gameOver->runAction(repeatTint); // 2) 缓缓旋转 CCRotateTo* rotate1 = CCRotateTo::create(2, 3); CCEaseBounceInOut*bounce1 = CCEaseBounceInOut::create(rotate1); CCRotateTo* rotate2 = CCRotateTo::create(2, -3); CCEaseBounceInOut*bounce2 = CCEaseBounceInOut::create(rotate2); CCSequence* rotateSequence = CCSequence::create(bounce1,bounce2,NULL); CCRepeatForever* repeateBounce = CCRepeatForever::create(rotateSequence); gameOver->runAction(repeateBounce); // 3) jumping CCJumpBy* jump = CCJumpBy::create(3, CCPointZero, screenSize.height/3, 1); CCRepeatForever* repeatJump = CCRepeatForever::create(jump); gameOver->runAction(repeatJump); //提醒继续游戏 CCLabelTTF*touchLabel = CCLabelTTF::create("请按下面按钮(继续挑战/返回上级)", "Arial", 20 ); touchLabel->setPosition(CCPointMake(screenSize.width/2,screenSize.height/2 + 180)); touchLabel->setColor(ccRED); this->addChild(touchLabel,100,101); CCMenuItemImage *pStartItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::menuCloseCallback) ); pStartItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width/2 - 70, CCDirector::sharedDirector()->getWinSize().height / 2 +120) ); CCMenuItemImage *pReturnItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::returnView) ); pReturnItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width/2 + 70, CCDirector::sharedDirector()->getWinSize().height / 2 + 120) ); // create menu, it's an autorelease object CCMenu* pMenu = CCMenu::create(pStartItem,pReturnItem, NULL); pMenu->setPosition( CCPointZero ); // pMenu->alignItemsHorizontally(); this->addChild(pMenu, 1,102); } //重新开始 void HelloWorld::menuCloseCallback(CCObject* pSender) { //添加暂停按钮 CCMenuItemImage *pPauseItem = CCMenuItemImage::create( "CloseNormal.png", "CloseSelected.png", this, menu_selector(HelloWorld::pauseOrStart)); pPauseItem->setPosition( ccp(CCDirector::sharedDirector()->getWinSize().width - 20, 20) ); CCMenu* pMenu = CCMenu::create(pPauseItem, NULL); pMenu->setPosition( CCPointZero ); // pMenu->alignItemsHorizontally(); this->addChild(pMenu, 1,105); this->HelloWorld::resetGame(); this->scheduleUpdate(); this->schedule(schedule_selector(HelloWorld::spidersUpdate),0.6f); } void HelloWorld::resetGame() { this->removeChildByTag(100, true); this->removeChildByTag(101, true); this->removeChildByTag(102, true); //重新开始排列蜘蛛精灵 this->resetSpiders(); // this->scheduleUpdate(); } //返回上级 void HelloWorld::returnView() { CCTransitionFade * secondScene = CCTransitionFade::create(0.5f, Loading::scene(), ccBLACK); CCDirector::sharedDirector()->replaceScene(secondScene); } //暂停或者开始 void HelloWorld::pauseOrStart() { if (flag) { CCDirector::sharedDirector()->stopAnimation(); flag = false; } else { CCDirector::sharedDirector()->startAnimation(); flag = true; } }
4.导航页面的设计
4.1 Loading.h:
// // Loading.h // GameDemo // // Created by 丁小未 on 13-9-6. // // #ifndef __GameDemo__Loading__ #define __GameDemo__Loading__ #include <iostream> #include "cocos2d.h" using namespace cocos2d; class Loading : public cocos2d::CCLayer { public: virtual bool init(); static cocos2d::CCScene* scene(); virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent); //void makeTransition(); void convertView(); virtual void registerWithTouchDispatcher(void); virtual void onEnter(); virtual void onExit(); //游戏介绍 void gameIntroduce(); //游戏设置 void gameSetting(); //游戏开始 void gameBegging(); CREATE_FUNC(Loading); }; #endif /* defined(__GameDemo__Loading__) */
4.2Loading.m:
#include "Loading.h" #include "SimpleAudioEngine.h" #include "HelloWorldScene.h" using namespace cocos2d; using namespace CocosDenshion; CCScene* Loading::scene() { CCScene *scene = CCScene::create(); Loading *layer = Loading::create(); scene->addChild(layer); return scene; } bool Loading::init() { if ( !CCLayer::init() ) { return false; } this->setTouchEnabled(true); return true; } void Loading::gameIntroduce() { CCLog("introduce"); } void Loading::gameSetting() { CCLog("gamesetting"); } void Loading::gameBegging() { this->Loading::convertView(); } void Loading::onEnter() { CCLayer::onEnter(); CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite *background = CCSprite::create("bg.png"); background->setPosition(ccp(size.width/2, size.height/2)); this->addChild(background); CCLabelTTF *label = CCLabelTTF::create("躲避蜘蛛游戏", "Marker Felt", 48); label->setPosition(ccp(size.width/2, size.height - 100)); label->setColor(ccGREEN); this->addChild(label); CCMenuItemImage * button = CCMenuItemImage::create("play.png", "play.png", this, menu_selector(Loading::gameBegging)); button->setPosition(size.width/2,size.height/2-80); CCLabelTTF *labell = CCLabelTTF::create("游戏概况", "Marker Felt", 34); CCMenuItemLabel *mlabel = CCMenuItemLabel::create(labell,this,menu_selector(Loading::gameIntroduce)); mlabel->setPosition(CCPointMake(size.width/2, size.height/2 + 75)); mlabel->setColor(ccBLUE); CCLabelTTF *labell1 = CCLabelTTF::create("游戏设置", "Marker Felt", 34); CCMenuItemLabel *mlabel1 = CCMenuItemLabel::create(labell1,this,menu_selector(Loading::gameSetting)); mlabel1->setPosition(CCPointMake(size.width/2, size.height/2 + 15)); mlabel1->setColor(ccBLUE); CCMenu *menu = CCMenu::create(button,mlabel,mlabel1,NULL); menu->setPosition(CCPointZero); this->addChild(menu); } void Loading::onExit() { CCLayer::onExit(); CCLog("结束"); } void Loading::registerWithTouchDispatcher() { CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 0, true); } bool Loading::ccTouchBegan(cocos2d::CCTouch *pTouch, cocos2d::CCEvent *pEvent) { CCPoint point = pTouch->getLocation(); CCLog("%f,%f",point.x,point.y); return true; } void Loading::convertView() { CCTransitionFade * secondScene = CCTransitionFade::create(0.5f, HelloWorld::scene(), ccBLACK); CCDirector::sharedDirector()->replaceScene(secondScene); }
收获:
1.获取图片的高度
float imageHeight =player->getTexture()->getContentSize().height;
2.断言的设置
CCAssert(dynamic_cast<CCSprite *>(this->getChildByTag(3))!=NULL, "非法类型");
3.设置屏幕刷新的频率
找到AppController.mm文件,找到- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions这个方法
//设置刷新频率
cocos2d::CCApplication::sharedApplication()->setAnimationInterval(0.3);
就能使得屏幕刷新变慢,然后方便调试
源码下载(猛戳)cocos2d介绍[转]:
一、游戏介绍
这个例子是一个叫做Doodle Drop的游戏,是一个重力感应类游戏。玩家操纵角色来躲避从空中坠落的障碍物。游戏界面如下:
二、设置主场景
1、新建Cocos2d Application,工程名DoodleDrop。
2、游戏主场景。选File -> new file,选择User Templates -> Cocos2d.0.99.x -> CCNode.class。Subclass Of选择CCLayer。文件名选GameScene。
3、在头文件中声明静态方法 +(id) scene;
4、.m文件
#import "GameScene.h"
@implementation GameScene
+(id) scene {
CCScene *scene = [CCScene node];
CCLayer* layer = [GameScene node];
[scene addChild:layer];
return scene;
}
-(id) init {
if ((self = [super init])) {
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self); return self;
}
}
-(void) dealloc {
// never forget to call [super dealloc] [super dealloc];
CCLOG(@"%@: %@", NSStringFromSelector(_cmd), self);
[super dealloc];
}
@end
5、删除HelloWorldScene.h和HelloWorldScene.m文件。
6、修改DoodleDropAppDelegate.m,将其中的主场景启动代码修改为GameScene:
[[CCDirector sharedDirector] runWithScene: [GameScene scene]];
三、游戏角色
1 、把玩家角色图片 alien.png 添加到工程。添加时,选中“ Copy items ”,同时勾选“ add to targets”中的“ DoodleDrop ”选项。
2 、在游戏主场景 (GameScene.h) 增加变量声明:
CCSprite* player;
3、在游戏主场景(GameScene.m)的init方法中加入下列代码:
self.isAccelerometerEnabled = YES;
player = [CCSprite spriteWithFile:@"alien.png"];
[self addChild:player z:0 tag:1];
CGSize screenSize = [[CCDirector sharedDirector] winSize];
float imageHeight = [player texture].contentSize.height;
player.position = CGPointMake(screenSize.width / 2, imageHeight / 2);
这样,玩家角色就被放到屏幕底部正中的位置上。注意,player变量未retain。因为addChild会自动retain。
[player texture].contentSize.height返回的是渲染图的content size。渲染对象(玩家角色图片alient.png)有两个尺寸:content size和texture size。前者是图片的实际尺寸,后者是渲染尺寸——iPhone规定渲染尺寸只能是2的n次方。比如图片实际尺寸100*100,那么渲染尺寸则是128*128,因为最接近100的2的n次方为128。
四、使用加速器
1、为了响应加速器事件,你必须在init方法中加上:
self.isAccelerometerEnabled = YES;
同时实现accelerometer方法:
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration{
CGPoint pos = player.position;
pos.x += acceleration.x * 10;
player.position = pos;
}
跟java和c不同。你不能对 player.position.x进行赋值。这种赋值在
c语言中是可以的,但oc中不行。因为player.position实际上是调用[player position],这个方法返回一个临时的CGPoint变量。当你想对这个临时的CGPoint的x进行赋值后,这个变量会被被抛弃,所以你的赋值没有任何作用。所以你需要用一个新的CGPoint变量,修改其x值,然后再把这个CGPoint赋值给player.position(即调用[player setPosition:])。如果你是来自java和c++的程序员,在oc中需要留心这个“不幸的”问题并尽可能的修改编程习惯。
2、运行测试
模拟器不支持重力感应,请在物理设备上运行代码。
五、玩家控制
现住发现用加速器控制有些不灵?反应迟钝,移动也不流畅?为此,我们需要增加一些代码。
首先需要增加变量声明:
CGPoint playerVelocity;
为了便于今后的扩展(假设有一天我们会想上下移动角色),这是一个CGPoint类型,而不是一个float。
然后修改加速器方法:
-(void) accelerometer:(UIAccelerometer *)accelerometer
didAccelerate:(UIAcceleration *)acceleration
{
// 减速度系数(值越小=转向越快)
float deceleration = 0.4f;
// 加速度系数 (值越大 = 越敏感)
float sensitivity = 6.0f;
// 最大速度
float maxVelocity = 100;
// 根据加速度计算当前速度
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
// 限制最大速度为 ±maxVelocity之间
directions if (playerVelocity.x > maxVelocity) {
playerVelocity.x = maxVelocity;
} else if (playerVelocity.x < - maxVelocity) {
playerVelocity.x = - maxVelocity;
}
}
现在,玩家速度由一个一次线性方程决定:
V= V
本文转蓬莱仙羽51CTO博客,原文链接:http://blog.51cto.com/dingxiaowei/1366389,如需转载请自行联系原作者
上一篇: Spark读写XML文件及注意事项
下一篇: 帝国CMS列表模板使用php