Cocos2dx系列笔记7:一个简单的跑酷游戏《萝莉快跑》的消化(附下载)
懒骨头(http://blog.csdn.com/iamlazybone)
或许有天
我们羡慕和崇拜的人
因为我们的努力
也会来了解我们
说不定
还会成为好友
骨头喜欢这样与哲哲共勉
多少个夜晚
一张长长的书桌上
哲哲在左边认真的做着可爱的独特的手作
骨头在右边噼里啪啦敲着自己真正喜欢的代码
中间的pad放部电影 || 放首歌 || 放段《一席》
这就是我们刚认识时憧憬的日子
所以现在是很幸福了
继续!
昨晚那个游戏已经成功运行在了手机上,接下来,好好看看代码。
AppDelegate.cpp类
常规的东西,设置FPS,设置是否显示FPS,生成菜单场景类Scene,然后让导演类加载第一个场景。
GameMenuScene.cpp类
大部分工作都在init里,设置背景:
- CCSize size = CCDirector::sharedDirector()->getWinSize();
- //菜单背景
- CCSprite* bg = CCSprite::create("MainMenu.png");
- bg->setScale(0.5);
- bg->setPosition( ccp(size.width/2, size.height/2) );
- this->addChild(bg, 0,0);
加载几个按钮,到CCMenu上,然后将CCMenu加载到Scene中
- //按钮
- CCMenuItemImage *newGameItem = CCMenuItemImage::create("newGameA.png", "newGameB.png",this,menu_selector(GameMenu::menuNewGameCallback));
- newGameItem->setScale(0.5);
- newGameItem->setPosition(ccp(size.width / 2 + 40,size.height / 2 - 20));
- newGameItem->setEnabled(false);
- CCMenuItemImage *continueItem = CCMenuItemImage::create("continueA.png", "continueB.png",this,menu_selector(GameMenu::menuContinueCallback));
- continueItem->setScale(0.5);
- continueItem->setPosition(ccp(size.width / 2 + 40,size.height / 2 - 60));
- continueItem->setEnabled(false);
- CCMenuItemImage *aboutItem = CCMenuItemImage::create("aboutA.png", "aboutB.png",this,menu_selector(GameMenu::menuAboutCallback));
- aboutItem->setScale(0.5);
- aboutItem->setPosition(ccp(size.width / 2 + 40,size.height / 2 - 100));
- aboutItem->setEnabled(false);
- soundItem = CCMenuItemImage::create("sound-on-A.png", "sound-on-B.png",this,menu_selector(GameMenu::menuSoundCallback));
- soundItem->setScale(0.5);
- soundItem->setEnabled(false);
- soundItem->setPosition(ccp(40,40));
- CCMenu* mainmenu = CCMenu::create(newGameItem,continueItem,aboutItem,soundItem,NULL);
- mainmenu->setPosition(ccp(0,0));
- this->addChild(mainmenu,1,3);
初始化背景音乐:
- //初始化声音
- SimpleAudioEngine::sharedEngine()->preloadBackgroundMusic("background.mp3");
- SimpleAudioEngine::sharedEngine()->setBackgroundMusicVolume(0.5);
- SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background.mp3");
然后在onEnter方法里,让菜单按钮从无放大至正常大小
- void GameMenu::onEnter(){
- CCLayer::onEnter();
- CCSize size = CCDirector::sharedDirector()->getWinSize();
- CCNode* mainmenu = this->getChildByTag(3);
- mainmenu->setScale(0);
- mainmenu->runAction(CCSequence::create(CCScaleTo::create(0.5,1),CCCallFunc::create(this, callfunc_selector(GameMenu::menuEnter)),NULL));
- }
使用getChildByTag()方法取得mainNenu。这也正是为何addChild()时,要加入tag参数了。
- CCSequence::create()里,CCScaleTo动作执行完之后,调用GameMenu类的menuEnter方法
然后通过mainmenu->getChildren();方法获取按钮组,遍历一下,设置为可用。
然后紧跟着一些callBack方法,也就是按钮事件
- void GameMenu::menuNewGameCallback(CCObject* pSender)
- {
- CCDirector::sharedDirector()->setDepthTest(true);
- CCDirector::sharedDirector()->replaceScene(CCTransitionPageTurn::create(0.5,GameMain::scene(), false));
- }
最后是控制背景音乐的方法
- void GameMenu::menuSoundCallback(CCObject* pSender)
- {
- //设置声音
- if(! issound){
- soundItem->setNormalImage(CCSprite::create("sound-on-A.png"));
- soundItem->setDisabledImage(CCSprite::create("sound-on-B.png"));
- SimpleAudioEngine::sharedEngine()->playBackgroundMusic("background.mp3", true);
- issound = true;
- }else{
- soundItem->setNormalImage(CCSprite::create("sound-off-A.png"));
- soundItem->setDisabledImage(CCSprite::create("sound-off-B.png"));
- SimpleAudioEngine::sharedEngine()->stopBackgroundMusic();
- issound = false;
- }
- }
再来看看关于界GameAboutScene.cpp
【插一句:setDepthTest:设置深度测试——可以用于自动处理遮挡关系】
这个类里,在init方法中贴几个CCSprite,加一个CCMenuItemImage及点击事件即可。没什么特别的。
GameObjStar.cpp星星类
本身继承自CCNode,有一个设置是否可见的方法
- void GameObjStar::set_visable(bool var){
- _visable = var;
- this->setVisible(var);
- }
在onEnter方法中初始化一下:缩放至一半大小,设置是否可见,设置尺寸。
- void GameObjStar::onEnter(){
- CCNode::onEnter();
- //星星初始化
- this->setContentSize(CCSizeMake(36.5,35.5));
- CCSprite* star = CCSprite::create("star.png");
- star->setScale(0.5);
- _visable = true;
- addChild(star,1);
- }
GameMark.cpp分数类
也是继承自CCNode,同样在onEnter方法里初始化,前面的socre是一个固定的CCSprite,后面是5个CCSprite,根据每个位数来动态修改图片
- void GameMark::onEnter()
- {
- CCNode::onEnter();
- CCSize size = CCDirector::sharedDirector()->getWinSize();
- this->setContentSize(size);
- // bits = CCArray::create(5);
- bits=new CCArray(5);
- CCSprite *title= CCSprite::create("score.png");
- title->setPosition(ccp(size.width/2 + 120,size.height - 15));
- title->setScale(0.5);
- addChild(title);
- for(int i = 0;i < 5;i ++){
- CCSprite * shu = CCSprite::create("shu.png");
- ui = shu->getTexture();
- shu->setScale(0.5);
- shu->setTextureRect(CCRectMake(234,0,26,31));
- shu->setPosition(ccp(size.width - 15 - i * 15,size.height - 15));
- bits->addObject(shu);
- addChild(shu);
- }
- bits->retain();
- mark = 0;
- }
bits->retain();// 应该是防止数组被回收
下面是按位设置数字,这种自定义rect的舒适化CCSprite的方式是第一次出现,其他的没什么了。
- setTextureRect(CCRectMake((temp - 1) * 26,0,26,31));
- void GameMark::addnumber(int var){
- //按位设置数字
- mark += var;
- int temp = mark % 10;
- if(temp > 0){
- ((CCSprite *)bits->objectAtIndex(0))->setTexture(ui);
- ((CCSprite *)bits->objectAtIndex(0))->setTextureRect(CCRectMake((temp - 1) * 26,0,26,31));
- }else{
- ((CCSprite *)bits->objectAtIndex(0))->setTexture(ui);
- ((CCSprite *)bits->objectAtIndex(0))->setTextureRect(CCRectMake(234,0,26,31));
- }
- temp = (mark % 100) / 10;
- if(temp > 0){
- ((CCSprite *)bits->objectAtIndex(0))->setTexture(ui);
- ((CCSprite *)bits->objectAtIndex(1))->setTextureRect(CCRectMake((temp - 1) * 26,0,26,31));
- }else{
- ((CCSprite *)bits->objectAtIndex(0))->setTexture(ui);
- ((CCSprite *)bits->objectAtIndex(1))->setTextureRect(CCRectMake(234,0,26,31));
- }
- temp = (mark % 1000) / 100;
再来看下萝莉类GameObjHero.cpp
首先在void GameObjHero::onEnter()方法里初始化。
接受触摸:
pDirector->getTouchDispatcher()->addTargetedDelegate(this, 0, true);
初始化萝莉:
- mainsprite = CCSprite::create("s_1.png");
- //动画
- CCAnimation * animation = CCAnimation::create();
- animation->addSpriteFrameWithFileName("s_1.png");
- animation->addSpriteFrameWithFileName("s_2.png");
- animation->addSpriteFrameWithFileName("s_3.png");
- animation->addSpriteFrameWithFileName("s_4.png");
- animation->addSpriteFrameWithFileName("s_5.png");
- animation->addSpriteFrameWithFileName("s_6.png");
- animation->setDelayPerUnit(0.1f);
- animation->setRestoreOriginalFrame(true);
- //运行奔跑动画
- mainsprite->runAction(CCRepeatForever::create(CCAnimate::create(animation)));
上面这种添加动画的方式,是骨头第一次遇到。
首先创建CCAnimation,然后设置每一帧的图片,然后设置每帧的延迟时间,设置播放完动画后是否回到第一帧。
然后是构造一个循环播放的CCRepeatForever动画,添加到精灵上。
里面有个设置状态方法:
- switch(state){
- case 1://跳跃
- this->stopAllActions();
- mainsprite->stopAllActions();
- mainsprite->setTexture(jump);
- this->runAction(CCSequence::create(CCJumpBy::create(2.5,ccp(0,0),100,1),CCCallFunc::create(this, callfunc_selector(GameObjHero::jumpend)),NULL));
- break;
- case 2://受伤
- this->stopAllActions();
- mainsprite->stopAllActions();
- mainsprite->setTexture(hurt);
- this->runAction(CCSequence::create(CCBlink::create(3, 10),CCCallFunc::create(this, callfunc_selector(GameObjHero::hurtend)),NULL));
- ((GameMain *)this->getParent())->setover();
- break;
跳跃,则运行CCJumpBy动画,受伤则运行CCBlink动画,就是一闪一闪的,并且在动画结束分别调用相应的方法。
然后是GameObjMap.cpp地图类
- void GameObjMap::bg1change(){
- //运动出屏幕重设位置,运动
- CCSprite * bg = (CCSprite *)this->getChildByTag(0);
- bg->setPosition(ccp(480,320));
- bg->runAction(CCSequence::create(CCMoveBy::create(4,ccp(-960,0)),CCCallFunc::create(this, callfunc_selector(GameObjMap::bg1change)),NULL));
- for(int i = 0;i < 5;i ++){
- ((GameObjStar *)stars1->objectAtIndex(i))->set_visable(true);
- }
- }
- void GameObjMap::bg2change(){
- //运动出屏幕重设位置,运动
- CCSprite * bg = (CCSprite *)this->getChildByTag(1);
- bg->setPosition(ccp(480,320));
- bg->runAction(CCSequence::create(CCMoveBy::create(4,ccp(-960,0)),CCCallFunc::create(this, callfunc_selector(GameObjMap::bg2change)),NULL));
- for(int i = 0;i < 5;i ++){
- ((GameObjStar *)stars2->objectAtIndex(i))->set_visable(true);
- }
- }
楼上两个方法作用是背景循环,callfunc_selector方法调用的是对方,一对好机油!
- bg1->runAction(CCSequence::create(CCMoveBy::create(2,ccp(-480,0)),CCCallFunc::create(this, callfunc_selector(GameObjMap::bg1change)),NULL));
- bg2->runAction(CCSequence::create(CCMoveBy::create(4,ccp(-960,0)),CCCallFunc::create(this, callfunc_selector(GameObjMap::bg2change)),NULL));
其实整个背景地图的宽度是两倍的可视屏幕宽度,即480*2=960,这样的地图有两套,两套地图的动画在第一次运行时正好差半个周期,而且是互相调用,呈现出来的效果就是一直循环下去。恩,懂了。
然后在两套地图上绘制植物、草地等元素。
最后是核心逻辑类:GameMainScene.cpp
首先在初始化方法里,把游戏的所有元素都实例化一下,比如萝莉,比如地图,比如分数星星等。
最主要的循环方法:
- scheduleUpdate();
- void GameMain::update(float time){}
在update里面判断是否跟星星相撞,
- bool GameMain::isCollion(CCPoint p1,CCPoint p2,int w1,int h1,int w2,int h2){
- if(abs(p1.x - p2.x) < w1 + w2 && abs(p1.y - p2.y) < h1 + h2){
- return true;
- }
- return false;
- };
判断是否是掉落状态:
- void GameMain::isherodrop(){
- CCPoint p1 = (map->getChildByTag(0))->getPosition();
- CCPoint p2 = (map->getChildByTag(1))->getPosition();
- int temp;
- if(p1.x <= 100 && (p1.x + 480) >= 100){
- temp = (100 - p1.x) / 64;
- if(bg1shu[temp] == -1){
- hero->setState(2);
- }
- }else{
- temp = (100 - p2.x) / 64;
- if(bg2shu[temp] == -1){
- hero->setState(2);
- }
- }
- }
上面方法比较难懂,大意就是根据当前地图的x值位置,来取得主角所站的位置有没有石头,没有的话即掉落。
- temp = (100 - p1.x) / 64;
100是因为萝莉站在x=100的位置,所以要得到萝莉所在位置是否为空,即
- bg2shu[temp] == -1
地图是这样添加的
//星星,植物等大图素的添加
for(int i = 0;i < 7;i ++){ //960/8=120
也就是说在960像素宽度的背景图上,可以放8个宽度等于120的元素。
static const short bg1shu[] = {-1,1,0,2,-1,1,2,3};
static const short bg2shu[] = {3,3,-1,3,-1,3,3,-1};
然后根据 数组的值来放置元素,-1时为空。
本篇完结
好了,《萝莉快跑》的例子到此算是消化了大部分了。
看3遍不如自己动手敲1遍,赶紧去噼里啪啦一下吧:)
大家晚安。
Cocos2dx系列笔记7:一个简单的跑酷游戏《萝莉快跑》的消化(附下载)的更多相关文章
- 用Qt写软件系列三:一个简单的系统工具(上)
导言 继上篇<用Qt写软件系列二:QIECookieViewer>之后,有一段时间没有更新博客了.这次要写的是一个简单的系统工具,需求来自一个内部项目.功能其实很简单,就是查看当前当前系统 ...
- [Ruby on Rails系列]6、一个简单的暗语生成器与解释器(上)
[0]Ruby on Rails 系列回顾 [Ruby on Rails系列]1.开发环境准备:Vmware和Linux的安装 [Ruby on Rails系列]2.开发环境准备:Ruby on Ra ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- 无聊的人用JS实现了一个简单的打地鼠游戏
直入正题,用JS实现一个简单的打地鼠游戏 因为功能比较简单就直接裸奔JS了,先看看效果图,或者 在线玩玩 吧 如果点击颜色比较深的那个(俗称坏老鼠),将扣分50:如果点击颜色比较浅的那个(俗称好老鼠) ...
- Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏
Unity 2D游戏开发高速入门第1章创建一个简单的2D游戏 即使是如今,非常多初学游戏开发的同学.在谈到Unity的时候.依旧会觉得Unity仅仅能用于制作3D游戏的. 实际上.Unity在2013 ...
- Cocos2d-x开发教程——《萝莉快跑》
更好的阅读体验请前往<萝莉快跑>开发教程. 配置:win7+Cocos2d-x.2.0.3+VS2012 目标读者:已经了解图形显示.动作.回调函数.定时器的用法. 一.基本知识点 1.动 ...
- cocos2dx系列笔记(1)- windows环境配置前篇
cocos2dx升级之旅,请多指教~ 本篇是本人搭建cocos2dx-Windows 64位环境的配置说明,仅供参考. 开发准备 搭建环境肯定需要准备好所有工具,只有把工具都准备好了,才能撸起袖子干活 ...
- VS Extension+NVelocity系列(一)——构建一个简单的NVelocity解析环境
一.前言 本节我们将实际实现一个简单的NVelocity解析环境,以便为以后的实例做一些基本工作,虽然NVelocity如何使用已经属于老掉牙的话题,但我只能专门挑出来一章来做铺垫.人生就是这样无奈啊 ...
- ADF_General JSF系列1_创建一个简单的JSF Application
2015-02-17 Creatd By BaoXinjian
随机推荐
- Python之路:迭代器和yield生成器
一.迭代器 对于Python 列表的 for 循环,他的内部原理:查看下一个元素是否存在,如果存在,则取出,如果不存在,则报异常 StopIteration.(python内部对异常已处理) 使用迭代 ...
- [WPF疑难]避免窗口最大化时遮盖任务栏
原文 [WPF疑难]避免窗口最大化时遮盖任务栏 [WPF疑难]避免窗口最大化时遮盖任务栏 周银辉 WPF窗口最大化时有个很不好的现象是:如果窗口的WindowStyle被直接或间接地设置为None后( ...
- Java学习之链表
数据结构学了,java实现下 package com.gh.Link; /** * 链表的实现 * @author ganhang * */ public class Links { public s ...
- Linux下批量转换文件编码
find -iname "*.java" -exec enca {} + |grep -v ASCI |grep -v -i utf |awk -F':' '{print $1}' ...
- 暂时和永久改动oracle sysdate的默认输出格式
1.当前会话有效 alter session set NLS_DATE_FORMAT='YYYY-MM-DD:HH24:MI:SS'; 2.永久生效 sys用户登入后运行例如以下命令 然后重新启动数据 ...
- Remoting简单实践
一句话概括 remoting是微软的一种实现在不同的.net应用程序中进行分布式通信的技术 重要概念 原理大致是首先客户端通过remoting通道来获取服务器对象代理,通过序列化与反序列方式实现数据交 ...
- c#中的委托使用(方法的调用, 和类的实话)
方法的调用 delegate int test1(int a); class Program { static int num = 10; static void Main(string[] args ...
- 【Eclipse】离线插件安装
1.在eclipse里根目录里,dropins里建一个目录,名字叫sonar(这个名字随便),再在svn下面建一个目录eclipse.在根目录里建一个目录links目录,并建一个sonar.link文 ...
- Tomcat日志catalina.out文件过大的处理方法
原文地址:http://lcbk.net/tomcat/1396.html 我们知道一般企业使用Tomcat 作为Web端时,它产生的日志会越来越大,特别是catalina.out这个日志文件,然而有 ...
- BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
做一次MST, 枚举不在最小生成树上的每一条边(u,v), 然后加上这条边, 删掉(u,v)上的最大边(或严格次大边), 更新答案. 树链剖分然后ST维护最大值和严格次大值..倍增也是可以的... - ...