最近看了一下《
使用Quick-Cocos2d-x搭建一个横版过关游戏》这个教程。
我不太懂lua,但感觉代码意思基本能看出来,就想用C++重新写一下这个示例,一方面了解一下lua,另一方面还可以熟悉一下用C++的开发。本人小白,免不了会犯些愚蠢的错误,不过犯了错只要能发现就是进步。
环境:
Cocos2dx 3.2 VS2012
Quick-Cocos2d-x + BabeLua(可选,用于在VS中查看lua源码及运行原游戏)
资源文件:
https://github.com/rainswan/Brave res文件夹中,将此文件夹下的image文件夹复制到你工程的Resource下面。
1.创建工程
打开命令行,输入:
cocos new -l cpp -d e:/projects/ Brave_cpp
这个命令会帮你创建一个新的HelloWorld工程,而且把整个cocos2d的源码给你拷了一份放在工程下面。
运行一下这个工程,什么,竟然报错了。果断关闭所有VS窗口,重新打开运行,发现竟然正常运行了。
将资源文件复制到Resource文件夹下面备用。
删除掉init中按钮,精灵,标签等代码,让程序变成只显示一个黑屏。
给游戏添加角色
添加背景:
加入代码,加完后init函数内容如下:
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
Sprite* background = Sprite::create("image/background.png");
background->setPosition(origin + visibleSize/2);
this->addChild(background);
return true;
}
这样应该就可以显示出背景了。咦,Vec2类型竟然可以直接与Size类型相加?Size可以支持除法?这是怎么一回事呢?看一下Size源码,Size类定义了除法运算,Vec2难道定义了对Size的加法?不对,Vec2里没有关于Size的加法运算符。那就是Size可以自动转化成Vec2了?看到Size中有个如下的定义:
public:
operator Vec2() const
{
return Vec2(width, height);
}
精确的含义我没查到,不过应该可以理解为:如果有人把Size当作Vec2,就按这个方法给他一个Vec2.
冥冥之中自有天意,本来应该是一时的手误竟然背后还隐藏着道理……
另外,Size还重载了=操作符,可以用Vec2给Size赋值。
导入精灵帧资源
继续在init函数中加入:
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("image/role.plist","image/role.pvr.ccz");
这个资源里包含了一些玩家、敌人动作的精灵帧,需要提前导入缓存。
显示玩家和怪物
玩家应该是一个类,可以继承自Sprite。原文中为Player建立了一个类,为Enemy1也建立了一个类,然后在后面出现Enemy2的时候又建立了一个类。
我觉得这几个类可以用一个类代替,因为他们属性十分类似,目前只是贴图不同,仅仅因为这个就建立这么多类不太划算。
添加的Player.h如下:
#ifndef __Player__
#define __Player__
#include "cocos2d.h"
USING_NS_CC;
class Player : public Sprite
{
public:
enum PlayerType
{
PLAYER,
ENEMY1,
ENEMY2
};
bool initWithPlayerType(PlayerType type);
static Player* create(PlayerType type);
};
#endif
目前先考虑三类角色,player , enemy1, enemy2。创建时,用枚举类型指定是哪一种。
Player.cpp 如下:
#include "Player.h"
bool Player::initWithPlayerType(PlayerType type)
{
std::string spName = "";
switch(type)
{
case PlayerType::PLAYER:
spName = "player1-1-1.png";
break;
case PlayerType::ENEMY1:
spName = "enemy1-1-1.png";
break;
case PlayerType::ENEMY2:
spName = "enemy2-1-1.png";
break;
}
this->initWithSpriteFrameName(spName);
return true;
}
Player* Player::create(PlayerType type)
{
Player* player = new Player();
if(player && player->initWithPlayerType(type))
{
player->autorelease();
return player;
}
else
{
delete player;
player = NULL;
return NULL;
}
}
可以看出,其核心就是根据不同的角色类型,用不同的SpriteFrameName来初始化精灵。
继续在HelloWorld的init类中加入:
Player* player = Player::create(Player::PlayerType::PLAYER);
player->setPosition(origin.x + player->getContentSize().width/2, origin.y + visibleSize.height/2);
this->addChild(player);
Player* enemy1 = Player::create(Player::PlayerType::ENEMY1);
enemy1->setPosition(origin.x + visibleSize.width - player->getContentSize().width/2, origin.y + visibleSize.height/2);
this->addChild(enemy1);
运行程序,结果如下: