看了cocos2d有一段时间了,简单的小游戏还是可以写出来。这个过程主要还是看,而很少动手去写,这样本身水平很难提高。就好比看完设计模式,现在依旧不会用,时间一久,也忘记的差不多了。俗话说,纸上得来终觉浅,绝知此事要躬行。因此,决定写一个高仿发飞机的小游戏,虽然简单,但还是要坚持写完。
这个系列主要还是基于我想到哪就写到哪,不定期更新。
1.开始界面首先,我们得找到微信打飞机的图片资源,直接到下面链接下载就可以了:
http://download.csdn.net/detail/q100036q/7524993
解压后:
资源图片准备就绪,我们就可以开始编码工作了,依旧是看图写代码,一步一步搭建。
开始画面很简单,一张背景图片再加一个animation,便构成了开始界面。
代码如下:
#ifndef _START_GAME_SCENE_H_#define _START_GAME_SCENE_H_#include "cocos2d.h"USING_NS_CC;class StartGameScene : public Layer{public: static cocos2d::Scene* createScene(); virtual bool init(); CREATE_FUNC(StartGameScene); voID loadingHandler(); voID loadingDone();};#endif#include "StartGameScene.h"#include "PlayGameScene.h"Scene* StartGameScene::createScene(){ // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = StartGameScene::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene;}// on "init" you need to initialize your instancebool StartGameScene::init(){ ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } Size visibleSize = Director::getInstance()->getVisibleSize(); Vec2 origin = Director::getInstance()->getVisibleOrigin(); // add background image auto sprite = Sprite::create("shoot_background/background.png"); // position the sprite on the center of the screen sprite->setposition(Vec2(visibleSize.wIDth/2 + origin.x,visibleSize.height/2 + origin.y)); // add the sprite as a child to this layer this->addChild(sprite,0); //加载页面 loadingHandler(); return true;}//loading handlervoID StartGameScene::loadingHandler(){ Size visibleSize = Director::getInstance()->getVisibleSize(); //start:开始界面的animation auto loadingSp = Sprite::create(); loadingSp->setposition(Point(visibleSize.wIDth / 2,visibleSize.height / 2)); this->addChild(loadingSp,1); Vector<SpriteFrame*> frameList; for(int i = 1; i <=4; i++) { SpriteFrame* sf = SpriteFrame::create(String::createWithFormat("shoot_background/game_loading%d.png",i)->_string,Rect(0,186,38)); frameList.pushBack(sf); } Animation* an = Animation::createWithSpriteFrames(frameList,0.5f); auto animate = Animate::create(an); auto repeat = Repeat::create(animate,3);//播放三次 //回调函数 auto callback = CallFunc::create(CC_CALLBACK_0(StartGameScene::loadingDone,this)); auto sequence = Sequence::create(repeat,callback,NulL); loadingSp->runAction(sequence); //end:开始界面的animation}//开始界面播放完,直接进入游戏场景voID StartGameScene::loadingDone(){ Director::getInstance()->replaceScene(PlayGameScene::createScene());}
显示效果如下:
进入游戏后,要让背景图片动起来,并且无缝衔接。实际上,用两张背景图片就可以达到这种效果。当第一张移出屏幕的时候,立即放置到最上面,衔接第二张,达到无缝衔接的效果。主要代码如下:
//run the background auto bg_1 = Sprite::create("shoot_background/background.png"); bg_1->setAnchorPoint(Point(0,0 )); bg_1->setposition(Point(0,0)); bg_1->setTag(BG_1); this->addChild(bg_1,0); auto bg_2 = Sprite::create("shoot_background/background.png"); bg_2->setAnchorPoint(Point(0,0 )); bg_2->setposition(Point(0,bg_1->getContentSize().height)); bg_2->setTag(BG_2); this->addChild(bg_2,0); //run background image this->schedule(schedule_selector(PlayGameScene::runBackground),0.01f);voID PlayGameScene::runBackground(float dt){ auto visibleSize = Director::getInstance()->getVisibleSize(); auto bg_1 = this->getChildByTag(BG_1); auto bg_2 = this->getChildByTag(BG_2); int bg_height = bg_1->getContentSize().height; bg_1->setpositionY(bg_1->getpositionY() - bg_speed); bg_2->setpositionY(bg_2->getpositionY() - bg_speed); //bg2移出屏幕后衔接在bg1后面 if(bg_2->getpositionY() <= 0) { bg_1->setpositionY(bg_2->getpositionY() + bg_height); } //bg1移出屏幕后衔接在bg2后面 if(bg_1->getpositionY() <= 0) { bg_2->setpositionY(bg_1->getpositionY() + bg_height); }}3.加载主飞机
经过步骤2,背景也可以无缝移动了,把主飞机(hero_plane)放上去,并且注册他的触碰事件检测,也就是我们手指触碰主飞机的时候,飞机能够跟着我们手指移动而移动。这样的效果也很简单,在层中去注册touchevent事件处理。点击时如果是touch飞机,设置一个标志位,touchmove事件的时候,不断去更新飞机的位置,这样就可以达到效果了。
主要代码如下:
//add plane hero Sprite* hero = Sprite::create("hero1.png"); PlaneHero* hero_plane = PlaneHero::create(hero); hero_plane->setposition(Point(visibleSize.wIDth / 2,visibleSize.height / 2)); hero_plane->setTag(HERO_PLANE); hero_plane->setAnchorPoint(Point(0,0)); this->addChild(hero_plane,1); //touch event handler auto touchListener = EventListenertouchOneByOne::create(); touchListener->setSwallowtouches(true); touchListener->ontouchBegan = CC_CALLBACK_2(PlayGameScene::ontouchBegan,this); touchListener->ontouchmoved = CC_CALLBACK_2(PlayGameScene::ontouchmoved,this); touchListener->ontouchCancelled = CC_CALLBACK_2(PlayGameScene::ontouchended,this); _eventdispatcher->addEventListenerWithSceneGraPHPriority(touchListener,this);//touch event handlerbool PlayGameScene::ontouchBegan(touch *touch,Event* event){ Point touchPoint = touch->getLocation(); btouchPlane = false; auto hero_plane = this->getChildByTag(HERO_PLANE); Point hero_pos = hero_plane->getposition(); Size hero_size = hero_plane->getContentSize(); log("hero_pos x = %f,y = %f",hero_pos.x,hero_pos.y); log("touchPoint x = %f,touchPoint.x,touchPoint.y); log("hero_size wIDth = %f,height = %f",hero_size.wIDth,hero_size.height); if(touchPoint.x >= hero_pos.x && touchPoint.x <= (hero_pos.x + hero_size.wIDth) && touchPoint.y >= hero_pos.y && touchPoint.y <= (touchPoint.y + hero_size.height)) { //touch the plane,mark this flag for use btouchPlane = true; } return true;}voID PlayGameScene::ontouchmoved(touch *touch,Event* event){ if(btouchPlane == true) { //move the hero_pane with out touch on screen auto hero_plane = this->getChildByTag(HERO_PLANE); Point pos = touch->getLocation(); hero_plane->setposition(pos); }}voID PlayGameScene::ontouchended(touch *touch,Event* event){ btouchPlane = false;}4.子d管理器
首先,我们写一个基类,用来绑定一个精灵,所有的飞机,子d都会继承他。
#ifndef _ENTITY_H_#define _ENTITY_H_#include "cocos2d.h"USING_NS_CC;class Entity : public Node{public: Entity(); ~Entity(); voID bindSprite(Sprite* sprite); Sprite* getSprite();private: Sprite* m_sprite;};#endif#include "Entity.h"Entity::Entity(){ m_sprite = NulL;}Entity::~Entity(){}voID Entity::bindSprite(Sprite* sprite){ if(this->m_sprite != NulL) { m_sprite->removeFromParentAndCleanup(true); } this->m_sprite = sprite; this->addChild(m_sprite); Size size = m_sprite->getContentSize(); this->setContentSize(size);}Sprite* Entity::getSprite(){ return this->m_sprite;}接着,写一个子d的基类,继承自Entity,他包含子d的共有属性。不同的子d类型都会继承自这个子d基类。方便扩展。
#ifndef _BulLETBASE_BASE_H_#define _BulLETBASE_BASE_H_#include "Entity.h"#define SPEED_DEFAulT 10#define SPEED_norMAL 5class BulletBase : public Entity{public: BulletBase(); ~BulletBase(); //子d是否在使用中 voID setUsed(bool isUsed); bool isUsed(); bool isArrive(); //设置子d速度 voID setSpeed(int speed); int getSpeed(); //是否飞出屏幕 bool isMoveOutScreen(); voID setIsMoveOutScreen(bool outScreen); //是否加进层里面 //bool isAddInLayer(); //voID setIsAddInLayer(bool inLayer);protected: bool m_isArrive; int m_speed;private: bool m_isUsed; bool m_isOutScreen; //bool m_isAddInLayer;};#endif#include "BulletBase.h"BulletBase::BulletBase(){ m_isUsed = false; m_isArrive = false; m_speed = SPEED_norMAL; m_isOutScreen = false; //m_isAddInLayer = false;}BulletBase::~BulletBase(){}voID BulletBase::setUsed(bool isUsed){ this->m_isUsed = isUsed;}bool BulletBase::isUsed(){ return this->m_isUsed;} bool BulletBase::isArrive(){ return this->m_isArrive;}//设置子d速度voID BulletBase::setSpeed(int speed){ this->m_speed = speed;}int BulletBase::getSpeed(){ return this->m_speed;}//是否已经飞出屏幕bool BulletBase::isMoveOutScreen(){ return this->m_isOutScreen;}voID BulletBase::setIsMoveOutScreen(bool outScreen){ this->m_isOutScreen = outScreen;}#if 0//是否加进层里面bool BulletBase::isAddInLayer(){ return this->m_isAddInLayer;}voID BulletBase::setIsAddInLayer(bool inLayer){ this->m_isAddInLayer = inLayer;}#endif紧接着,写一个普通类型的子d,在这里其实主要是写入子d的速度。不同类型的子d拥有不同的属性值,我们先简单的设置子d的速度就可以。以后需要扩展直接对这个类进行。
#ifndef _BulLET_norMAL_H_#define _BulLET_norMAL_H_#include "BulletBase.h"class Bulletnormal : public BulletBase{public: Bulletnormal(); ~Bulletnormal(); CREATE_FUNC(Bulletnormal); virtual bool init(); static Bulletnormal* create(Sprite* sprite); bool init(Sprite* sprite);private: voID moveEnd();};#endif
#include "Bulletnormal.h"Bulletnormal::Bulletnormal(){ m_speed = SPEED_norMAL;}Bulletnormal::~Bulletnormal(){}bool Bulletnormal::init(){ return true;}Bulletnormal* Bulletnormal::create(Sprite* sprite){ Bulletnormal* bnor = new Bulletnormal(); if(bnor && bnor->init(sprite)) { bnor->autorelease(); } else { CC_SAFE_DELETE(bnor); } return bnor;}bool Bulletnormal::init(Sprite* sprite){ bool ret = false; bindSprite(sprite); ret = true; return ret;}voID Bulletnormal::moveEnd(){ m_isArrive = true;}最后,创建子d管理器,生成子d,保存到一个列表里面,需要的时候直接取出。同时,子d的飞行也在管理器中做处理,不断检测子d并且设置子d的运行。
#ifndef _BulLET_MANAGER_H_#define _BulLET_MANAGER_H_#include "cocos2d.h"USING_NS_CC;#define BulLET_MAX_CACHE_NUM 20 //子d缓存数量class BulletBase;class BulletManager : public Node{public: BulletManager(); ~BulletManager(); static BulletManager* create(); bool init(); //获取未用的子d BulletBase* getUnusedBullet();private: Vector<BulletBase*> m_bulletList;//子d列表,保存子d voID createBullets();//创建缓存子d voID bulletLogicCheck(float dt);//子d逻辑};#endif#include "BulletManager.h"#include "BulletBase.h"#include "Bulletnormal.h"BulletManager::BulletManager(){}BulletManager::~BulletManager(){}BulletManager* BulletManager::create(){ BulletManager* bulletMgr = new BulletManager(); if(bulletMgr && bulletMgr->init()) { bulletMgr->autorelease(); } else { CC_SAFE_DELETE(bulletMgr); } return bulletMgr;}bool BulletManager::init(){ //创建子d列表 createBullets(); log("m_bulletList size() = %d",m_bulletList.size()); //循环检测子d列表 this->schedule(schedule_selector(BulletManager::bulletLogicCheck)); return true;}//获取未用的子dBulletBase* BulletManager::getUnusedBullet(){ log("m_bulletList size() = %d",m_bulletList.size()); for(int i = 0; i < m_bulletList.size(); i++) { BulletBase* bullet = m_bulletList.at(i); if(bullet->isUsed() == false) { bullet->setUsed(true); bullet->setIsMoveOutScreen(false); return bullet; } }#if 0 //i don't kNow why for(auto bullet : m_bulletList) { if(bullet->isUsed() == false) { bullet->setUsed(true); bullet->setIsMoveOutScreen(false); return bullet; } }#endif log("no bullet unused"); return NulL;}//创建子d缓存voID BulletManager::createBullets(){ BulletBase* bullet = NulL; for(int i = 0; i < BulLET_MAX_CACHE_NUM; i++) { auto bullet_sprite = Sprite::create("bullet1.png"); bullet = Bulletnormal::create(bullet_sprite); bullet->setUsed(false); bullet->setIsMoveOutScreen(false); m_bulletList.pushBack(bullet); this->addChild(bullet); } log("m_bulletList size() = %d",m_bulletList.size());}//检测子dvoID BulletManager::bulletLogicCheck(float dt){ auto visibleSize = Director::getInstance()->getVisibleSize(); for(auto bullet : m_bulletList) { if(bullet->isUsed() == true) { //子d运行 int posY = bullet->getpositionY(); posY += SPEED_DEFAulT; bullet->setpositionY(posY); //out of screen if(posY >= visibleSize.height) { bullet->setIsMoveOutScreen(true); bullet->setUsed(false); } } }}
以上全部写完,基本的画面就出来了,画面如下
好了 第一篇就先写到这里,后续会写第二篇。
总结以上是内存溢出为你收集整理的【cocos2d-x-3.2】【高仿微信打飞机系列一】【开始界面 子d生成 背景滑动 主飞机】全部内容,希望文章能够帮你解决【cocos2d-x-3.2】【高仿微信打飞机系列一】【开始界面 子d生成 背景滑动 主飞机】所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)