本来打算分多个模块实现的,后来想想看cocos2d一个多月,还是先学会走路,等走稳了再学跑步。
游戏的主要内容是:
- 显示Logo画面,并模拟了一个资源加载的进度条;
- “资源加载”完成后会进行场景切换,切换到主场景;
- 主场景的下方有宇智波鼬, 上方是几只九尾狐,宇智波鼬通过发射手里剑攻击敌人。
代码结构如下:
LoadingScene是Logo显示及“资源加载”场景
GameScene是游戏的主场景,主要实现了背景的无限滚动
InputLayer是用户输入层,玩家通过虚拟摇杆控制游戏,但这次的游戏逻辑也实现在了这里,这次没加入碰撞检测,可以看到手里剑和敌人擦肩进过,下次加入新功能后会重构代码结构。
游戏效果如下:
http://www.56.com/u49/v_OTE4NTUxNDI.html
代码下载地址:
http://vdisk.weibo.com/s/Cjiy3/1369105760
LoadingScene的代码可以参考我以前写的关于进度条的文章,GameScene可参考背景的无限滚动。主要贴一下InputLayer的代码:
InputLayer.h
#include "cocos2d.h" typedef enum { HudLayerTag = 2, GameLayerTag =1, }GameLayersTags; using namespace cocos2d; class InputLayer : public cocos2d::CCLayer { public: InputLayer(); //构造函数声明 ~InputLayer(); //析构函数声明 CREATE_FUNC(InputLayer); //类似于cocos2d中的node方法,返回一个autorelease对象 virtual bool init(); //本类对象初始化 void InitJoystick(); //初始化摇杆 void InitHero(); //初始化主角精灵 //void InitBullet(); //初始化子弹 void InitFox(); //初始化敌人-9尾狐 void update(float dt); //定时器 void Shootupdate(float dt); //发射子弹定时器 //主角精灵发射子弹 void shootBulletFromHero(CCSprite *bullet, cocos2d::CCPoint point); void menuCloseCallback(CCObject* pSender); //退出游戏按钮 //触摸事件处理 virtual void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent); virtual void ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent); virtual void ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent); float heronsformula(float x1, float y1, float x2, float y2, float x3, float y3); bool triangleContainPoint(float x1, float y1, float x2, float y2, float x3, float y3, float px, float py); void setPlayerPosition(cocos2d::CCPoint position); //设置玩家位置 CC_SYNTHESIZE(cocos2d::CCSprite*, _player, Player); //CC_SYNTHESIZE(); private: void Moving(float dt); cocos2d::CCSprite *joystick; cocos2d::CCSprite *joystick1; cocos2d::CCSize size; //cocos2d::CCSpriteBatchNode *_spritebatchnode; cocos2d::CCPoint velocity; cocos2d::CCSprite *bullet; cocos2d::CCPoint O; //中心点O float R; //大圆半径 //精灵移动的速度分量值 float speedX; float speedY; //是否移动的标志 bool IsMoving; CCMotionStreak* _strike; //主角精灵的CCMotionStreak变量 CCMotionStreak* _bulletstrike; //手里剑的CCMotionStreak变量 };
InputLayer.cpp:
#include "InputLayer.h" InputLayer::InputLayer() { //初始化需要的变量 IsMoving = false; speedX = speedY = 0; size = CCDirector::sharedDirector()->getWinSize(); } InputLayer::~InputLayer() { } bool InputLayer::init() { bool bRet = false; do { //先初始化父类,如果失败则break循环 CC_BREAK_IF(! CCLayer::init()); //创建一个关闭按钮菜单置于屏幕右下角 CCMenuItemLabel *txtmenItem = CCMenuItemLabel::create(CCLabelTTF::create("EXIT", "Arial", 20), this, menu_selector(InputLayer::menuCloseCallback)); CC_BREAK_IF(! txtmenItem); txtmenItem->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width - txtmenItem->getContentSize().width/2, 20)); CCMenu* pMenu = CCMenu::create(txtmenItem, NULL); pMenu->setPosition(CCPointZero); CC_BREAK_IF(! pMenu); // Add the menu to HelloWorld layer as a child layer. this->addChild(pMenu, 10); this->InitHero(); //初始化精灵 this->setTouchEnabled(TRUE); //打开触摸事件处理 this->InitJoystick(); //初始化摇杆 //this->InitBullet(); //初始化子弹 this->InitFox(); //初始化敌人-9尾狐 //每帧要执行的函数 this->schedule(schedule_selector(InputLayer::Moving)); this->schedule(schedule_selector(InputLayer::Shootupdate)); bRet = true; }while(0); return bRet; } void InputLayer::menuCloseCallback(CCObject* pSender) { CCDirector::sharedDirector()->end(); } void InputLayer::InitJoystick() { //创建摇杆下面部分 joystick1 = CCSprite::create("joystick1.png"); //设置透明度,锚点,位置 joystick1->setOpacity(150); joystick1->setAnchorPoint(ccp(0, 0)); joystick1->setPosition(ccp(0, 0)); joystick1->setColor(ccGREEN); //大圆半径 R=joystick1->getContentSize().width/2; //中心点 O = ccp(R, R); //添加进布景 this->addChild(joystick1, 3); //创建摇杆上面圆圈部分 joystick = CCSprite::create("joystick2.png"); //设置位置为摇杆中心点并添加进布景 joystick->setPosition(ccp(O.x, O.y)); joystick->setColor(ccRED); joystick->setScale(0.5f); this->addChild(joystick, 4); } void InputLayer::InitHero() { CCSize size = CCDirector::sharedDirector()->getWinSize(); this->setPlayer(CCSprite::create("hartnett.jpg")); _player->setScale(0.3f); float picsize = _player->getContentSize().width * 0.3f; _strike = CCMotionStreak::create(0.5f, picsize, picsize, ccWHITE, "hartnett.jpg"); this->addChild(_strike); CCSize spSize = _player->getContentSize(); _player->setPosition(ccp(size.width/2, spSize.height * 0.5f * 0.3f)); this->addChild(_player); } void InputLayer::Moving(float dt) { if (IsMoving && (speedX != 0 || speedY != 0)) { //精灵移动 CCPoint position = ccp(_player->getPosition().x + speedX * 3, _player->getPosition().y + speedY * 3); CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSize spSize = _player->getContentSize(); CCRect rect = CCRectMake(spSize.width * 0.5f * 0.3f, spSize.height * 0.5f * 0.3f, size.width - spSize.width * 0.5f * 0.3f * 2, size.height - spSize.height * 0.5f * 0.3f * 2); //判断触摸点是否在屏幕内 if(rect.containsPoint(position)) { _player->setPosition(position); _strike->setPosition(position); } } } float InputLayer::heronsformula(float x1, float y1, float x2, float y2, float x3, float y3) { //求边长a float a = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2)); //求边长b float b = sqrt(pow(x2 - x3, 2) + pow(y2 - y3, 2)); //求边长c float c = sqrt(pow(x3 - x1, 2) + pow(y3 - y1, 2)); //求半周长s float s = (a + b + c) / 2; //根据海伦公式返回三角形面积 return sqrt(s * (s - a) * (s - b) * (s - c)); } //判断三个新三角形面积和是否等于原先三角形面积的函数的实现 bool InputLayer::triangleContainPoint(float x1, float y1, float x2, float y2, float x3, float y3, float px, float py) { //求S1的面积 float s1=heronsformula(x1, y1, x2, y2, px, py); //求S2的面积 float s2=heronsformula(x2, y2, x3, y3, px, py); //求S3的面积 float s3=heronsformula(x3, y3, x1, y1, px, py); //求S的面积 float s=heronsformula(x1, y1, x2, y2, x3, y3); //返回S是否等于S1,S2,S3的和 return abs(s - (s1 + s2 + s3)) < 0.001f; } void InputLayer::ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent) { CCTouch *touch = (CCTouch*)pTouches->anyObject(); CCPoint location = touch->getLocation(); CCRect rect = joystick->boundingBox(); if (rect.containsPoint(location)) { IsMoving = true; } } void InputLayer::ccTouchesMoved(CCSet *pTouches, CCEvent *pEvent) { CCTouch *touch = (CCTouch*)pTouches->anyObject(); CCPoint location = touch->getLocation(); //判断触摸滑动点是否在摇杆范围内 bool inRange = pow(O.x - location.x, 2) + pow(O.y - location.y, 2) < pow(R, 2); if (IsMoving && inRange) { CCPoint position=_player->getPosition(); joystick->setPosition(location); float r = R * 2 / 6; float d = R * 2 / 3; //上,区域2或5 if(triangleContainPoint(O.x, O.y, O.x - r, O.y + r, O.x +r, O.y + r, location.x, location.y) || CCRectMake(O.x - r, O.y + r, d, d).containsPoint(location)) { speedX = 0; speedY = 1; } //下,区域6或11 else if (triangleContainPoint(O.x, O.y, O.x - r, O.y - r, O.x + r, O.y - r, location.x, location.y) || CCRectMake(O.x - r, O.y - r - d, d, d).containsPoint(location)) { speedX = 0; speedY = -1; } //左,区域4或7 else if (triangleContainPoint(O.x, O.y, O.x - r, O.y + r, O.x - r, O.y - r, location.x, location.y) || CCRectMake(O.x - r - d, O.y - r, d, d).containsPoint(location)) { speedX = -1; speedY = 0; } //右,区域9或8 else if (triangleContainPoint(O.x, O.y, O.x + r, O.y + r, O.x + r, O.y - r, location.x, location.y) || CCRectMake(O.x + r, O.y - r, d, d).containsPoint(location)) { speedX = 1; speedY = 0; } //右上,区域3 else if (location.x - (O.x + r) > 0 && location.y - (O.y + r) > 0) { speedX = 0.7f; speedY = 0.7f; } //左上,区域1 else if (location.x - (O.x - r) < 0 && location.y - (O.y + r) > 0) { speedX =- 0.7f; speedY = 0.7f; } //左下,区域10 else if (location.x - (O.x - r) < 0 && location.y - (O.y - r) < 0) { speedX = -0.7f; speedY = -0.7f; } //右下,区域12 else if (location.x - (O.x + r) > 0 && location.y - (O.y - r) < 0) { speedX = 0.7f; speedY = -0.7f; } } } void InputLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) { IsMoving = false; joystick->setPosition(O); speedX = speedY = 0; } /* void InputLayer::InitBullet() { _spritebatchnode = CCSpriteBatchNode::create("bullet.png"); _spritebatchnode->setPosition(ccp(size.width, size.height/2)); this->addChild(_spritebatchnode, 12); for (int i = 0; i < 200; i++) { CCSprite *bullet = CCSprite::create("bullet.png"); bullet->setPosition(ccp(-50, -50)); //置于屏幕外面 bullet->setScale(0.3f); _spritebatchnode->addChild(bullet); } } */ void InputLayer::InitFox() { CCSprite *tmpfox = CCSprite::create("fox.png"); CCSize foxsize = tmpfox->getContentSize(); //tmpfox->setPosition(ccp(size.width/2, size.height/2)); //tmpfox->setScale(0.3f); //this->addChild(tmpfox); //CCLOG("Fox num %d", (int)(size.width / foxsize.width / 0.3f)); int foxnum = (int)(size.width / foxsize.width / 0.3f); for (int i = 0; i < foxnum; i++) { CCSprite *fox = CCSprite::create("fox.png"); fox->setScale(0.3f); fox->setPosition(ccp(foxsize.width * 0.3f * 0.5f + i * foxsize.width * 0.3f, size.height - foxsize.height * 0.5f * 0.3f)); this->addChild(fox); } } void InputLayer::shootBulletFromHero(CCSprite *bullet, cocos2d::CCPoint point) { float spread = (CCRANDOM_0_1() + 12.5f) * 0.5f; velocity = ccp(0, spread); bullet->setPosition(ccp(point.x, point.y + this->getPlayer()->getContentSize().height * 0.5f * 0.3f)); bullet->setVisible(true); CCRotateBy* rotate = CCRotateBy::actionWithDuration(1, 360 * 5); bullet->runAction(rotate); this->scheduleUpdate(); } void InputLayer::update(float dt) { bullet->setPosition(ccpAdd(bullet->getPosition(), velocity)); _bulletstrike->setPosition(ccpAdd(bullet->getPosition(), velocity)); if (bullet->getPosition().y > size.height) { bullet->setVisible(false); this->unscheduleAllSelectors(); this->schedule(schedule_selector(InputLayer::Moving)); this->schedule(schedule_selector(InputLayer::Shootupdate)); } } void InputLayer::Shootupdate(float dt) { this->unschedule(schedule_selector(InputLayer::Shootupdate)); bullet = CCSprite::create("bullet.png"); bullet->setPosition(ccp(-50, -50)); //置于屏幕外面 bullet->setScale(0.3f); this->addChild(bullet); float picsize = bullet->getContentSize().width * 0.5f; _bulletstrike = CCMotionStreak::create(0.5f, picsize, picsize, ccRED, "bullet.png"); this->addChild(_bulletstrike); this->shootBulletFromHero(bullet, this->getPlayer()->getPosition()); }