前言
前段时间心血来潮看了下app游戏方面的东西
,对比了下各种技术和市场招聘情况,赶脚cocos2dx在2D游戏方向还算是大有所为,遂找了几个基础教程看看了解了解。并附上一个简单demo作为成果
准备工作
环境搭建倒是重头戏,相关教程也比较多,我直接转个给大家参考吧(安装教程戳这里)。
开始游戏
找了个经典游戏是男人就坚持20秒,相信大家都接触过,游戏逻辑比较简单不外乎控制飞机躲避子弹,这里就山寨它吧
可以看到组成部分只有计时器,子弹和小鸟(为什么选小鸟呢,因为圆形图标做碰撞检测比较简单,本来用飞机的,但是飞机的空白地方不好处理,简单实例就用简单的方法吧)
1、计时器
int time=;
CCLabelTTF* timelb;//文本框
schedule(schedule_selector(manfor20s::timecount), 1.0f);//每秒执行的计时器 //每秒累加
void manfor20s::timecount(float dt)
{
time= time+;
CCString* ns=CCString::createWithFormat("%d", manfor20s::time);
timelb->setString(ns->getCString() );
}
计时器逻辑
2、子弹的生成和碰撞检测
CCArray* listSpirit;//获取页面上所有元素的容器
CCSprite* plane;//小鸟
schedule(schedule_selector(manfor20s::update));//每一帧执行 void manfor20s::update(float dt)
{
CCSprite *pl = plane ;
CCRect targetRect = CCRectMake(
pl->getPosition().x - (pl->getContentSize().width/),
pl->getPosition().y - (pl->getContentSize().height/),
pl->getContentSize().width,
pl->getContentSize().height); CCRect win=CCRectMake(,,visibleSize.width,visibleSize.height);
listSpirit=this->getChildren();//获取所有元素
for (int i=listSpirit->count()-;i>=;i--)
{ CCSprite* it=(CCSprite*)listSpirit->objectAtIndex(i);
if(it->getTag()==)//tag为2则为子弹
{
/*
CCSprite *sp = dynamic_cast<CCSprite*>(it); */
CCRect projectileRect = CCRectMake( it->getPosition().x - (it->getContentSize().width/),
it->getPosition().y - (it->getContentSize().height/),
it->getContentSize().width,
it->getContentSize().height);
if ( ccpDistance(it->getPosition(),plane->getPosition())<) //子弹和小鸟圆心点相距小于15则认为碰撞了
{
CCMessageBox("被击中了","alert");
menuCloseCallback();//关闭
break;
}
if(!win.intersectsRect(projectileRect))//如果子弹超出窗体则删除 {
this->removeChild(it);
}
}
} #pragma region 产生弹道 随机生成各个方向的子弹
if(getRand(,)>)//随机因子
{
//get directer
int di =getRand(,);
CCSprite * pu =CCSprite::create("p.png");
pu->setTag();
CCPoint from;
CCPoint to;
switch(di)
{
case ://up to down
{
from=ccp(getRand(,visibleSize.width),visibleSize.height);
to=ccp(getRand(-visibleSize.width,visibleSize.width*),-);
}
break;
case ://down to up
{
from=ccp(getRand(,visibleSize.width),);
to=ccp(getRand(-visibleSize.width,visibleSize.width*),visibleSize.height+);
}
break;
case ://left to right
{
from=ccp(,getRand(,visibleSize.height));
to=ccp(visibleSize.width+,getRand(-visibleSize.height,visibleSize.height*));
}
break;
case ://right to left
{
from=ccp(visibleSize.width,getRand(,visibleSize.height));
to=ccp(-,getRand(-visibleSize.height,visibleSize.height*));
}
break;
default:break;
}
pu->setPosition(from);
this->addChild(pu);
int distance=cocos2d::ccpDistance(from,to);
CCActionInterval *forward = CCMoveTo::create(distance/,to); //moveto 速度控制
pu->runAction(forward);
}
#pragma endregion
} //random
int manfor20s::getRand(int start,int end)
{
float i = CCRANDOM_0_1()*(end-start+)+start; //get random from start to end
return (int)i;
}
子弹的生成和碰撞检测
3、小鸟的移动
bool manfor20s::ccTouchBegan(CCTouch * touch,CCEvent* event)
{
CCPoint heropos = plane->getPosition();
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
if (location.x > heropos.x - && location.x < heropos.x + && location.y > heropos.y - && location.y < heropos.y + )
{
isControl = true;
deltax = location.x - heropos.x;
deltay = location.y - heropos.y;
}
return true;
} void manfor20s::ccTouchMoved(CCTouch * touch,CCEvent* event)
{
if (isControl)
{
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
float x = location.x - deltax;
float y = location.y - deltay;
plane->setPosition(ccp(x,y));
}
} void manfor20s::ccTouchEnded(CCTouch * touch, CCEvent * event)
{
isControl = false;
}
小鸟的移动
大体逻辑就是这样,第一次做c++项目,分不清:: . ->的概念,幸好项目比较小问题不大,希望有机会能接触高大上一点的项目做做,哈哈,不知道怎么传代码,就吧.h文件和.cpp文件都贴上来吧
#ifndef __manfor20s_SCENE_H__
#define __manfor20s_SCENE_H__ #include "cocos2d.h" class manfor20s:public cocos2d::CCLayer
{ public:
virtual bool init(); // there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene(); // a selector callback
void menuCloseCallback(); // implement the "static node()" method manually
CREATE_FUNC(manfor20s);
void timecount(float dt);
void update(float dt);
int getRand(int start,int end) ;
int time;
bool isControl;
int deltax;
int deltay; //触屏响应重写这三个方法
virtual bool ccTouchBegan(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);//按下
virtual void ccTouchMoved(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);//拖动
virtual void ccTouchEnded(cocos2d::CCTouch* touch, cocos2d::CCEvent* event);//松开
}; #endif
游戏页.h
#include "manfor20s.h"
#include "MainPage.h"
USING_NS_CC;
CCLabelTTF* timelb;
CCSize visibleSize;
CCArray* listSpirit;
CCSprite* plane;
CCScene* manfor20s::scene(){
CCScene *scene = CCScene::create();
manfor20s *layer = manfor20s::create();
scene->addChild(layer);
return scene;
} bool manfor20s::init()
{
if ( !CCLayer::init() )
{
return false;
}
this->setTouchEnabled(true);
CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this,,true);
visibleSize = CCDirector::sharedDirector()->getVisibleSize();
CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();
timelb=CCLabelTTF::create("", "Arial", );
timelb->setPosition(ccp(origin.x+,origin.y +visibleSize.height-));
this->addChild(timelb);
manfor20s::time=; plane=CCSprite::create("bird.png");
plane->setTag();
plane->setPosition(ccp(origin.x+visibleSize.width/,origin.y + visibleSize.height/));
this->addChild(plane); schedule(schedule_selector(manfor20s::update));
schedule(schedule_selector(manfor20s::timecount), 1.0f); return true;
} void manfor20s::update(float dt)
{
CCSprite *pl = plane ;
CCRect targetRect = CCRectMake(
pl->getPosition().x - (pl->getContentSize().width/),
pl->getPosition().y - (pl->getContentSize().height/),
pl->getContentSize().width,
pl->getContentSize().height); CCRect win=CCRectMake(,,visibleSize.width,visibleSize.height);
listSpirit=this->getChildren();
for (int i=listSpirit->count()-;i>=;i--)
{ CCSprite* it=(CCSprite*)listSpirit->objectAtIndex(i);
if(it->getTag()==)
{
/*
CCSprite *sp = dynamic_cast<CCSprite*>(it); */
CCRect projectileRect = CCRectMake( it->getPosition().x - (it->getContentSize().width/),
it->getPosition().y - (it->getContentSize().height/),
it->getContentSize().width,
it->getContentSize().height);
if ( ccpDistance(it->getPosition(),plane->getPosition())<)
{
CCMessageBox("被击中了","alert");
menuCloseCallback();
break;
}
if(!win.intersectsRect(projectileRect))//delete if over the windows
{
this->removeChild(it);
}
}
} #pragma region 产生弹道
if(getRand(,)>)//随机因子
{
//get directer
int di =getRand(,);
CCSprite * pu =CCSprite::create("p.png");
pu->setTag();
CCPoint from;
CCPoint to;
switch(di)
{
case ://up to down
{
from=ccp(getRand(,visibleSize.width),visibleSize.height);
to=ccp(getRand(-visibleSize.width,visibleSize.width*),-);
}
break;
case ://down to up
{
from=ccp(getRand(,visibleSize.width),);
to=ccp(getRand(-visibleSize.width,visibleSize.width*),visibleSize.height+);
}
break;
case ://left to right
{
from=ccp(,getRand(,visibleSize.height));
to=ccp(visibleSize.width+,getRand(-visibleSize.height,visibleSize.height*));
}
break;
case ://right to left
{
from=ccp(visibleSize.width,getRand(,visibleSize.height));
to=ccp(-,getRand(-visibleSize.height,visibleSize.height*));
}
break;
default:break;
}
pu->setPosition(from);
this->addChild(pu);
int distance=cocos2d::ccpDistance(from,to);
CCActionInterval *forward = CCMoveTo::create(distance/,to); //moveto 速度控制
pu->runAction(forward);
}
#pragma endregion
} void manfor20s::timecount(float dt)
{
manfor20s::time= manfor20s::time+;
CCString* ns=CCString::createWithFormat("%d", manfor20s::time);
timelb->setString(ns->getCString() );
} int manfor20s::getRand(int start,int end)
{
float i = CCRANDOM_0_1()*(end-start+)+start; //get random from start to end
return (int)i;
} //close button
void manfor20s::menuCloseCallback()
{
this->removeAllChildren();
this->unscheduleAllSelectors();
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();
pDirector->setOpenGLView(pEGLView);
// turn on display FPS
pDirector->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / );
// create a scene. it's an autorelease object
CCScene *pScene = MainPage::scene(); pDirector->replaceScene(pScene);
} bool manfor20s::ccTouchBegan(CCTouch * touch,CCEvent* event)
{
CCPoint heropos = plane->getPosition();
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
if (location.x > heropos.x - && location.x < heropos.x + && location.y > heropos.y - && location.y < heropos.y + )
{
isControl = true;
deltax = location.x - heropos.x;
deltay = location.y - heropos.y;
}
return true;
} void manfor20s::ccTouchMoved(CCTouch * touch,CCEvent* event)
{
if (isControl)
{
CCPoint location = touch->getLocationInView();
location = CCDirector::sharedDirector()->convertToGL(location);
float x = location.x - deltax;
float y = location.y - deltay;
plane->setPosition(ccp(x,y));
}
} void manfor20s::ccTouchEnded(CCTouch * touch, CCEvent * event)
{
isControl = false;
}
游戏页.cpp
#ifndef __MainPage_SCENE_H__
#define __MainPage_SCENE_H__ #include "cocos2d.h" class MainPage : public cocos2d::CCLayer
{
public:
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init(); // there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::CCScene* scene(); // a selector callback
void menuCloseCallback(CCObject* pSender); // a selector callback
void menustartGame(CCObject* pSender); // implement the "static node()" method manually
CREATE_FUNC(MainPage);
}; #endif // __HELLOWORLD_SCENE_H__
菜单页.h
#include "MainPage.h"
#include "manfor20s.h"
USING_NS_CC; CCScene* MainPage::scene()
{
// 'scene' is an autorelease object
CCScene *scene = CCScene::create(); // 'layer' is an autorelease object
MainPage *layer = MainPage::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 MainPage::init()
{
//////////////////////////////
// 1. super init first
if ( !CCLayer::init() )
{
return false;
}
//获取原始尺寸
CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize(); CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin(); //开始和退出按钮
CCLabelTTF *label1 = CCLabelTTF::create("Start", "Arial", ); // create a exit botton
CCMenuItemLabel *start_game = CCMenuItemLabel::create(label1, this, menu_selector(MainPage::menustartGame) ); CCLabelTTF *label2 = CCLabelTTF::create("Exit", "Arial", ); // create a exit botton
CCMenuItemLabel *exit_game = CCMenuItemLabel::create(label2, this, menu_selector(MainPage::menuCloseCallback) ); start_game->setPosition(ccp((origin.x + visibleSize.width - start_game->getContentSize().width)/ ,
origin.y+visibleSize.height/ + start_game->getContentSize().height/));
exit_game->setPosition(ccp((origin.x + visibleSize.width - exit_game->getContentSize().width)/ ,
origin.y+visibleSize.height/ + exit_game->getContentSize().height/-)); // create menu, it's an autorelease object
CCMenu* pMenu = CCMenu::create(start_game,exit_game, NULL);
pMenu->setPosition(CCPointZero);
this->addChild(pMenu, ); //标题
CCLabelTTF* pLabel = CCLabelTTF::create("can you hold 20 sec?", "Arial", ); // position the label on the center of the screen
pLabel->setPosition(ccp(origin.x + visibleSize.width/,
origin.y + visibleSize.height - pLabel->getContentSize().height)); // add the label as a child to this layer
this->addChild(pLabel, ); //背景图片
CCSprite* pSprite = CCSprite::create("background.jpg"); pSprite->setPosition(ccp(visibleSize.width/ + origin.x, visibleSize.height/ + origin.y)); this->addChild(pSprite, ); return true;
} void MainPage::menuCloseCallback(CCObject* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT) || (CC_TARGET_PLATFORM == CC_PLATFORM_WP8)
CCMessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
#else
CCDirector::sharedDirector()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit();
#endif
#endif
} void MainPage::menustartGame(CCObject* psender)
{
CCDirector* pDirector = CCDirector::sharedDirector();
CCEGLView* pEGLView = CCEGLView::sharedOpenGLView(); pDirector->setOpenGLView(pEGLView); // turn on display FPS
pDirector->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this
pDirector->setAnimationInterval(1.0 / );
// create a scene. it's an autorelease object
CCScene *pScene = manfor20s::scene(); pDirector->replaceScene(pScene);
}
菜单页.cpp
下载代码戳这里