Cocos2dx微信打飞机体感游戏
演示视频地址:点击打开链接 (注 : 视频中两次使用炸弹,没有很好的感应,因为阈值设定有点问题,已改)
游戏的源码也上传到了 csdn 50下载积分 , 但同时也上传到了Github,来个star吧,免费下载:
https://github.com/tanlichun211/SomaticGame-WeChat_PlanWars
1.打飞机添加结束层 √
2.道具双排子弹 √(为了保证游戏趣味性,放50颗子弹后恢复单排子弹)
3.各类飞机的添加 √
4.数据本地化。历史最高成绩的获取 (保存为.xml文件)√
5.随着分数越高,速度越快-----设置参数改变定时器时间(单位时间产生的敌人会越多)和移动一次屏幕距离的时间即可。√
5.体感游戏实现 (一周时间,技术难点较多,主要创新点)√
这里提供一个kinectV2控制鼠标的C++版本程序,同时包含Chengaotan的C#版本程序供参考,Kinect V2 能实现手势识别,石头,箭头和布,因此可以控制鼠标响应不同的点击事件,网上有个人写的鼠标控制,抖动太厉害,我这个还不错,根据chenggaotan C# 程序改写 C++版本 vs2013 戳我打开KinectV2控制鼠标程序。
先讲讲老师们的层次设计,将. 背景 飞机子弹 小敌机 中敌机 大敌机 Food(炸弹) 分门别类的进行分层。
主要的三个场景: start 、 main 、 over
Start 场景:
看图片,决定屏幕大小,这里在AppDelegate中设计为
pEGLView->setDesignResolutionSize(480, 800, kResolutionExactFit);
然后预加载一些资源 声音, 图片缓存。在处理资源时候,通常将一类,放在一起。开始头文件如下,接下来只提供cpp文件,因为头文件大同小异。
#ifndef __LayerGameStart_H__ #define __LayerGameStart_H__ #include "cocos2d.h" USING_NS_CC; class LayerGameStart :public CCLayer { public: static CCScene * scene(); CREATE_FUNC(LayerGameStart); bool init(); void addStartGamePicture();//预加载游戏背景图片 void addPreLoadMusic(); //预加载音乐 void toMainGameCallback(); //被回调的 }; #endifcpp文件也比较简单
#include "LayerGameStart.h" #include "AppMacros.h" #include "LayerGameMain.h" #include "SimpleAudioEngine.h" using namespace CocosDenshion; //声音的外部库 #define loadMusic() CocosDenshion::SimpleAudioEngine::sharedEngine() CCScene * LayerGameStart::scene() { CCScene * scene = CCScene::create(); LayerGameStart * layer = LayerGameStart::create(); scene->addChild(layer); return scene; } bool LayerGameStart::init() { CCLayer::init(); addPreLoadMusic(); //预加载音乐 addStartGamePicture();//预加载图片 return true; } void LayerGameStart::addStartGamePicture() { // 设置安卓返回键 setKeypadEnabled(true); //加载全局图片信息 CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("ui/shoot_background.plist"); CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("ui/shoot.plist"); //加载当前gamestart页面所需要的图片,动画 CCSprite * background = CCSprite::createWithSpriteFrameName("background.png"); background->setAnchorPoint(ccp(0, 0)); background->setPosition(ccp(0, 0)); addChild(background); CCSprite *copyright = CCSprite::createWithSpriteFrameName("shoot_copyright.png"); copyright->setAnchorPoint(ccp(0.5, 0)); copyright->setPosition(ccp(winSize.width / 2, winSize.height / 2)); addChild(copyright); CCSprite *loading = CCSprite::createWithSpriteFrameName("game_loading1.png"); loading->setPosition(ccp(winSize.width / 2, winSize.height / 2 - 40)); addChild(loading); CCAnimation * animation = CCAnimation::create(); animation->setDelayPerUnit(0.2f); char nameBuf[100]; for (int i = 0; i < 4; i++) { memset(nameBuf, 0, sizeof(nameBuf)); sprintf(nameBuf, "game_loading%d.png", i + 1); animation->addSpriteFrame(CCSpriteFrameCache::sharedSpriteFrameCache()->spriteFrameByName(nameBuf)); } CCAnimate *animate = CCAnimate::create(animation); CCRepeat *repeat = CCRepeat::create(animate, 4); //动画播放四次 CCCallFunc * loadingDone = CCCallFunc::create(this, callfunc_selector(LayerGameStart::toMainGameCallback)); //动画播放完毕回主场景 CCSequence * sequence = CCSequence::create(repeat, loadingDone, NULL); loading->runAction(sequence); } void LayerGameStart::addPreLoadMusic() { //加载全局音乐信息 loadMusic()->preloadBackgroundMusic("sound/game_music.wav"); loadMusic()->preloadEffect("sound/achievement.wav"); loadMusic()->preloadEffect("sound/big_spaceship_flying.wav"); loadMusic()->preloadEffect("sound/bullet.wav"); loadMusic()->preloadEffect("sound/button.wav"); loadMusic()->preloadEffect("sound/enemy1_down.wav"); loadMusic()->preloadEffect("sound/enemy2_down.wav"); loadMusic()->preloadEffect("sound/enemy3_down.wav"); loadMusic()->preloadEffect("sound/game_over.wav"); loadMusic()->preloadEffect("sound/get_bomb.wav"); loadMusic()->preloadEffect("sound/get_double_laser.wav"); loadMusic()->preloadEffect("sound/out_porp.wav"); loadMusic()->preloadEffect("sound/use_bomb.wav"); } void LayerGameStart::toMainGameCallback() { CCScene * scene = LayerGameMain::scene(); CCDirector::sharedDirector()->replaceScene(scene); }此场景会跳到主场景中去,也就是主游戏场景。
#include "LayerGameMain.h" #include "AppMacros.h" #include "LayerGameOver.h" #include "SimpleAudioEngine.h" #include "KinectControl.h" using namespace CocosDenshion; int LayerGameMain::score = 0; //分数初始化 CCScene * LayerGameMain::scene() { CCScene * scene = CCScene::create(); LayerGameMain * layer = LayerGameMain::create(); scene->addChild(layer); return scene; } bool LayerGameMain::init() { CCLayer::init(); // 设置安卓返回键 setKeypadEnabled(true); //播放背景音乐 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/game_music.wav", true); score = 0; bombInterval =false ; //处理多于两个炸弹间隔爆炸 bombIntervalCount = 0; bigBoomCount = 0; scheduleUpdate(); // 开启帧循环定时器 进行碰撞检测 setTouchEnabled(true); setTouchMode(kCCTouchesOneByOne); addBackGround(); //加载主场景背景 addHero(); //加飞机 addBulletLayer(); addEnemyLayer(); addCtrlLayer(); addFoodLayer(); return true; } //加载主场景背景 void LayerGameMain::addBackGround() { CCSprite * bg1 = CCSprite::createWithSpriteFrameName("background.png"); bg1->setTag(BACK1); bg1->setAnchorPoint(ccp(0, 0)); bg1->setPosition(ccp(0, 0)); addChild(bg1); CCSprite * bg2 = CCSprite::createWithSpriteFrameName("background.png"); bg2->setTag(BACK2); bg2->setAnchorPoint(ccp(0, 0)); bg2->setPosition(ccp(0, bg2->getContentSize().height - 2)); addChild(bg2); //启动定时器 帧循环是一帧是0.016 schedule(schedule_selector(LayerGameMain::movingBackGround), 0.01f); } //背景动起来 void LayerGameMain::movingBackGround(float dt) { CCSprite * bg1 = (CCSprite*)getChildByTag(BACK1); CCSprite * bg2 = (CCSprite*)getChildByTag(BACK2); bg1->setPositionY(bg1->getPositionY() - 5); bg2->setPositionY(bg1->getPositionY() + bg2->getContentSize().height - 2); if (bg2->getPositionY() < 0) { bg1->setPositionY(0); } } void LayerGameMain::addHero() //添加飞机 { Plane * hero = Plane::getInstance(); //单例获得飞机 hero->setPosition(ccp(winSize.width / 2, hero->getContentSize().height / 2)); //设置初始时飞机的位置 addChild(hero); } bool LayerGameMain::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) { CCRect planeRect = Plane::getInstance()->boundingBox(); planeRect.origin.x -= 30; planeRect.origin.y -= 40; planeRect.size.width += 60; planeRect.size.height += 80; if (planeRect.containsPoint(pTouch->getLocation())){ //点中了则继续 return true; } else{ return false; } } void LayerGameMain::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) { Plane *hero = Plane::getInstance(); CCPoint positon = hero->getPosition() + pTouch->getDelta(); //getDelta 一帧中获得的 //CCLog("%g", hero->boundingBox().size.width/2); //CCLog("%g", winSize.width - hero->boundingBox().size.width/2); //CCLog("%g", hero->boundingBox().size.height/2); //CCLog("%g", winSize.height - hero->boundingBox().size.height/2); if (positon.x < hero->boundingBox().size.width / 2 || positon.x > winSize.width - hero->boundingBox().size.width / 2 || positon.y <hero->boundingBox().size.height / 2 || positon.y > winSize.height - hero->boundingBox().size.height / 2) { return; //出界了 } else { Plane::getInstance()->setPosition(positon); } } void LayerGameMain::addBulletLayer() { _bulletLayer = LayerBullet::create(); addChild(_bulletLayer); } void LayerGameMain::addEnemyLayer() { _enemyLayer = LayerEnemy::create(); addChild(_enemyLayer); } void LayerGameMain::update(float dt) { //bullet vs enemysmall CCObject * bt = NULL; //子弹 CCObject * et = NULL; //敌机 CCArray *bulletsToDel = CCArray::create(); CCARRAY_FOREACH(_bulletLayer->_bulletArray, bt) //遍历子弹 { CCSprite * bullet = (CCSprite*)bt; CCArray * smallEnemyToDel = CCArray::create(); CCARRAY_FOREACH(_enemyLayer->smallArray, et) //取得小敌机 { Enemy * smallEnemy = (Enemy *)et; if (bullet->boundingBox().intersectsRect(smallEnemy->getBoundingBox())) { CCLog("%d", smallEnemy->getLife()); if (smallEnemy->getLife() == 1) { smallEnemy->loseLife(); bulletsToDel->addObject(bullet); smallEnemyToDel->addObject(smallEnemy); score += SMALL_SCORE; _ctrlLayer->updataScore(score); //更新分数 } } } CCARRAY_FOREACH(smallEnemyToDel, et) //遍历一遍再删除 { Enemy * smallEnemy = (Enemy*)et; _enemyLayer->smallEnemyBlowUp(smallEnemy); } smallEnemyToDel->release(); } CCARRAY_FOREACH(bulletsToDel, bt) { CCSprite * bullet = (CCSprite*)bt; _bulletLayer->removeBullet(bullet); } bulletsToDel->removeAllObjects(); //----------------bullet vs midplane CCARRAY_FOREACH(_bulletLayer->_bulletArray, bt) //遍历子弹 { CCSprite * bullet = (CCSprite*)bt; CCArray * midEnemyToDel = CCArray::create(); CCARRAY_FOREACH(_enemyLayer->midArray, et) //取得中敌机 { Enemy * midEnemy = (Enemy *)et; if (bullet->boundingBox().intersectsRect(midEnemy->getBoundingBox())) { //CCLog("%d", midEnemy->getLife()); if (midEnemy->getLife() > 1) { midEnemy->loseLife(); _enemyLayer->midHitAnimate(midEnemy); //显示击中效果 bulletsToDel->addObject(bullet); } else if (midEnemy->getLife() == 1) { midEnemy->loseLife(); bulletsToDel->addObject(bullet); midEnemyToDel->addObject(midEnemy); score += MID_SCORE; _ctrlLayer->updataScore(score); //更新分数 } } } CCARRAY_FOREACH(midEnemyToDel, et) //遍历一遍再删除 { Enemy * midEnemy = (Enemy*)et; _enemyLayer->midEnemyBlowUp(midEnemy); } midEnemyToDel->release(); } CCARRAY_FOREACH(bulletsToDel, bt) { CCSprite * bullet = (CCSprite*)bt; _bulletLayer->removeBullet(bullet); } bulletsToDel->removeAllObjects(); ////----------------------------------bullet VS bigplane CCARRAY_FOREACH(_bulletLayer->_bulletArray, bt) //遍历子弹 { CCSprite * bullet = (CCSprite*)bt; CCArray * bigEnemyToDel = CCArray::create(); CCARRAY_FOREACH(_enemyLayer->bigArray, et) //取得大敌机 { Enemy * bigEnemy = (Enemy *)et; if (bullet->boundingBox().intersectsRect(bigEnemy->getBoundingBox())) { //CCLog("%d", bigEnemy->getLife()); if (bigEnemy->getLife() > 1) { bigEnemy->loseLife(); _enemyLayer->bigHitAnimate(bigEnemy); //显示击中效果 bulletsToDel->addObject(bullet); } else if (bigEnemy->getLife() == 1) { bigEnemy->loseLife(); bulletsToDel->addObject(bullet); bigEnemyToDel->addObject(bigEnemy); score += BIG_SCORE; _ctrlLayer->updataScore(score); //更新分数 } } } CCARRAY_FOREACH(bigEnemyToDel, et) //遍历一遍再删除 { Enemy * bigEnemy = (Enemy*)et; _enemyLayer->bigEnemyBlowUp(bigEnemy); } bigEnemyToDel->release(); } CCARRAY_FOREACH(bulletsToDel, bt) { CCSprite * bullet = (CCSprite*)bt; _bulletLayer->removeBullet(bullet); } bulletsToDel->removeAllObjects(); //------------------------------------hero vs enemySmall CCRect planeRect = Plane::getInstance()->boundingBox(); //获得飞机单例 planeRect.origin.x += 30; planeRect.origin.y += 20; planeRect.size.width -= 60; planeRect.size.height -= 40; //-----------------------// CCARRAY_FOREACH(_enemyLayer->smallArray,et) { Enemy * smallEnemy = (Enemy *)et; if (planeRect.intersectsRect(smallEnemy->getBoundingBox())) { ((CCLayer*)(Plane::getInstance()->getParent()))->setTouchEnabled(false); //关闭触摸 _bulletLayer->stopShoot(); unscheduleAllSelectors(); // 关闭所有定时器 Plane::getInstance()->blowUp(); Plane::getInstance()->removePlane(); //如果加了场景切换 这里就不需要REMOVE _enemyLayer->smallEnemyBlowUp(smallEnemy); //把碰撞的小敌机也销毁 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/game_over.wav", true); CCScene *over = LayerGameOver::scene(); CCDirector::sharedDirector()->replaceScene(over); } } //------------------------------------hero vs enemyMid CCARRAY_FOREACH(_enemyLayer->midArray, et) { Enemy * midEnemy = (Enemy *)et; if (planeRect.intersectsRect(midEnemy->getBoundingBox())) { ((CCLayer*)(Plane::getInstance()->getParent()))->setTouchEnabled(false); //关闭触摸 _bulletLayer->stopShoot(); unscheduleAllSelectors(); // 关闭所有定时器 Plane::getInstance()->blowUp(); Plane::getInstance()->removePlane(); //如果加了场景切换 这里就不需要REMOVE _enemyLayer->midEnemyBlowUp(midEnemy); //把碰撞的中敌机也销毁 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/game_over.wav", true); CCScene *over = LayerGameOver::scene(); CCDirector::sharedDirector()->replaceScene(over); } } //------------------------------------hero vs enemyBig CCARRAY_FOREACH(_enemyLayer->bigArray, et) { Enemy * bigEnemy = (Enemy *)et; if (planeRect.intersectsRect(bigEnemy->getBoundingBox())) { ((CCLayer*)(Plane::getInstance()->getParent()))->setTouchEnabled(false); //关闭触摸 _bulletLayer->stopShoot(); unscheduleAllSelectors(); // 关闭所有定时器 Plane::getInstance()->blowUp(); Plane::getInstance()->removePlane(); //如果加了场景切换 这里就不需要REMOVE _enemyLayer->midEnemyBlowUp(bigEnemy); //把碰撞的大敌机也销毁 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/game_over.wav", true); CCScene *over = LayerGameOver::scene(); CCDirector::sharedDirector()->replaceScene(over); } } //------------------------------------food vs hero CCObject * ut; CCARRAY_FOREACH(_foodLayer->bigBoomArray, ut) { CCSprite * bigBoom = (CCSprite*)ut; if (bigBoom->boundingBox().intersectsRect(Plane::getInstance()->boundingBox()) ) { SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/get_bomb.wav", true); //得到炸弹的音效 _foodLayer->removeBigBoom(bigBoom); bigBoomCount++; //有几个炸弹 updateBigBoomCount(bigBoomCount); } } //-------------------------gesture bigboom --------------------- if (bombInterval) { bombIntervalCount++; } if (bombIntervalCount > 40) //比较合理的参数 { bombInterval =false ; bombIntervalCount = 0; } if (KinectControl::getInstance()->useBomb && bigBoomCount > 0 && !bombInterval ) { bombInterval = true; //处于间隔时间 SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/use_bomb.wav", true); bigBoomCount--; CCString *strBoomCount = CCString::createWithFormat("X%d", bigBoomCount); ((CCLabelBMFont*)(getChildByTag(TAG_BIGBOOMCOUNT)))->setCString(strBoomCount->getCString()); score += _enemyLayer->smallArray->count() * SMALL_SCORE; score += _enemyLayer->midArray->count() * MID_SCORE; score += _enemyLayer->bigArray->count() * BIG_SCORE; _ctrlLayer->updataScore(score); _enemyLayer->removeAllEnemy(); //干掉所有敌机 if (bigBoomCount == 0) { removeChildByTag(TAG_BIGBOOM); removeChildByTag(TAG_BIGBOOMCOUNT); } KinectControl::getInstance()->useBomb = false; } //----------------------------------foodMultiBullet vs hero CCObject * mbt; CCARRAY_FOREACH(_foodLayer->multiBulletArray, mbt) { CCSprite * multiBullets = (CCSprite*)mbt; if (multiBullets->boundingBox().intersectsRect(Plane::getInstance()->boundingBox())) { SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/get_double_laser.wav", true); //得到双排子弹的音效 _foodLayer->removeMultiBullets(multiBullets); _bulletLayer->multiBulletEffet(); //立即使用 } } } void LayerGameMain::updateBigBoomCount(int bigBoomCount) { CCString strBoomCount; if (bigBoomCount < 0) { return; } else if (bigBoomCount == 0) { if (getChildByTag(TAG_BIGBOOM)) //炸弹 图显示 { removeChildByTag(TAG_BIGBOOM, true); } if (getChildByTag(TAG_BIGBOOMCOUNT)) //炸弹 数目的显示 { removeChildByTag(TAG_BIGBOOMCOUNT, true); } } else if (bigBoomCount == 1) { CCSprite * norBoom = CCSprite::createWithSpriteFrameName("bomb.png"); if (!getChildByTag(TAG_BIGBOOM)) { CCSprite * selBoom = CCSprite::createWithSpriteFrameName("bomb.png"); CCMenuItemSprite * boomItem = CCMenuItemSprite::create(norBoom, selBoom, this, menu_selector(LayerGameMain::boomMenuCallBack)); boomItem->setPosition(ccp(norBoom->getContentSize().width / 2, norBoom->getContentSize().height / 2)); CCMenu * boomMenu = CCMenu::create(boomItem, NULL); boomMenu->setPosition(CCPointZero); addChild(boomMenu, 100, TAG_BIGBOOM); } if (!getChildByTag(TAG_BIGBOOMCOUNT)) { strBoomCount.initWithFormat("X%d", bigBoomCount); CCLabelBMFont * labelBoomCount = CCLabelBMFont::create(strBoomCount.getCString(), "font/font.fnt"); labelBoomCount->setAnchorPoint(ccp(0, 0.5)); labelBoomCount->setPosition(ccp(norBoom->getContentSize().width + 15, norBoom->getContentSize().height / 2)); addChild(labelBoomCount, 200, TAG_BIGBOOMCOUNT); } } else if (bigBoomCount > 1) { strBoomCount.initWithFormat("X%d", bigBoomCount); ((CCLabelBMFont*)(getChildByTag(TAG_BIGBOOMCOUNT)))->setCString(strBoomCount.getCString()); } } void LayerGameMain::boomMenuCallBack(CCObject * obj) //炸弹炸 { SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/use_bomb.wav", true); bigBoomCount--; CCString *strBoomCount = CCString::createWithFormat("X%d", bigBoomCount); ((CCLabelBMFont*)(getChildByTag(TAG_BIGBOOMCOUNT)))->setCString(strBoomCount->getCString()); score += _enemyLayer->smallArray->count() * SMALL_SCORE; score += _enemyLayer->midArray->count() * MID_SCORE; score += _enemyLayer->bigArray->count() * BIG_SCORE; _ctrlLayer->updataScore(score); _enemyLayer->removeAllEnemy(); //干掉所有敌机 if (bigBoomCount == 0) { removeChildByTag(TAG_BIGBOOM); removeChildByTag(TAG_BIGBOOMCOUNT); } } void LayerGameMain::addCtrlLayer() { _ctrlLayer = LayerControl::create(); addChild(_ctrlLayer); } void LayerGameMain::addFoodLayer() { _foodLayer = LayerFood::create(); addChild(_foodLayer); }
上面是主要部分,数据本地化,保存历史最高成绩实现如下:
void LayerGameOver::showScore() { int score = LayerGameMain::score; //----------------显示最终得分------------------------------// CCString *strScore = CCString::createWithFormat("%d", score); scoreFinalItem = CCLabelBMFont::create(strScore->getCString(), "font/font.fnt"); scoreFinalItem->setColor(ccc3(10, 250, 10)); scoreFinalItem->setAnchorPoint(ccp(0, 0)); scoreFinalItem->setPosition(ccp(winSize.width / 2 - 30, winSize.height / 2)); addChild(scoreFinalItem); //----------------------历史最佳成绩显示---------------------// int BestScore= CCUserDefault::sharedUserDefault()->getIntegerForKey("HistoryHighScore", 0); if (BestScore < score) { SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/achievement.wav", true); CCUserDefault::sharedUserDefault()->setIntegerForKey("HistoryHighScore", score); CCUserDefault::sharedUserDefault()->flush(); //下次读取前先从内存写入硬盘 BestScore = score; } CCString *strHistoryHighScore = CCString::createWithFormat("%d", BestScore); scoreBestItem = CCLabelBMFont::create(strHistoryHighScore->getCString() , "font/font.fnt"); scoreBestItem->setColor(ccc3(160, 160, 164)); scoreBestItem->setAnchorPoint(ccp(0, 0)); scoreBestItem->setPosition(ccp(winSize.width / 2 - 50, winSize.height -70)); addChild(scoreBestItem); }随着游戏得分越高,速度变快和小敌机中敌机大敌机参数设置,用了一个parameter的结构体变量,同时随机化保证飞机间隔不定时间出场,设定一个计数值smallEnemyFrameCount 达到计数值后清零;
void LayerEnemy::reSetframeCount(int degree) { switch (degree) { case SMALL: { curSmallFramCount = 0; smallEnemyFrameCount = rand() % 8 + (6 - parameter.smallParameter); break; } case MID: { curMidFrameCount = 0; midEnemyFrameCount = rand() % 15 + (10 - parameter.midParameter); break; } case BIG: { curBigFrameCount = 0; bigEnemyFrameCount = rand() % 25+ (35 - parameter.bigParameter); break; } default: break; } } void LayerEnemy::updateParameter() { int score = LayerControl::getScore(); if (score > 1000) { int degree =(int ) ((score - 1000) / 500) + 1 ; parameter.smallParameter = degree; if (parameter.smallParameter > 6) parameter.smallParameter = 6; parameter.midParameter = degree; if (parameter.midParameter > 8) parameter.midParameter = 8; parameter.bigParameter = degree; if (parameter.bigParameter > 12) parameter.bigParameter = 12; } }这里的体感控制,也就是手势区控制鼠标完成单击,确定,以及拖动飞机
1 kinect 单例设计 if(!m_Kinect)
{
m_Kinect = new KinectControl;
if (m_Kinect &&m_Kinect->init()){}
}
return m_Kinect; //模仿cocos2dx设计风格
2 获取运行窗体相对于整个屏幕坐标
HWND h =cocos2d::CCEGLView::sharedOpenGLView()->getHWnd(); //获得cocos2dx窗口的句柄
RECTrt = { 0 };
::GetWindowRect(h,&rt); //得到的既是相对于屏幕左上角的窗口矩形区域
3 关键两行代码参考chengaotan GitHub 的C#程序,还好C#和MFC大致差不多,勉强看懂。也有用指尖识别的,抖动太剧烈,不过改改采集间隔和加阈值判断应该可以。3个与鼠标操作有关的API ClipCursor;SetCursorPos; GetCursorPos
https://github.com/TangoChen/KinectV2MouseControl
下下来是不能运行了,改了一回才弄好,原来wpf和mfc也类似嘛,不然就GG了。
int xNow = (int)(curPos.x + (x*mouseSensitivity*lWidth -( curPos.x - rt.left))*smoothing);
int yNow = (int)(curPos.y + ((y + 0.25f) *mouseSensitivity *lHeight - (curPos.y-rt.top)) * smoothing);
schedule(schedule_selector(LayerControl::kinectUpdate), 0.02f); //定时器进行鼠标控制
4 实现KinectV2对鼠标控制后,一开始要让鼠标指向飞机,不同手势代表不同操作。共有三种不同的手势。这里用open代表飞机移动,拳头表示使用bomb(前提是你吃到了bomb),Lasso表示确定,用来返回游戏和退出游戏。
这里放一个没有和游戏交互的自己改进的Kinect控制鼠标的代码,和游戏交互,为了一开始就能使鼠标在飞机上,获取了游戏运行窗口在整个屏幕上的坐标,然后将鼠标固定到飞机上
HWND h = cocos2d::CCEGLView::sharedOpenGLView()->getHWnd(); //获得cocos2dx窗口的句柄 rt = { 0 }; ::GetWindowRect(h, &rt); //得到的既是相对于屏幕左上角的窗口矩形区域 Plane * plane = Plane::getInstance(); rtNew.left = rt.left + plane->boundingBox().size.width / 3 ; rtNew.right = rt.right - plane->boundingBox().size.width / 2; rtNew.top = rt.top + 30; //加上30为菜单栏的大小 rtNew.bottom = rt.bottom - plane->boundingBox().size.height / 2 - 5; TopLeftCorner = { rtNew.left, rtNew.top }; //屏幕左上角 lWidth = rtNew.right - rtNew.left; lHeight = rtNew.bottom - rtNew.top; SetCurPositonInPlane(); ClipCursor(&rtNew); //限制光标在矩形区域内游戏结束场景,可以通过手势剪刀表示确定:
游戏结束代码如下:
#include "LayerGameOver.h" #include "AppMacros.h" #include "LayerGameMain.h" #include "SimpleAudioEngine.h" #include "KinectControl.h" using namespace CocosDenshion; CCScene * LayerGameOver::scene() { CCScene * scene = CCScene::create(); LayerGameOver * layer = LayerGameOver::create(); scene->addChild(layer); return scene; } bool LayerGameOver::init() { CCLayer::init(); addGameOverPicture(); showScore(); OneMoreGame(); schedule(schedule_selector(LayerControl::kinectUpdate), 0.016f); //定时器进行鼠标控制 return true; } void LayerGameOver::kinectUpdate(float dt) { KinectControl::getInstance()->Update (); } void LayerGameOver::MenuGameMainCallBack(CCObject *obj) //切换场景到游戏运行界面 { // SetCursorPos(1024, 955); //就算这样 , 飞机还是回不来了 O(∩_∩)O~ CCScene * scene = LayerGameMain::scene(); CCDirector::sharedDirector()->replaceScene(scene); } void LayerGameOver::addGameOverPicture() { CCSprite * background = CCSprite::createWithSpriteFrameName("gameover.png"); background->setAnchorPoint(ccp(0, 0)); background->setPosition(ccp(0, winSize.height-background->getContentSize().height)); addChild(background); } void LayerGameOver::addOneMoreGame() { MoreGame = CCSprite::createWithSpriteFrameName("btn_finish.png"); MoreGame->setPosition(ccp(winSize.width / 2 - 10, winSize.height / 3 - 20)); addChild(MoreGame); } void LayerGameOver::showScore() { int score = LayerGameMain::score; //----------------显示最终得分------------------------------// CCString *strScore = CCString::createWithFormat("%d", score); scoreFinalItem = CCLabelBMFont::create(strScore->getCString(), "font/font.fnt"); scoreFinalItem->setColor(ccc3(10, 250, 10)); scoreFinalItem->setAnchorPoint(ccp(0, 0)); scoreFinalItem->setPosition(ccp(winSize.width / 2 - 30, winSize.height / 2)); addChild(scoreFinalItem); //----------------------历史最佳成绩显示---------------------// int BestScore= CCUserDefault::sharedUserDefault()->getIntegerForKey("HistoryHighScore", 0); if (BestScore < score) { SimpleAudioEngine::sharedEngine()->playBackgroundMusic("sound/achievement.wav", true); CCUserDefault::sharedUserDefault()->setIntegerForKey("HistoryHighScore", score); CCUserDefault::sharedUserDefault()->flush(); //下次读取前先从内存写入硬盘 BestScore = score; } CCString *strHistoryHighScore = CCString::createWithFormat("%d", BestScore); scoreBestItem = CCLabelBMFont::create(strHistoryHighScore->getCString() , "font/font.fnt"); scoreBestItem->setColor(ccc3(160, 160, 164)); scoreBestItem->setAnchorPoint(ccp(0, 0)); scoreBestItem->setPosition(ccp(winSize.width / 2 - 50, winSize.height -70)); addChild(scoreBestItem); } void LayerGameOver::QuitCallBack(CCObject * obj) { KinectControl::getInstance()->KinectRemove(); exit(1); } void LayerGameOver::OneMoreGame() //添加回到游戏按钮 { CCSprite * GameOnceMore = CCSprite::createWithSpriteFrameName("btn_finish.png"); CCSprite * OutGame = CCSprite::create("define/out.png"); CCMenuItemSprite * Again = CCMenuItemSprite::create(GameOnceMore, GameOnceMore, this, menu_selector(LayerGameOver::MenuGameMainCallBack)); CCMenuItemSprite * End = CCMenuItemSprite::create(OutGame, OutGame , this, menu_selector(LayerGameOver::QuitCallBack )); CCMenu * backMenu = CCMenu::create(Again,End, NULL); backMenu->alignItemsVerticallyWithPadding(40); backMenu->setPosition(ccp(winSize.width / 2 - 10, winSize.height / 3 - 20)); addChild(backMenu); }