接《基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)》

三、代码分析

1.界面初始化

 bool PlaneWarGame::init()
{
bool bRet = false;
do
{
CC_BREAK_IF(! CCLayer::init()); _size = CCDirector::sharedDirector()->getWinSize(); // 设置触摸可用
this->setIsTouchEnabled(true);
// 从窗口中取消息
CCDirector::sharedDirector()->getOpenGLView()->SetWin32KeyLayer( this ); // 初始化游戏背景
CC_BREAK_IF(!initBackground());
// 菜单1(暂停/声音/炸弹)
CC_BREAK_IF(!initMenu1());
// 菜单2(继续/重新开始/返回)
CC_BREAK_IF(!initMenu2());
// 菜单3(重新开始/返回)
CC_BREAK_IF(!initMenu3()); // 创建玩家飞机
_player = new PlaySprite;
_player->setPosition(CCPointZero);
addChild(_player); // 调度器:定时调用自定义的回扫函数
this->schedule( schedule_selector(PlaneWarGame::gameLoop));
this->schedule( schedule_selector(PlaneWarGame::shoot), 0.1 );
this->schedule( schedule_selector(PlaneWarGame::addEnemy), 0.3 );
this->schedule( schedule_selector(PlaneWarGame::addProp), ); // 初始化两个数组
_enemys = CCArray::array();
_enemys->retain();
_bullets = CCArray::array();
_bullets->retain(); // 背景音乐
CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
"planewar/game_music.wav", true); bRet = true;
} while (); return bRet;
}

初始化的工作包括:

  • 设置触摸可用
  •   设置可自定义处理消息
  • 初始化游戏背景
  •   初始化三个菜单(界面菜单/游戏暂停时的菜单/游戏结束时的菜单)
  •   初始化两个CCArray类型的数组,分别用来存储有效的敌机精灵对象和子弹对象
  • 设置需要定时调用函数的调度器
  • 设置背景音乐
  • 添加玩家角色

2.初始化游戏背景

 bool PlaneWarGame::initBackground()
{
// 显示分数
_label = CCLabelBMFont::labelWithString("","planewar/font.fnt");
_label->setPosition(ccp(,_size.height-));
_label->setColor(ccc3(,,));
this->addChild(_label, ); // 显示炸弹数量
CCLabelBMFont* bombcount = CCLabelBMFont::labelWithString("X09","planewar/font.fnt");
bombcount->setAnchorPoint(ccp(,));
bombcount->setPosition(ccp(,));
bombcount->setColor(ccc3(,,));
addChild(bombcount, ,); // 添加背景
CCSprite* bg1 = CCSprite::spriteWithFile("planewar/bg1.png");
if (!bg1)return false;
bg1->setAnchorPoint(ccp(,));
bg1->setPosition( ccp(, _size.height) );
this->addChild(bg1, , ); bg1->runAction(
CCSequence::actions(
CCMoveBy::actionWithDuration(,ccp(,-)),
CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL)); CCSprite* bg2 = CCSprite::spriteWithFile("planewar/bg2.png");
if (!bg1)return false;
bg2->setAnchorPoint(ccp(,));
bg2->setPosition( ccp(, _size.height*) );
this->addChild(bg2, , ); bg2->runAction(
CCSequence::actions(
CCMoveBy::actionWithDuration(,ccp(,-)),
CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL));
return true;
} void PlaneWarGame::bg1roll(){
//运动出屏幕重设位置,运动
CCSprite * bg = (CCSprite *)getChildByTag();
bg->setPosition(ccp(,));
CCAction* seq = CCSequence::actions(
CCMoveBy::actionWithDuration(,ccp(,-)),
CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL);
bg->runAction(seq);
} void PlaneWarGame::bg2roll(){
//运动出屏幕重设位置,运动
CCSprite * bg = (CCSprite *)getChildByTag();
bg->setPosition(ccp(,));
CCAction* seq = CCSequence::actions(
CCMoveBy::actionWithDuration(,ccp(,-)),
CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL);
bg->runAction(seq);
}

初始化游戏背景时,需要注意的是:要做出飞机向上走的视觉效果,就要把背景向下滚动,这里使用两个背景bg1和bg2,大小分别为屏幕大小。初始bg1在屏幕内,bg2在屏幕上方,两个同事向下运动;当bg1刚刚运动到屏幕外,bg2刚好盖住屏幕,bg1挪到屏幕上方向下运动...循环操作,就能做出循环滚动的背景效果了。

3.子弹的处理

 // 确定子弹类型
void PlaneWarGame::shoot(float dt)
{
if (_isOver)return;
if(_player==NULL) return; if(_player->_bulletKind == BK_SINGLE)
{
CCSprite *bullet = CCSprite::spriteWithFile(
"planewar/plane.png", CCRectMake(,,,));
addBullet(bullet,_player->getPlayerPt());
}else if (_player->_bulletKind == BK_DOUBLE)
{
CCSprite *bullet = CCSprite::spriteWithFile(
"planewar/plane.png", CCRectMake(,,,));
addBullet(bullet,ccp(_player->getPlayerPt().x-,_player->getPlayerPt().y));
CCSprite *bullet1 = CCSprite::spriteWithFile(
"planewar/plane.png", CCRectMake(,,,));
addBullet(bullet1,ccp(_player->getPlayerPt().x+,_player->getPlayerPt().y));
}
}
// 添加子弹
void PlaneWarGame::addBullet(CCSprite* bullet, CCPoint pt)
{
bullet->setPosition(pt);
this->addChild(bullet); bullet->runAction( CCSequence::actions(
CCMoveTo::actionWithDuration(0.5, ccp(pt.x,_size.height+bullet->getContentSize().height/)),
CCCallFuncN::actionWithTarget(this,callfuncN_selector(PlaneWarGame::spriteMoveFinished)),
NULL) ); bullet->setTag();
_bullets->addObject(bullet);
}
// 回收
void PlaneWarGame::spriteMoveFinished(CCNode* sender)
{
CCSprite *sprite = (CCSprite *)sender;
this->removeChild(sprite, true);
if (sprite->getTag()==)//子弹
_bullets->removeObject(sprite);
}

吃道具可改变子弹类型。子弹的回收方式:从飞机坐标处出发,运动到屏幕外被回收。道具的处理类似。

4.设置触摸/鼠标点击控制玩家角色的移动

 bool PlaneWarGame::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
{
if(_player==NULL) return false; CCPoint pt = CCDirector::sharedDirector()->convertToGL(
pTouch->locationInView(pTouch->view())); CCRect rt = _player->getRect();
if (CCRect::CCRectContainsPoint(rt,pt))
_player->_isDragEnabled = true;
return true;
} void PlaneWarGame::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
{
if(_player==NULL) return; CCSize size = CCDirector::sharedDirector()->getWinSize();
CCPoint pt = CCDirector::sharedDirector()->convertToGL(
pTouch->locationInView(pTouch->view())); CCRect rt = CCRect(,,size.width,size.height); if (_player->_isDragEnabled && CCRect::CCRectContainsPoint(rt,pt))
_player->setPlayerPt(pt);
} void PlaneWarGame::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
{
_player->_isDragEnabled = false;
}

这里重写3个虚函数。移动角色的方式:触摸/鼠标按下时,如果点击位置在角色上,将角色可被拖拽状态置为true;触摸/鼠标移动时,根据角色的可被拖拽状态和屏幕范围确定是否移动;触摸/鼠标弹起时,将角色的可被拖拽状态恢复为false。

5.碰撞检测

 void PlaneWarGame::updateGame(float dt)
{
CCArray *bulletsToDelete = CCArray::array();
CCObject* it = NULL;
CCObject* jt = NULL; if(_player==NULL) return; CCRect playerRect = _player->getRect();
// 己方飞机和敌方飞机的碰撞
CCARRAY_FOREACH(_enemys, jt)
{
EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
if (!enemy->isNull() && CCRect::CCRectIntersectsRect(playerRect, enemy->getRect()))
{
_player->die();
gameover(false);
return;
}
} //////////////////////////////////////////////////////////////////////////
// 道具和角色的碰撞检测
CCSprite* prop = (CCSprite*)getChildByTag();//子弹
if (NULL != prop)
{
CCRect propRect = CCRectMake(
prop->getPosition().x - (prop->getContentSize().width/),
prop->getPosition().y - (prop->getContentSize().height/),
prop->getContentSize().width,
prop->getContentSize().height);
if (CCRect::CCRectIntersectsRect(playerRect, propRect))
{
_player->_bulletKind = BK_DOUBLE;
removeChild(prop,true);
CocosDenshion::SimpleAudioEngine::sharedEngine()->
playEffect("planewar/get_double_laser.wav",false);
}
}
CCSprite* prop1 = (CCSprite*)getChildByTag();//炸弹
if (NULL != prop1)
{
CCRect prop1Rect = CCRectMake(
prop1->getPosition().x - (prop1->getContentSize().width/),
prop1->getPosition().y - (prop1->getContentSize().height/),
prop1->getContentSize().width,
prop1->getContentSize().height);
if (CCRect::CCRectIntersectsRect(playerRect, prop1Rect))
{
_player->_bombCount++;
removeChild(prop1,true);
CocosDenshion::SimpleAudioEngine::sharedEngine()->
playEffect("planewar/get_bomb.wav",false);
}
} //////////////////////////////////////////////////////////////////////////
// 子弹和敌机的碰撞检测
CCARRAY_FOREACH(_bullets, it)
for (int i=; i<_bullets->count(); i++)
{
CCSprite *bullet = dynamic_cast<CCSprite*>(_bullets->objectAtIndex(i));
CCRect bulletRect = CCRectMake(
bullet->getPosition().x - (bullet->getContentSize().width/),
bullet->getPosition().y - (bullet->getContentSize().height/),
bullet->getContentSize().width,
bullet->getContentSize().height); CCArray* enemysToDelete =CCArray::array(); CCARRAY_FOREACH(_enemys, jt)
{
EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
if (!enemy->_die && CCRect::CCRectIntersectsRect(bulletRect, enemy->getRect()))
{
if (enemy->_hp>)
{
enemy->_hp--;
//bulletsToDelete->addObject(bullet);
_bullets->removeObject(bullet);
removeChild(bullet,true);
}
else if (enemy->_hp<=)
{
//bulletsToDelete->addObject(bullet);
_bullets->removeObject(bullet);
removeChild(bullet,true);
enemysToDelete->addObject(enemy);
}
}
} CCARRAY_FOREACH(enemysToDelete, jt)
{
EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
enemy->_die = true;
enemy->die();
_bulletsDestroyed++;
} enemysToDelete->release();
} // 释放已死亡的子弹
CCARRAY_FOREACH(bulletsToDelete, it)
{
CCSprite* projectile = dynamic_cast<CCSprite*>(it);
_bullets->removeObject(projectile);
this->removeChild(projectile, true);
}
bulletsToDelete->release();
}

碰撞检测使用最简单的矩形检测。

6.玩家角色的添加和操作

 void PlaySprite::onEnter()
{
CCNode::onEnter(); CCSize size = CCDirector::sharedDirector()->getWinSize();
_sprite = CCSprite::spriteWithFile("planewar/hero1.png");
_sprite->setContentSize(CCSize(,));
_sprite->setPosition( ccp(size.width/,_sprite->getContentSize().height/) );
addChild(_sprite,); CCAnimation * animation = CCAnimation::animation();
animation->addFrameWithFileName("planewar/hero1.png");
animation->addFrameWithFileName("planewar/hero2.png");
CCAction* action = CCRepeatForever::actionWithAction(
CCAnimate::actionWithDuration(0.1f, animation, false));
action->setTag();
_sprite->runAction(action); // 调度器
schedule( schedule_selector(PlaySprite::move), 0.002 );
} CCRect PlaySprite::getRect()
{
if (_sprite!=NULL)
return CCRect(
_sprite->getPosition().x - (_sprite->getContentSize().width/),
_sprite->getPosition().y - (_sprite->getContentSize().height/),
_sprite->getContentSize().width,
_sprite->getContentSize().height);
} CCPoint PlaySprite::getPlayerPt()
{
if (_sprite!=NULL)
return _sprite->getPosition();
} void PlaySprite::setPlayerPt(CCPoint pt)
{
if (_sprite!=NULL)
return _sprite->setPosition(pt);
} void PlaySprite::setMoveMode( UINT message, WPARAM wParam)
{
if (message == WM_KEYDOWN)
{// 控制飞机移动
if (wParam == VK_UP)
_mode = MM_UP;
else if (wParam == VK_DOWN)
_mode = MM_DOWN;
else if (wParam == VK_LEFT)
_mode = MM_LEFT;
else if (wParam == VK_RIGHT)
_mode = MM_RIGHT;
}else if (message == WM_KEYUP)
{
if (wParam == VK_UP || wParam == VK_DOWN ||wParam == VK_LEFT||wParam == VK_RIGHT)
_mode = MM_NONE;
}
} void PlaySprite::move(float dt)
{
CCSize winSize = CCDirector::sharedDirector()->getWinSize(); switch(_mode)
{
case MM_NONE:
break;
case MM_UP:
if (getPlayerPt().y<winSize.height)
setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y+));
break;
case MM_DOWN:
if (getPlayerPt().y>)
setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y-));
break;
case MM_LEFT:
if (getPlayerPt().x>)
setPlayerPt(ccp(getPlayerPt().x-,getPlayerPt().y));
break;
case MM_RIGHT:
if (getPlayerPt().x<winSize.width)
setPlayerPt(ccp(getPlayerPt().x+,getPlayerPt().y));
break;
}
} void PlaySprite::die()
{
if (_sprite==NULL)return; _sprite->stopActionByTag();
CCAnimation * animation = CCAnimation::animation();
animation->addFrameWithFileName("planewar/hero_blowup_n1.png");
animation->addFrameWithFileName("planewar/hero_blowup_n2.png");
animation->addFrameWithFileName("planewar/hero_blowup_n3.png");
animation->addFrameWithFileName("planewar/hero_blowup_n4.png");
_sprite->runAction(CCSequence::actions(
CCAnimate::actionWithDuration(0.1f, animation, false),
CCCallFunc::actionWithTarget(this, callfunc_selector(PlaySprite::destroy)),NULL));
} void PlaySprite::destroy()
{
if (_sprite==NULL)return; removeChild(_sprite,true);
_sprite = NULL;
}
  • 玩家角色类是派生自CCNode类,用组合的方式包含一个CCSprite类的成员对象,在玩家角色类内部封装对精灵的操作。
  • 重写onEnter函数初始化_sprite成员,设置位置、大小、图片和帧动画等。
  • 玩家的方向键控制移动和鼠标拖拽移动方式类似,在操作时设置移动状态,在schedule定时调用的函数move中根据移动状态来移动玩家角色。
  • 关于碰撞之后的动画和销毁,参照上面的die和destroy函数,对象被碰撞时调用die函数运行爆炸的帧动画,动画结束后自动调用destroy函数销毁对象。
  • 敌机对象的操作和玩家角色类似。

四、完成效果图

经过不到一周的时间,从什么都没有,到游戏正常运行、功能完整,体会了cocos2dx的调用机制。

下面是运行效果图:

如果实现中有什么问题,欢迎大家在评论中指教!

基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(中)的更多相关文章

  1. 基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(下)

    在飞机大战游戏开发中遇到的问题和解决方法: 1.在添加菜单时,我要添加一个有背景的菜单,需要在菜单pMenu中添加一个图片精灵,结果编译过了但是运行出错,如下图: 查了很多资料,调试了很长时间,整个人 ...

  2. 基于Cocos2d-x-1.0.1的飞机大战游戏开发实例(上)

    最近接触过几个版本的cocos2dx,决定每个大变动的版本都尝试一下.本实例模仿微信5.0版本中的飞机大战游戏,如图: 一.工具 1.素材:飞机大战的素材(图片.声音等)来自于网络 2.引擎:coco ...

  3. 基于Cocos2d-x-1.0.1的飞机大战游戏迁移到Cocos2d-x-3.0版本,并移植到Android平台成功运行

    一.版本迁移中的问题 1.游戏元素Sprite.Label.Action等等的创建函数名都改为create. 2.函数的回调callfunc_selectorcallfuncN_selectorcal ...

  4. 微信5.0 Android版飞机大战破解无敌模式手记

    微信5.0 Android版飞机大战破解无敌模式手记 转载: http://www.blogjava.net/zh-weir/archive/2013/08/14/402821.html 微信5.0 ...

  5. 11.pygame飞机大战游戏整体代码

    主程序 # -*- coding: utf-8 -*- # @Time: 2022/5/20 22:26 # @Author: LiQi # @Describe: 主程序 import pygame ...

  6. "飞机大战"游戏_Java实现_详细注释

    1 package cn.xiaocangtian.Util; import java.awt.Frame; import java.awt.Graphics; import java.awt.Ima ...

  7. 用Javascript模拟微信飞机大战游戏

    最近微信的飞机大战非常流行,下载量非常高. 利用JS进行模拟制作了一个简单的飞机大战[此源码有很多地方可以进行重构和优化] [此游戏中没有使用HTML5 任何浏览器都可以运行]. 效果图: 原理:利用 ...

  8. 一、利用Python编写飞机大战游戏-面向对象设计思想

    相信大家看到过网上很多关于飞机大战的项目,但是对其中的模块方法,以及使用和游戏工作原理都不了解,看的也是一脸懵逼,根本看不下去.下面我做个详细讲解,在做此游戏需要用到pygame模块,所以这一章先进行 ...

  9. "飞机大战"游戏_Java

    1 package cn.xiaocangtian.Util; import java.awt.Frame; import java.awt.Graphics; import java.awt.Ima ...

随机推荐

  1. 【金融123】ISDA协议

    http://blog.sina.com.cn/s/blog_799af92f0100ur03.html http://www.nafmii.org.cn/ NAFMII 官方文档 NAFMII_Ma ...

  2. Kali-linux使用Nessus

    Nessus号称是世界上最流行的漏洞扫描程序,全世界有超过75000个组织在使用它.该工具提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库.Nessus不同于传统的漏洞扫描软件,Nessus可同时在 ...

  3. 初始化列表initializer_list

    初始化列表定义在<initializer_list>,初始化列表简化了参数数量可变的函数的编写,初始化列表的所有的元素都应该是同一种数据类型 由于定义了列表中允许的类型,所以初始化列表是安 ...

  4. Infiniband基本知识

    InfiniBand架构是一种支持多并发链接的“转换线缆”技术,在这种技术中,每种链接都可以达到2.5 Gbps的运行速度.这种架构在一个链接的时候速度是500 MB/秒,四个链接的时候速度是2 GB ...

  5. [Oracle]记一次由sequence引发的enq sv-contention等待事件

    数据库版本:11.2.0.4 RAC(1)问题现象从EM里面可以看到,在23号早上8:45~8:55时,数据库等待会话暴增,大约到了80个会话.通过查看EM的SQL信息,发现等待产生于SQL语句 se ...

  6. Unity-iPhone has Conflicting Provisioning Settings

    Select the top level node called Unity-iPhone in the left tree view (the one with the blue item). Se ...

  7. Extjs6 组件浅谈

    一.Component组件 一个 Ext JS 应用的界面由一个或多个叫做 组件的控件组成. 所有的组件都是 Ext.Component 类的子类,这个类可以允许参与包含实例化.渲染.自动大小和位置以 ...

  8. javascript的执行机制—Event Loop

    既然今天要谈的是javascript的事件循环机制,要理解事件循环,首先要知道事件循环是什么. 我们先从一个例子来看一下javascript的执行顺序. <script> setTimeo ...

  9. MySQL----navicat for mysql(破解版)可视化数据库操作

    本博文介绍破解版navicat for mysql的安装方法及常用操作 navicat for mysql是一个专业的MySQL数据库图形化界面工具. 百度云下载地址:https://pan.baid ...

  10. Spring MVC中如何解决POST请求中文乱码问题,GET的又如何处理呢

    在web.xml中配置过滤器 GET请求乱码解决: 在Tomcat中service.xml中