接《基于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. ps基础练习

    1. 直接把图片拖进来 2. F 键 视窗全屏快捷键 3. 此时的图片是“背景”层,不能直接编辑,双击该背景层,就变成了“图层”,就可以编辑了  4. 5. 6. 7. 魔棒工具,在需要去掉的点一下, ...

  2. 20145314郑凯杰 《Java程序设计》第10周学习总结

    20145314郑凯杰 <Java程序设计>第10周学习总结 代码托管: 学习内容总结 网络编程 会打手机吗? 第一个问题:会打手机吗?很多人可能说肯定会啊,不就是按按电话号码,拨打电话嘛 ...

  3. 失败 - 模块“MonitorLoop”打开电源失败。

    启动虚拟机提示以下错误 失败 - 模块“MonitorLoop”打开电源失败. 磁盘空间满了

  4. ORA-00600:internal error code,arguments:[keltnfy-idmlnit],[46],[1],[],[],[],[],[]

    如图:在DBCA进行到3%时.报错 由于/etc/hosts与/etc/sysconfig/network不正确应,所以报错 [root@ocm2 ~]# cat /etc/hosts # Do no ...

  5. PHP介绍(PHP入门1)

    BS架构和CS架构 B:Browser:浏览器 S:Server:服务器 C:Client:客户端 BS 浏览器和服务器的关系,通过浏览器来访问服务器,比如:百度.新浪... 优点:只要有浏览器就能访 ...

  6. CORS跨域实现思路及相关解决方案

    本篇包括以下内容: CORS 定义 CORS 对比 JSONP CORS,BROWSER支持情况 主要用途 Ajax请求跨域资源的异常 CORS 实现思路 安全说明 CORS 几种解决方案 自定义CO ...

  7. 小程序 组件 Component

    一.组件模板和样式 类似于页面,自定义组件拥有自己的 wxml 和模板 wxss 样式. 1.组件模板 组件的写法和页面的写法相同,组件模板与组件数据结合后生成的数节点, 将被插入到组件的引用位置.在 ...

  8. eclipse 打开一个新工程的基本设置

    1.代码自动提示 Window -> Preferences -> Java -> Editor -> Content Assist -> Auto Activation ...

  9. 如何创建一个新的vue项目

    一.cnpm安装 1.百度node官网,进入官网下载安装包安装好node环境 2.成功后打开cmd命令行工具,执行node-v命令,查看node版本号,如果能输出版本号说明安装成功 3.推荐使用淘宝 ...

  10. ios中input输入无效

    项目中一个登陆界面的input在安卓下可以输入,iOS下无法输入,经查询为 设置了-webkit-user-select:none;将其改为-webkit-user-select:auto;修正. 参 ...