本篇博客又将开启一个新的游戏demo,之所以要写这个别人写的不想写的打飞机,是因为刚刚看了下3.0,感觉用这个小例子练练手顺便熟悉一下3.0会很不错的,所以就准备抽一个礼拜时间写写,大神勿喷!当然如果是新手的话,可以看看我原来的一些基础博客,这里写的时候只会说3.0和2.x有差别的地方,其他的只简要说明!

这个demo我们先来写个游戏开始场景,使用3.0的方法搭建我们的工程,下载资源文件放到resource目录下,我这里逐一介绍。首先用cocos new新建一个工程,用vs2012打开工程文件,然后删除掉helloworld这个场景,将下载好的资源文件放到resource目录下,如图所示。shoot和ui文件夹可以从工程中去掉,这俩个文件夹中的东西就是用来生成.plist文件用到的图片资源,我们在项目中使用的图片都是从.plist文件中获取的,这里保留是为了方便查看名字,最后打包的时候记着移除掉。font是字体文件,里边还包含一个.xml的中文字体文件,这个待会会说,sound就是声音文件了(资源上传到小塔cocos2d-x交流群了298136329)。

使用3.0实现飞机大战——游戏开始场景

建立场景筛选器,然后添加类StartGame,这个类继承自Layer,覆写其中的一些方法,在init函数中完成初始化的工作。

使用3.0实现飞机大战——游戏开始场景 使用3.0实现飞机大战——游戏开始场景

我先把代码贴上来,然后说明3.0的几个特别之处。

#ifndef _START_GAME_H_
#define _START_GAME_H_
#include "cocos2d.h"

USING_NS_CC;

class StartGame : public Layer
{
public:
	//继承layer需要覆写的几个函数
	static Scene * createScene();
	bool init();
	CREATE_FUNC(StartGame);
public:
	//构造和析构函数,新建项目的时候就自动为我们建立好了,vs还是很方便的
	StartGame(void);
	~StartGame(void);
public:
	//对游戏开始菜单的响应函数
	void play(Ref * ref);
	//对键盘的响应函数
	void onKeyReleased(EventKeyboard::KeyCode keyCode,Event * pEvent);
};

#endif
#include "StartGame.h"

StartGame::StartGame(void)
{
}

StartGame::~StartGame(void)
{
	//移除监听器
	Director::getInstance()->getEventDispatcher()->removeAllEventListeners();
}

Scene * StartGame::createScene()
{
	 auto scene = Scene::create();
	auto layer = StartGame::create();
	scene->addChild(layer);

	return scene;
}

bool StartGame::init()
{
	if(!Layer::init())
		return false;

	auto size = Director::getInstance()->getWinSize();

	//加载缓存文件
	SpriteFrameCache::getInstance()->addSpriteFramesWithFile("ui.plist");
	//使用缓存文件创建精灵
	auto background = Sprite::createWithSpriteFrameName("background.png");
	background->setPosition(Point(size.width/2,size.height/2));
	this->addChild(background);

	//设置logo
	auto logo = Sprite::createWithSpriteFrameName("shoot_copyright.png");
	logo->setPosition(Point(size.width/2,size.height-logo->getContentSize().height));
	//设置透明度是0
	logo->setOpacity(0);
	this->addChild(logo);

	//设置logo的动作
	auto fade = FadeIn::create(2.0f);
	logo->runAction(fade);

	//设置开始游戏场景处的动画
	auto animation = Animation::create();
	for(int i=0;i<4;i++)
	{
		auto spriteFrameName = String::createWithFormat("game_loading%d.png",i+1);
		auto spriteFrame = SpriteFrameCache::getInstance()->getSpriteFrameByName(spriteFrameName->getCString());
		animation->addSpriteFrame(spriteFrame);
	}
	animation->setDelayPerUnit(0.5f);
	animation->setLoops(-1);
	//指定第一帧执行loading动画
	auto sprite = Sprite::createWithSpriteFrameName("game_loading1.png");
	sprite->setPosition(size.width/2,size.height/2);
	this->addChild(sprite);
	//动作
	auto animate = Animate::create(animation);
	sprite->runAction(animate);

	//添加一个游戏开始按钮
	//从xml文件中读取中文显示出来
	auto dictionary = Dictionary::createWithContentsOfFile("font/text.xml");
	auto playText = Label::createWithTTF(((__String *)(dictionary->objectForKey("play")))->getCString(),
		"font/DFPShaoNvW5-GB.ttf",40);
	playText->setColor(Color3B(100,100,100));
	auto playMenu = MenuItemLabel::create(playText,CC_CALLBACK_1(StartGame::play,this));
	auto menu = Menu::create(playMenu,NULL);
	menu->setPosition(size.width/2,size.height*0.3);
	this->addChild(menu);

	//对手机返回键的监听
	auto listener = EventListenerKeyboard::create();
	//和回调函数绑定
	listener->onKeyReleased = CC_CALLBACK_2(StartGame::onKeyReleased,this);
	//添加到事件分发器中
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener,this);

	return true;
}
//对android返回键的响应函数
void StartGame::onKeyReleased(EventKeyboard::KeyCode keyCode,Event * pEvent)
{
	Director::getInstance()->end();
}
//开始游戏按钮的响应函数
void StartGame::play(Ref * ref)
{
	log("play game!");
}

主要代码就是init中了,我们使用了SpriteFrameCache来加载用到的图片资源,这个在2.x中也是这样的做法,因为opengl es用到的资源文件大小都是2的整数倍,所以做成一张大图,这样还可以提高渲染的效率,工具就是texturePacker,然后我们创建了一个logo,让logo执行了一个淡入的动作。接下来就是飞机飞动的动画了,方法和2.x的是相同的,当然animation创建的时候也可以是一个vector数组,里边放的就是spriteframe。游戏开始按钮这里要说下,我们使用一个label来创建菜单,这个label的中文文本是从.xml文件中读取到的,这个.xml文件如下。以后大家也按照这个格式写就可以了,一个key对应一个string,获取string是靠key的值,这种方法解决中文的问题比较好,有利于国际化,我之前都是用的iconv库解决的,以后也采用这种方法了,最后将这个文件保存为utf-8的格式。这个label要注意一下,3.0创建文本就是使用的这种方式,什么bmfont啦,都是这么做的,直接label->create...就可以了,原来的LabelTTF也不提倡使用了。菜单和回调函数的绑定用的就是CC_CALLBACK_1,关于CC_CALLBACK_的说明可以看看我前边的博客。最后是对手机返回键的监听,这个东西搞了我挺长时间的,关键问题是粗心了,犯了下二,我在classes下也建立了文件夹用来保存文件,就是和帅选器相同的名称为了好看,移植的时候需要复制到外边,结果改了代码没有复制,一直找代码的错误,哎,最后才发现。所以建议大家文件夹用成英文的,不要用中文,这样会很麻烦的。所以对手机返回键的监听你也会了吧。

使用3.0实现飞机大战——游戏开始场景

接下来需要修改appdelegate里边的东西了,主要是适配的问题,我采用的是我以前的方法,看了看也能用,函数的使用上变了点参数而已。

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview)
	{
		//更改一下窗口的名字
        glview = GLView::create("Plane By XiaoTa");
		//设置窗口的大小
		glview->setFrameSize(400,600);
        director->setOpenGLView(glview);
    }

	//适配方案
	//getFrameSize()获得实际屏幕的大小
	 Size frameSize = glview->getFrameSize();
	 //这填写的就是一般你作为背景图片的那种图片的大小,适配的原理就是放到和缩小,而以什么为参照,当然就是
	 //以最大的那张图片为参照,什么图片最大,当然是背景图片了,以后美工做图的时候用的就是以下的这个尺寸
	 Size winSize=CCSize(480,852);

	 //将宽和高做一个比,通过这个比,来具体的调整逻辑分辨率的大小
	 float widthRate = frameSize.width/winSize.width;
	 float heightRate = frameSize.height/winSize.height;

	 //如果是if中的语句,说明逻辑的高度有点大了,就把逻辑的高缩小到和宽度一样的比率
    if (widthRate > heightRate)
	{
		//里边传入的前俩个参数就是逻辑分辨率的大小,也就是通过getWinSize()得到的大小
		glview->setDesignResolutionSize(winSize.width,
			winSize.height*heightRate/widthRate, ResolutionPolicy::NO_BORDER);
	}
    else
	{
		glview->setDesignResolutionSize(winSize.width*widthRate/heightRate, winSize.height,
			ResolutionPolicy::NO_BORDER);
	}

	//设置和显示帧率
    director->setDisplayStats(true);
    director->setAnimationInterval(1.0 / 60);

	//创建场景并且运行
    auto scene = StartGame::createScene();
    director->runWithScene(scene);

    return true;
}

这样的话一个简单的开始游戏界面就搞定了,运行起来看看吧。

使用3.0实现飞机大战——游戏开始场景

接下来就是移植了,为什么要急着做这个呢,因为3.0移植真是太方便了,直接用手机连接上电脑,然后敲行代码就搞定了,而且我也建议大家写完了一段程序就尽快移植,这样便于发现问题,关于设置游戏竖版和icon图标的问题我之前也说过了,大家按照原来的博客做就行了,不明白的留言吧,最后机器运行一些正常!

使用3.0实现飞机大战——游戏开始场景