• Cocos2d-X 3D跑酷游戏

    2020-06-03 23:31:18
    Cocos2d-X 3D跑酷游戏,包含游戏完整代码demo和游戏运行的录制视频,可直接使用。
  • 看了泰然论坛的跑酷,教程很详细,代码也很清晰,不过是JS版的。 上次我也重写过他们的...泰然的跑酷代码连cocos2d-x2.1.5的引擎代码都一起打包了,这样方便大家直接调试,不需要自己再另建工程,避免引擎版本不一

    原创,转载请注明出处:http://blog.csdn.net/dawn_moon/article/details/21229369


    看了泰然论坛的跑酷,教程很详细,代码也很清晰,不过是JS版的。


    上次我也重写过他们的雷电,不过由于比较忙,当时也没有专职做游戏就没有写详细的教程。这次我想按照他们的思路重写一下,写个详细的系列教程。然后写个Lua版的,希望对还没有入门的开发者有帮助。


    泰然的跑酷代码连cocos2d-x2.1.5的引擎代码都一起打包了,这样方便大家直接调试,不需要自己再另建工程,避免引擎版本不一致对新手造成困扰。我重写完之后,也会原地打包,方便大家调试。


    原地打开Parkour工程,可以看到工程结构,游戏逻辑全在Resources分组下面,如下:


    入口是MainScene.js文件,这个文件做了三件事,构建开始画面,一张背景,一个按钮,预加载音效文件。

    好了,我们开始写C++版的MainScene:

    //
    //  MainScene.h
    //  Parkour
    //
    //  Created by lerry on 14-3-13.
    //  Copyright (c) 2014年 Goonear Co.,Ltd. All rights reserved.
    //
    
    #ifndef __Parkour__MainScene__
    #define __Parkour__MainScene__
    
    #include "cocos2d.h"
    #include "resources.h"
    
    class MainScene : public cocos2d::CCLayer
    {
    private:
        void onPay();
        
        void preloadMusic();
        
    public:
        virtual bool init();
        
        static cocos2d::CCScene* scene();
        
        CREATE_FUNC(MainScene);
        
        
    };
    
    
    #endif /* defined(__Parkour__MainScene__) */
    
    实现文件:

    //
    //  MainScene.cpp
    //  Parkour
    //
    //  Created by lerry on 14-3-13.
    //  Copyright (c) 2014年 Goonear Co.,Ltd. All rights reserved.
    //
    
    #include "MainScene.h"
    #include "SimpleAudioEngine.h"
    
    USING_NS_CC;
    using namespace CocosDenshion;
    
    CCScene* MainScene::scene()
    {
        CCScene* scene = CCScene::create();
        CCLayer* layer = MainScene::create();
        scene->addChild(layer);
        return scene;
    }
    
    
    
    bool MainScene::init()
    {
        if (!CCLayer::init()) {
            return false;
        }
        // 预加载音乐文件
        preloadMusic();
        
        CCSize winsize = CCDirector::sharedDirector()->getWinSize();
        CCPoint center = ccp(winsize.width / 2, winsize.height / 2);
        
        CCSprite* spriteBg = CCSprite::create("MainBG.png");
        spriteBg->setPosition(center);
        this->addChild(spriteBg);
        
        // 这里的菜单是用图片,setFontSize貌似没用啊
        CCMenuItemFont::setFontSize(60);
        // 和js版参数顺序不一样
        CCMenuItemSprite* menuItem = CCMenuItemSprite::create(CCSprite::create("start_n.png"), CCSprite::create("start_s.png"), this, menu_selector(MainScene::onPay));
        
        // 必须以NULL结尾
        CCMenu* menu = CCMenu::create(menuItem, NULL);
        menu->setPosition(center);
        this->addChild(menu);
        
        return true;
    }
    
    void MainScene::preloadMusic()
    {
        SimpleAudioEngine* audioEngine = SimpleAudioEngine::sharedEngine();
        audioEngine->preloadBackgroundMusic(backmusic);
        audioEngine->preloadEffect(jummpmusic);
        audioEngine->preloadEffect(crouch);
        
    }
    
    // start按钮回调
    void MainScene::onPay()
    {
        CCLog("onPlay click");
    }
    

    预加载音效的函数里面的参数我做了处理,我习惯将所有的资源文件写到一个头文件里面resources.h

    //
    //  resources.h
    //  Parkour
    //
    //  Created by lerry on 14-3-13.
    //  Copyright (c) 2014年 Goonear Co.,Ltd. All rights reserved.
    //
    
    #ifndef Parkour_resources_h
    #define Parkour_resources_h
    
    static const char backmusic[] = "background.mp3";
    
    static const char jummpmusic[] = "jump.mp3";
    
    static const char crouch[] = "crouch.mp3";
    
    #endif
    
    这个开始场景写好了以后需要替换JS版的场景,修改AppDelegate.cpp

    include 一下MainScene.h

    然后修改实现,看代码片段

        // set searching path
        CCFileUtils::sharedFileUtils()->setSearchPaths(searchPath);
        
        // turn on display FPS
        pDirector->setDisplayStats(true);
        
        // set FPS. the default value is 1.0/60 if you don't call this
        pDirector->setAnimationInterval(1.0 / 60);
        
    //    ScriptingCore* sc = ScriptingCore::getInstance();
    //    sc->addRegisterCallback(register_all_cocos2dx);
    //    sc->addRegisterCallback(register_all_cocos2dx_extension);
    //    sc->addRegisterCallback(register_all_cocos2dx_extension_manual);
    //    sc->addRegisterCallback(register_cocos2dx_js_extensions);
    //    sc->addRegisterCallback(register_CCBuilderReader);
    //    sc->addRegisterCallback(jsb_register_chipmunk);
    //    sc->addRegisterCallback(jsb_register_system);
    //    sc->addRegisterCallback(JSB_register_opengl);
    //    sc->addRegisterCallback(MinXmlHttpRequest::_js_register);
    //    sc->addRegisterCallback(register_jsb_websocket);
    //
    //    sc->start();
    //    
    //    CCScriptEngineProtocol *pEngine = ScriptingCore::getInstance();
    //    CCScriptEngineManager::sharedManager()->setScriptEngine(pEngine);
    //    ScriptingCore::getInstance()->runScript("MainScene.js");
        
        // C++的场景实现
        CCScene *scene = MainScene::scene();
        pDirector->runWithScene(scene);
        
        return true;



    将绑定JS的代码注释掉,加入C++的场景。然后跑起来,看到如下画面,第一步就成功了。



    展开全文
  • 最近在看龙灵修的跑酷游戏视频教程。然后自己跟着做跑酷游戏。 可是发现没有图片资源,导致做起来总感觉不对劲。 于是花了点时间,整理了网上的一些素材。主要从中提取的地图。 使用于TiledMap, 每个瓦片以32,64...

    最近在看龙灵修的跑酷游戏视频教程。然后自己跟着做跑酷游戏。

    可是发现没有图片资源,导致做起来总感觉不对劲。

    于是花了点时间,整理了网上的一些素材。主要从<彩虹岛>中提取的地图。

    使用于TiledMap, 每个瓦片以32,64分割都行。

    花了几个小时整理的… 希望对大家有所帮助。

    先上传2张效果图,其他的可以到我给出的链接里面下载。

    (注意:素材来自网上…  仅供自己学习使用)

    ps: 素材下载需要csnd积分5分,如果没有的话,可以留下邮箱。我会单独发送。

    下载链接:http://download.csdn.net/detail/hitwhylz/6910095







    学习的路上,与君共勉。

    展开全文
  • Cocos2dx】跑酷游戏

    2015-11-01 12:19:16
    下面将用Cocos2dx完成一个跑酷游戏跑酷游戏从头到尾包括美工完全可以一个人完成,就是比较耗费时间,只能达到能玩的程度而已。 做出来的跑酷游戏如下所示: 玩家能做的就只有一个动作,触摸屏幕,触摸屏幕...

    下面将用Cocos2dx完成一个跑酷游戏,跑酷游戏从头到尾包括美工完全可以一个人完成,就是比较耗费时间,只能达到能玩的程度而已。

    做出来的跑酷游戏如下所示:


    玩家能做的就只有一个动作,触摸屏幕,触摸屏幕之后,游戏的主角,就是黑色的方块,能够向上跳跃,再次触摸就能够二段跳,

    而在屏幕右上方则有不停发射的箭矢,玩家控制的黑色方块被射中,则会掉10滴血,从1000血可以扣,扣到0则游戏自动重新开始。在屏幕的左上方与中上部有当前的血量显示,而右上角是分数,玩家能撑住,躲过箭矢,分数就会增加。

    左下与右下是必须提供的两个功能,一个是暂停游戏,一个是退出游戏,这些小游戏就不提供保存了……(其实,主要是笔者太菜,Cocos2dx的关卡功能与保存功能还有待研究,不会做的缘故。)

    一、基本准备

    好,游戏大致是这样的情况。在开始游戏之前,我们先要利用(cocos2d-x-2.2.6安装目录)\tools\project-creator下的create_project.py用python命令创建一个名为RunGame的工程。具体是用命令行进入到此文件夹,利用如下命令,新建工程

    python create_project.py -project Rungame -package test.Rungame -language cpp

    之后准备素材到RunGame的资源文件夹Resource中,上述游戏用到了如下的素材:


    1、图片准备

    除了各种自带的素材,下面说说每一张图片是如何自己用WIN7画图搞出来的。

    首先是关于血条的1.png,就是一张1x1的图片,自己在画图的属性调出一张1x1的图片,之后保存即可。


    kuang.png,之后是框,同时用于血条与按钮,具体是用画图的圆角矩形工具一拖就有了,属性设置为100x25像素


    hp_full.png,最后是满血状态的血条,是在kuang.png上面加工,用刷子工具,涂上两涂就可以了。大小同上。


    至于为什么要这样整,具体可以参考我之前的《【Cocos2dx】利用音量螺旋控件控制血量条 》(点击打开链接

    接着是背景backgroud.png,就是利用画图的三角形工具与直线工具,加文字工具弄出来的,唯一注意到的是要适配游戏的屏幕大小,在480x320的像素上创作。


    player.png直接将属性设置为40x40,用黑色一填充就完事。


    kuang_fan.png,是根据kuang.png用画图的反色工具,一整就出来了。


    最后是,稍微有点复杂的是array.png,用画图的直线工具搞出来之后,还要通过photoshop将array.png白色的部分扣出来搞成透明,当然,不整也可以,只是在游戏运行的时候不美观而已。

    2、strings.xml,具体如下,原理同《【Cocos2dx】中文乱码问题》(点击打开链接),主要防止乱码。

    <dict>
        <key>fanhui</key>
        <string>返回</string>
        <key>xueliang</key>
        <string>血量:</string>
        <key>fenshu</key>
        <string>分数:</string>
        <key>zanting</key>
        <string>暂停</string>
        <key>tuichu</key>
        <string>退出</string>
    </dict>

    二、工程制作

    之后就可以开始工程的制作了,整个工程的UML大致如下:


    先提醒大家注意,新建的类一定要放在Classes这个文件夹,如果放在proj.win32就悲剧了,这个我在《【Cocos2dx】新建场景、场景的切换、设置启动场景与菜单的新建》(点击打开链接)中已经提到过了,不在赘述。

    先来说两个处于次要地位的类。

    首先是飘字类FlowWord,这个类完全与《【Cocos2dx】飘字特效与碰撞检测》(点击打开链接)原理一样,只是改了把字体的颜色从黄色改成红色而已。

    FlowWord.h:

    #include "cocos2d.h"
    
    USING_NS_CC;  
      
    class FlowWord:public CCNode{  
    public:  
        void showWord(const char* text,CCPoint pos);//飘字方法,text为飘字的内容,pos为飘字的位置  
    private:  
        CCLabelTTF* label;//类成员  
        void flowEnd();//飘字结束时的回调(处理)函数,主要用于删除自己      
    };

    FlowWord.cpp:

    #include "FlowWord.h"
    
    void FlowWord::showWord(const char* text, CCPoint position){//text为飘字的内容,pos为飘字的位置  
    	/*初始化*/  
    	label=CCLabelTTF::create(text,"Arial",18);//创建一个字体为Arial,字号为18,内容为text的CCLabelTTF,也就是标签文本  
    	label->setColor(ccc3(255,0,0));//设置其颜色为红色
    	label->setPosition(position);//设置其位置  
    	this->addChild(label);//在场景上添加这个标签文本  
    	/*三个动作,放大->移动->缩小*/     
    	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等       
    	CCFiniteTimeAction* action1=CCScaleTo::create(0.2f,3.0f,3.0f);//0.2s内在x、y上方向皆放大为原尺寸的3倍  
    	CCFiniteTimeAction* action2=CCMoveTo::create(0.3f,ccp(visibleSize.width/4,3*visibleSize.height/4));//在0.3s内,移动到坐标为(x=屏幕宽度的25%,y=屏幕高度的75%处)  
    	CCFiniteTimeAction* action3 = CCScaleTo::create(0.2f, 0.1f,0.1f);//之后在0.2s内在x、y上皆缩小为原尺寸的0.1倍  
    	CCCallFunc* callFunc = CCCallFunc::create(this, callfunc_selector(FlowWord::flowEnd));//声明一个回调(处理)函数,为FlowWord类中的flowEnd()  
    	CCFiniteTimeAction* action = CCSequence::create(action1,action2,action3,callFunc, NULL);//以上的所有动作组成动作序列action  
    	/*对label实行action这个动作*/  
    	label->runAction(action);  
    }  
    
    void FlowWord::flowEnd(){//动作结束,从父节点中删除自身  
    	label->setVisible(false);//先隐藏显示  
    	label->removeFromParentAndCleanup(true);//再删除  
    }  

    之后是暂停场景PauseScene,这个原理也在《【Cocos2dx】利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能》(点击打开链接)讲过,不再赘述了。

    PauseScene.h:

    #include "cocos2d.h"  
    #include "cocos-ext.h" //使用按钮事件,必须要需要的头文件  
    USING_NS_CC_EXT;//使用按钮事件,必须要需要的命名空间    
    using namespace cocos2d;  
      
    class PauseScene:public CCLayer{  
    public:  
        static CCScene* scene();  
        virtual bool init();  
        CREATE_FUNC(PauseScene);  
        void back(CCObject* pSender,CCControlEvent event);//返回场景  
    };  

    PauseScene.cpp:

    #include "PauseScene.h"  
    
    USING_NS_CC;  
    
    CCScene* PauseScene::scene()  
    {  
    	CCScene *scene=CCScene::create();    
    	PauseScene* pauseScene=PauseScene::create();  
    	scene->addChild(pauseScene);  
    	return scene;    
    }  
    
    bool PauseScene::init()  
    {  
    	//获取屏幕的尺寸、位置信息等      
    	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();    
    
    	/*通过载入strings.xml的中文,防止乱码*/
    	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
    	const char *fanhui = ((CCString*)strings->objectForKey("fanhui"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string
    
    	//声明按钮部分    
    	cocos2d::extension::CCScale9Sprite *btn_noraml=cocos2d::extension::CCScale9Sprite::create("kuang_fan.png");//声明按钮没被按下时的背景图片    
    	CCLabelTTF *label1=CCLabelTTF::create(CCString::createWithFormat("%s",fanhui)->getCString(),"arial",36);//声明第1个参数是文字的内容,第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
    	CCControlButton *controlButton=CCControlButton::create(label1,btn_noraml);//创建按钮
    	controlButton->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));//按钮的位于屏幕的中央    
    	controlButton->addTargetWithActionForControlEvents(this, cccontrol_selector(PauseScene::back), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的PauseScene::back(){}中所有代码。    
    	this->addChild(controlButton);//将此按钮添加到场景,默认不自动添加      
    	return true;  
    }  
    
    
    void PauseScene::back(CCObject* pSender,CCControlEvent event)    
    {  
    	//本场景出栈  
    	CCDirector::sharedDirector()->popScene();  
    }  

    接下来比较重要的两个主角,一个玩家类,一个是怪物类:

    首先是怪物类Monster,也就是那些箭矢,一只怪物很简单,声明好其开始位置、图片即可,到时候其产生与击中玩家、飞出屏幕外围的方法,在MainScene这个主场景类中控制。唯一注意的是暴露出CCSprite* sprite;自身精灵类与是否处于屏幕的标识bool isEmerge给主场景类MainScene控制。

    Monster.h:

    #include "cocos2d.h"
    USING_NS_CC;//用到了CCxx,比如CCNode
    
    class Monster:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNode
    public:
    	Monster();//构造函数
    	CCSprite* sprite;
    	bool isEmerge;//是否处于屏幕的标识
    };
    
    Monster.cpp:

    #include "Monster.h"
    Monster::Monster(){
    	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    	sprite=CCSprite::create("array.png");//使用CloseSelected.png这张图片
    	sprite->setScale(0.5f);
    	sprite->setPosition(ccp(5*visibleSize.width/6+CCRANDOM_0_1()*visibleSize.width/6,5*visibleSize.height/6+CCRANDOM_0_1()*visibleSize.height/6));
    	this->addChild(sprite);//添加到舞台
    	isEmerge=true;//开始为已经出现状态
    }

    随后是玩家类Player,要完成的事情是三件,一个在玩家的构造函数,设置其初始诞生的位置、自身拥有的属性等;二是,其跳跃与二段跳跃具体是怎么实现的,原理与《【Cocos2dx】精灵触摸跳跃功能》(点击打开链接)一模一样,这里不再赘述了,二段跳跃只是在此基础上加深,具体见下面代码的注释;最后是被箭矢击中,怎么做什么动作的hit(),主要就是调用FlowWord的showword()飘字,扣血除自身的hp10点。

    Player.h,暴露jump()这个方法给主场景类MainScene,主场景类的触摸事件直接调用这个方法即可。hit()、hp、score都要暴露给主函数所操作、修改、判断、执行:

    #include "cocos2d.h"
    #include "FlowWord.h"
    USING_NS_CC;//用到了CCxx,比如CCNode
    
    class Player:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNode
    public:
    	Player();//构造函数	
    	void jump();//跳跃
    	CCSprite* sprite;
    	void hit();//被击中的处理函数
    	float score;//当前得分
    	int hp;//当前血量
    private:	
    	bool isJumping;//是否跳跃的flag
    	void doubleJump();//二段跳的实现
    	void jumpEnd();//声明跳跃结束的回调函数
    	bool isDoubleJumping;//是否二段条的flag
    	void doubleJumpEnd();//声明二段条结束的回调函数
    };
    

    Player.cpp:

    #include "Player.h"
    /*构造函数,也就是初始化的函数*/
    Player::Player(){
    	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    	sprite=CCSprite::create("player.png");//使用CloseSelected.png这张图片
    	sprite->setPosition(ccp(visibleSize.width/3, visibleSize.height/6));//放在屏幕大小的(1/3,1/6)这个位置
    	this->addChild(sprite);//添加到舞台
    	isJumping=false;//开始为没有跳跃状态
    	isDoubleJumping=false;
    	score=0;
    	hp=1000;
    }
    
    /*被击中之后的动作*/
    void Player::hit(){
    	FlowWord* flowWord=new FlowWord();//初始化FlowWord  
    	this->addChild(flowWord);//将FlowWord飘字特效放上舞台,尽管飘字特效,一不是精灵,二在showWord中同样有将字体放上舞台的代码,然而没有这一句,HelloWorldScene这个场景根本不会与FlowWord联系起来,也就是FlowWord中添加的Label根本无法在HelloWorldScene中显示。  
    	flowWord->showWord("-10",sprite->getPosition());//执行飘字-10,位置从自身位置开始。 
    	hp-=10;
    }
    
    /*跳跃*/
    void Player::jump(){ 
    	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    	if(!isJumping){//如果主角还在跳跃中,则不重复执行
    		isJumping=true;//标记主角为跳跃状态     
    		CCJumpBy* jump=CCJumpBy::create(1.0f,ccp(0,0),visibleSize.height/2,1);//在2.0秒内,先跳起屏幕尺寸的1/2再落下0px,该动作重复1次
    		CCCallFunc* callFunc=CCCallFunc::create(this, callfunc_selector(Player::jumpEnd));//创建回调函数,声明跳跃结束后调用jumpEnd函数
    		CCActionInterval* jumpActions=CCSequence::create(jump, callFunc, NULL);//将回调函数与跳跃动作结合起来,这个NULL不能省 
    		sprite->runAction(jumpActions);//执行动作
    	}
    	else{//如果是在跳跃
    		if(isDoubleJumping){//判断是否在二段跳
    			return;//否则不能二段跳
    		}
    		else{//如果不是,则可以二段跳
    			doubleJump();
    		}
    	}
    };   
    
    void Player::jumpEnd(){//主角已经完成跳跃了  
    	isJumping=false;//标志主角为没有跳跃状态
    	isDoubleJumping=false;
    }  
    
    /*二段跳跃*/
    void Player::doubleJump(){ 
    	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    	isDoubleJumping=true;//标记主角为跳跃状态     
    	CCJumpBy* double_jump=CCJumpBy::create(0.5f,ccp(0,0),visibleSize.height/3,1);//在2.0秒内,先跳起屏幕尺寸的1/2再落下0px,该动作重复1次
    	CCCallFunc* callFunc=CCCallFunc::create(this, callfunc_selector(Player::doubleJumpEnd));//创建回调函数,声明跳跃结束后调用jumpEnd函数
    	CCActionInterval* jumpActions=CCSequence::create(double_jump, callFunc, NULL);//将回调函数与跳跃动作结合起来,这个NULL不能省 
    	sprite->runAction(jumpActions);//执行动作
    };   
    
    
    void Player::doubleJumpEnd(){//主角已经完成二段跳跃了  
    	isDoubleJumping=false;//标志主角为没有二段跳跃状态
    }  

    最后是整个程序的核心、入口,主函数类MainScene,

    1、首先因为用到了音乐资源,所以先给这个类如同《【Cocos2dx】资源文件夹,播放背景音乐,导入外部库》(点击打开链接)一样,引入cocos2dx的音频引擎,否则SimpleAudioEngine.h会被说是找不到这个类,编译错误

    2、Cocos2dx中文的使用请看《【Cocos2dx】中文乱码问题》(点击打开链接

    3、滚动背景的实现请看《【Cocos2dx】连续滚动的场景》(点击打开链接

    4、血条的使用请看《【Cocos2dx】利用音量螺旋控件控制血量条 》(点击打开链接

    5、按钮的使用请看《【Cocos2dx】使用CCControlButton创建按钮、按钮点击事件,点击事件中的组件获取,setPosition的坐标问题 》(点击打开链接

    6、关于两只精灵如何的碰撞检测的,请看《【Cocos2dx】飘字特效与碰撞检测》(点击打开链接

    7、暂停游戏、退出游戏等请看《【Cocos2dx】利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能》(点击打开链接

    8、关键在与箭矢的产生、也就是怪物的产生,大家可以看到上面介绍过的怪物类,通过主场景类中的init的new方法,执行怪物的构造函数,怪物将产生如下图的在右上角的区域,区域的控制,核心在设置了一个固定位置再加上一个随机数。


    之后,我们将这一个一个类的指针压入一个类指针数组,在Java就是将类压入一个ArrayList,在这C++中可以清晰地看到实质是在操作类的指针。

    当然这扯远了,回到正题,主场景类中的update即时更新函数,这个类指针数组被不停地遍历,被不停地操作。不停地判断箭矢,是否碰到玩家、是否已经飞出屏幕,对碰到玩家、飞出屏幕的箭矢,重新将其位置搞出其原来产生的地方,同时记得更改其出现标识与显示与否。

    触摸事件只放一个Player类的jump函数就可以了,当用户触摸屏幕之时,则不停地执行jump(),但是,我们已经在Player实现了封装,判断好此时主角是处于什么状态,该怎么操作了。

    具体见下面的代码的注释,欢迎交流。

    MainScene.h:

    #include "cocos2d.h"
    #include "Player.h"
    #include "Monster.h"
    #include "cocos-ext.h"//血条
    #include "SimpleAudioEngine.h"//BGM
    
    #include "PauseScene.h"
    
    USING_NS_CC; //用到了CCxx,比如CCNode
    using namespace cocos2d::extension;//血条
    
    #define MAX_MONSTER_NUM 2//怪物最大数量
    
    class MainScene:public cocos2d::CCLayer
    {
    public:
    	/*场景创建必须的函数*/
    	static cocos2d::CCScene* scene();
    	CREATE_FUNC(MainScene);	
    	virtual bool init();//场景初始化函数
    	virtual void update(float delta);//即使更新事件
    private:
    	CCLabelTTF* label_upper_left;//左上角文字
    	CCLabelTTF* label_upper_right;//右上角文字	
    	void ccTouchesBegan(CCSet *pTouches, CCEvent *pEvent);//触摸事件的函数声明,开始触摸屏幕的瞬间则触发此事件  
    	Player* player;//主角类
    	Monster* monster;//怪物类
    	CCControlSlider *controlSlider;//血条
    	//添加两个背景精灵,作为背景用,实质上就是同一张图片放上二个不同的背景精灵
    	CCSprite* bgSprite1;  
    	CCSprite* bgSprite2;
    
    	Monster* monster_arr[10];//存放怪物的数组
    
    	void close(CCObject* pSender,CCControlEvent event);//关闭  
    	void pause(CCObject* pSender,CCControlEvent event);//暂停
    };
    

    MainScene.cpp:

    #include "MainScene.h"
    
    CCScene* MainScene::scene()//必须存在的场景建立函数
    {
    	CCScene *scene = CCScene::create();
    	MainScene *layer = MainScene::create();
    	scene->addChild(layer);
    	return scene;
    }
    
    /*初始化*/
    bool MainScene::init(){
    
    	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    
    	/*BGM*/
    	CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Kalimba.mp3",true);//播放音乐,BGM是Kalimba.mp3这首难听的歌,而且是洗脑循环
    
    	/*事件声明*/
    	this->setTouchEnabled(true);//声明这个场景是存在触摸事件的
    	this->scheduleUpdate();//声明这个场景是存在即使更新事件的
    
    	/*通过载入strings.xml的中文,防止乱码*/
    	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
    	const char *xueliang = ((CCString*)strings->objectForKey("xueliang"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string
    	const char *fenshu = ((CCString*)strings->objectForKey("fenshu"))->m_sString.c_str();//读取fenshu键中的值,objectForKey会根据key,获取对应的string
    	const char *zanting = ((CCString*)strings->objectForKey("zanting"))->m_sString.c_str();//读取zanting键中的值,objectForKey会根据key,获取对应的string
    	const char *tuichu = ((CCString*)strings->objectForKey("tuichu"))->m_sString.c_str();//读取tuichu键中的值,objectForKey会根据key,获取对应的string
    
    	/*背景*/
    	bgSprite1=CCSprite::create("background.png");  
    	bgSprite1->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));
    	this->addChild(bgSprite1,0);//将此控件添加到场景,层次为0,最底部 
    
    	bgSprite2=CCSprite::create("background.png");  
    	bgSprite2->setPosition(ccp(visibleSize.width+visibleSize.width/2,visibleSize.height/2));
    	this->addChild(bgSprite2,0);//将此控件添加到场景,层次为0,最底部
    
    	/*文字声明*/
    	label_upper_left=CCLabelTTF::create(CCString::createWithFormat("%s%d",xueliang,1000)->getCString(),"arial",36);
    	label_upper_left->setAnchorPoint(ccp(0,1));//设置label的中心点在左上角
    	label_upper_left->setPosition(ccp(0,visibleSize.height));//把中心点摆在屏幕的左上角
    	label_upper_left->setColor(ccc3(0,0,0));
    	this->addChild(label_upper_left,1);//添加此文字到场景中,层次为1
    
    	label_upper_right=CCLabelTTF::create(CCString::createWithFormat("%s%d",fenshu,0)->getCString(),"arial",36);
    	label_upper_right->setAnchorPoint(ccp(1,1));//设置label的中心点在左下角
    	label_upper_right->setPosition(ccp(visibleSize.width,visibleSize.height));//把中心点摆在屏幕的左下角
    	label_upper_right->setColor(ccc3(0,0,0));
    	this->addChild(label_upper_right,1);//添加此文字到场景中,层次为1
    
    	/*血条声明*/
    	controlSlider = CCControlSlider::create("kuang.png","hp_full.png","1.png");//第1个参数是血条没有被占据的部分的背景图片,第2是血条被占据的部分的背景图片,第3个参数是条件按钮。  
    	controlSlider->setAnchorPoint(ccp(0.5,1));//设置controlSlider的中心点在中上部
    	controlSlider->setPosition(ccp(visibleSize.width/2,visibleSize.height));//将此组件布置在中上部
    	//设置按钮最大、最小值的基准
    	controlSlider->setMinimumValue(0);  
    	controlSlider->setMaximumValue(1000);
    	controlSlider->setValue(1000);//设置按钮当前值  
    	controlSlider->setTouchEnabled(false);//本来CCControlSlider是供用户调节的,调节按钮是1.png,但是1.png是一张1x1的近乎看不到的图片,同时利用setTouchEnabled(false)将此按钮锁上,禁止用户调节  
    	this->addChild(controlSlider,1);//将此控件添加到场景,层次为1
    
    	/*右下角按钮*/  
    	CCScale9Sprite *btn_noraml3 = CCScale9Sprite::create("kuang.png");//声明按钮没被按下时的背景图片    
    	CCLabelTTF *label3 = CCLabelTTF::create(CCString::createWithFormat("%s",tuichu)->getCString(),"arial",36);//第1个参数是按钮的内容,第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
    	label3->setColor(ccc3(0,0,0));
    	CCControlButton *controlButton3 = CCControlButton::create(label3,btn_noraml3);    
    	controlButton3->setAnchorPoint(ccp(1,0));  
    	controlButton3->setPosition(ccp(visibleSize.width,0));  
    	controlButton3->addTargetWithActionForControlEvents(this, cccontrol_selector(MainScene::close), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的MainScene::close(){}中所有代码。    
    	this->addChild(controlButton3);//将此按钮添加到场景,默认不自动添加   
    
    
    	/*左下角按钮*/  
    	CCScale9Sprite *btn_noraml2 = CCScale9Sprite::create("kuang.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片    
    	CCLabelTTF *label2 = CCLabelTTF::create(CCString::createWithFormat("%s",zanting)->getCString(),"arial",36);//声明一个文字Refresh!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
    	label2->setColor(ccc3(0,0,0));
    	CCControlButton *controlButton2 = CCControlButton::create(label2,btn_noraml2);    	
    	controlButton2->setAnchorPoint(ccp(0,0));  
    	controlButton2->setPosition(ccp(0,0));  
    	controlButton2->addTargetWithActionForControlEvents(this, cccontrol_selector(MainScene::pause), CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的HelloWorld::restart(){}中所有代码。    
    	this->addChild(controlButton2);//将此按钮添加到场景,默认不自动添加    
    
    	/*精灵声明*/
    	player=new Player();//创建一个主角
    	this->addChild(player,2);//将主角注册到这个场景中,层次为2
    
    	/*怪物的产生*/
    	for(int i=0;i<MAX_MONSTER_NUM;i++){
    		monster=new Monster();	
    		this->addChild(monster,2);//将此控件添加到场景,层次为2
    		monster_arr[i]=monster;//保存怪物对象到类指针中,给即时更新事件update中处理。
    	}
    	return true;
    }
    
    /*碰撞检测,判断两只精灵是否相交的函数*/
    bool is_collision(CCSprite* sprite1,CCSprite* sprite2){  
    
    	//建立精灵1的矩形  
    	CCSize sprite_size1=sprite1->getContentSize();//求精灵的尺寸  
    	CCPoint sprite_position1=sprite1->getPosition();//求精灵的中心点坐标  
    	CCRect sprite_rect1=CCRectMake(//以精灵的中心点为中心点、以精灵的尺寸为宽与高,建立一个矩形。  
    		sprite_position1.x-sprite_size1.width/2,   
    		sprite_position1.y-sprite_size1.height/2,   
    		sprite_size1.width,   
    		sprite_size1.height);  
    	//建立精灵2的矩形,同理  
    	CCSize sprite_size2=sprite2->getContentSize();  
    	CCPoint sprite_position2=sprite2->getPosition();  
    	CCRect sprite_rect2=CCRectMake(  
    		sprite_position2.x-sprite_size2.width / 2,   
    		sprite_position2.y-sprite_size2.height / 2,   
    		sprite_size2.width,   
    		sprite_size2.height);
    	return sprite_rect1.intersectsRect(sprite_rect2);//如果是判断矩形与一个像素点则用Rect实例.containsPoint(像素点);这里是判断两个矩形是否相交  
    
    
    }
    
    /*触摸屏幕*/
    void MainScene::ccTouchesBegan(cocos2d::CCSet *pTouches, cocos2d::CCEvent *pEvent){
    	player->jump();//主角跳跃
    }
    
    /*即时更新事件*/
    void MainScene::update(float delta){
    	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
    	/*背景连续滚动*/
    	int posX1=bgSprite1->getPositionX();//背景地图1的x坐标  
    	int posX2=bgSprite2->getPositionX();//背景地图2的x坐标  
    
    	int iSpeed=1;//地图滚动速度  
    
    	//两张地图向左滚动,因为两张地图是相邻的,所以要一起滚动,否则会出现空隙。  
    	posX1-=iSpeed;  
    	posX2-=iSpeed; 
    
    	CCSize mapSize=bgSprite1->getContentSize();//地图大小  
    
    	//当第1个地图完全离开屏幕时,让第2个地图完全出现在屏幕上,同时让第1个地图紧贴在第2个地图后面  
    	if(posX1<-mapSize.width/2){  
    		posX2=mapSize.width/2;  
    		posX1=mapSize.width+mapSize.width/2;  
    	}  
    	//同理,当第2个地图完全离开屏幕时,让第1个地图完全出现在屏幕上,同时让第2个地图紧贴在第1个地图后面  
    	if(posX2<-mapSize.width/2){  
    		posX1=mapSize.width/2;  
    		posX2=mapSize.width+mapSize.width/2;  
    	}  
    
    	bgSprite1->setPositionX(posX1);  
    	bgSprite2->setPositionX(posX2);
    
    	/*通过载入strings.xml的中文,防止乱码*/
    	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
    	const char *xueliang = ((CCString*)strings->objectForKey("xueliang"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string
    	const char *fenshu = ((CCString*)strings->objectForKey("fenshu"))->m_sString.c_str();//读取fenshu键中的值,objectForKey会根据key,获取对应的string
    
    	player->score+=0.2;//不断给玩家加分
    	label_upper_right->setString(CCString::createWithFormat("%s%.0f",fenshu,player->score)->getCString());//改变右上角的标签文本
    
    
    	for(int i=0;i<MAX_MONSTER_NUM;i++){//时刻遍历怪物的类指针数组
    		monster=monster_arr[i];
    		if(monster->isEmerge) {//如果怪物处于屏幕内	
    			monster->sprite->setPosition(ccp(monster->sprite->getPositionX()-visibleSize.width/100,
    				monster->sprite->getPositionY()-visibleSize.height/100));//那么他们的位置将会移动当前屏幕宽度与高度的1/100
    			if(monster->sprite->getPositionX()<0|| monster->sprite->getPositionY()<0){//如果怪物x坐标小于0,则表示已经超出屏幕范围,隐藏怪物
    				monster->sprite->setVisible(false);//将其隐藏
    				monster->isEmerge=false;//设置为不在屏幕内
    			}
    			if (is_collision(player->sprite,monster->sprite)){//判断怪物是否碰撞玩家
    				monster->sprite->setVisible(false);//将其隐藏
    				player->hit();//玩家执行被撞击函数
    				monster->isEmerge=false;//设置为不在屏幕内		
    				controlSlider->setValue(player->hp);//改变中上部血条当前的值
    				label_upper_left->setString(CCString::createWithFormat("%s%d",xueliang,player->hp)->getCString());//左上角的文字
    				if(player->hp<1){//如果玩家被扣到0
    					CCDirector::sharedDirector()->replaceScene(MainScene::scene());//游戏重新开始
    				}
    			}			
    		}
    		else {			
    			monster->sprite->setPosition(ccp(5*visibleSize.width/6+CCRANDOM_0_1()*visibleSize.width/6,5*visibleSize.height/6+CCRANDOM_0_1()*visibleSize.height/6));//在屏幕的右上方区域产生箭矢
    			monster->sprite->setVisible(true);
    			monster->isEmerge=true;			
    		}
    	}
    }
    
    void MainScene::close(CCObject* pSender,CCControlEvent event)    
    {  
    	//结束当前游戏  
    	CCDirector::sharedDirector()->end();   
    	exit(0);    
    }
    
    void MainScene::pause(CCObject* pSender,CCControlEvent event)    
    {  
    	//将游戏界面暂停,压入场景堆栈。并切换到GamePause界面  
    	CCDirector::sharedDirector()->pushScene(PauseScene::scene());  
    }  

    总体来说吧,这个游戏的逻辑并不是复杂,但是将Cocos2dx所有的基本知识一次性地运用起来了。

    而且在C++中,尤其是这些多个类配合一起来工作的时候,一定要时刻注意你是在操作哪个指针,不要出现指针的重复声明,导致编译没错,程序打死都运行都不起来。


    展开全文
  • 首先思考一下跑酷游戏的元素组成部分 游戏场景(Scene) 控制的角色(Role) 游戏道具(Tool) 障碍物(Obstacles) 称为SRTO 游戏场景 游戏场景也就是跑酷地图,下面分析一下地图需要分多少层 背景图衬...
    • 跑酷地图的层级分布

       首先思考一下跑酷游戏的元素组成部分
      • 游戏场景(Scene)
      • 控制的角色(Role)
      • 游戏道具(Tool)
      • 障碍物(Obstacles)  

              称为SRTO

    • 游戏场景

            游戏场景也就是跑酷地图,下面分析一下地图需要分多少层

    1. 背景图衬(一般不动)       
    2. 天空层(移动较为缓慢,基本不动)
    3. 远景层(移动较慢,移动时能感觉出来)
    4. 近景层(以下三层移动速度一致,即跑酷的速度)
    5. 道路层
    6. 前景层 

         不同层的相对移动速度实现了景深的效果

          除了分层之外 还需要将地图循环

    展开全文
  • 这里包括游戏的所有源码 , 以及游戏的所有资源文件。
  • cocos2d-js跑酷游戏实战笔记1 用cocos2d-js加载瓦片地图 为了访问瓦片地图,Cocos2d-JS中访问瓦片地图API,主要的类有:TMXTiledMap、TMXLayer和TMXObjectGroup等。 TMXTiledMap类图 TMXTiledMap常用的函数...
    cocos2d-js跑酷游戏实战笔记1
    用cocos2d-js加载瓦片地图

    为了访问瓦片地图,Cocos2d-JS中访问瓦片地图API,主要的类有:TMXTiledMap、TMXLayer和TMXObjectGroup等。

    TMXTiledMap类图

    TMXTiledMap常用的函数如下: 
    new cc.TMXTiledMap(tmxFile)。创建瓦片地图对象。
    getLayer(layerName)。通过层名获得层对象。
    getObjectGroup(groupName)。通过对象层名获得层中对象组集合。
    getObjectGroups()。获得对象层中所有对象组集合。
    getProperties()。获得层中所有属性。
    getPropertiesForGID (GID)。通过GID[ GID是一个瓦片的全局标识符。]获得属性。
    getMapSize()。获得地图的尺寸,它的单位是瓦片。
    getTileSize()。获得瓦片尺寸,它的单位是像素。

    具体应用代码如下:

    runmap=new cc.TMXTiledMap(res.runmap);

    runmap.attr({

    x:0,

    y:size.height/2-320

    });

    this.addChild(runmap,3);

    让地图移动,

    if (runmap.getPositionX()<=-runmap.getContentSize().width/2) {

    runmap.setPositionX(0);

    }else{

    runmap.setPositionX(runmap.getPositionX()-10);

    }

    展开全文
  • 从网上下了一点素材资源,外加自己ps一点资源,然后东拼西凑写了一个横版跑酷的小游戏 ps:csdn好不爽,无法传大点的gif,所以只好录了个短的gif,而且压缩之后凑合能看 预览 步骤 1 工程结构 开发环境 win...
  • Font 字体导入 ... http://docs.cocos.com/creator/manual/zh/scripting/internal-events.html 05_scripting &gt; 03_events &gt; TouchEvent 03_gameplay &gt; 01_player_control &gt...
  • 泰然JS版的跑酷,这个地图是一个自定义class。在C++里面尽量不要自定义一个class,不然你new一个对象,在delete它,虽然也是一样能跑,但是跟引擎风格不一致,看起来感觉怪怪的。 我这里创建一个MapMa
  • cocos2dx 3.3 跑酷游戏源代码和资源 全部文件上传的话太大,就传了classes和resources里的文件 要全部文件的话可私信我
  • 因为我没用过chipmunk,而且它是面向过程的东西,情感上又不太愿意去研究,所以我用box2d来做了物理仿真。个人感觉box2d还是蛮好用的,它的作者很牛逼的哦。暴雪娱乐的首席软件工程师,box2d是他业余写的。国外的攻...
  • 要实现跑酷需要用到帧动画,什么是帧动画,不解释行么。 介绍一个将小图打包的工具TexturePacker,这是一个很强大的工具,另外还有一个物理编辑器PhysicsEditor,也不错,地址:http://www.cod
  • OUZEL 是一个 C++ 游戏引擎,主要针对 2D 游戏的开发。 特性: 跨平台(支持 Windows、MacOS、IOS、tvOS、Android、Linux 和 Emscripten 等) 多线程(用于呈现、声音和游戏的单独线程) 二维和三维场景管理 位图和...
  • 下面先给出游戏过程中用到的所有资源 开始界面定义为:MainScene 有如下功能: 1.背景 2.进入游戏界面按钮 3.预先加载背景音乐文件 好吧,弄错啦,本来想设置为0积分,但是上传几次出错,就忘改默认值啦,私信我或者...
  • cocos2d-x 3.2 |跑酷游戏:角色动画 qian'qin
  • cocos2d x跑酷源码 C++版

    2020-06-05 23:30:53
    自己仿照泰然论坛的跑酷JS版写的C++版,物理引擎用的box2d,思路清晰,注释详细,希望对大家有帮助,只要1分哦。 首先你要下载泰然的JS版跑酷,把这个代码加到工程里面去,替换掉C++部分就好了
  • Cocos2d-x 酷跑游戏例子

    2014-04-10 15:16:40
    1. 效果图     可以拉到底部看下动态...主角挂的时候,会有主角的帽子升上的动画,不知为什么这个简单的动画看起来是那么的有趣,点睛之笔。...2. cocos2d-x 中菜单的使用   ? 1
  • cocos2d-JS跑酷游戏实战笔记2 地图加载出错,原因是获取人物的坐标,转化成地图坐标的行和列后,获取地图的GIDAT时横纵坐标时弄反了 获取人物的横坐标var x=hero.getPositionX()-runmapp.getPositionX(); 获取...
  • 15款Cocos2d-x游戏源码

    2017-11-30 17:52:12
    (1)用cocos2d-x开发的中国象棋游戏源码 使用Cocos2d-X2.2.3开发的一款中国象棋游戏游戏中可以实现、新局面、悔棋、游戏音乐、胜利后会显示游戏结果。 源码下载:http://www.okbase.net/file/item/27881 ...
1 2 3 4 5 ... 20
收藏数 440
精华内容 176