【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现

时间:2022-04-20 23:00:38

本节课的视频教程地址是:第六课在此
如果本教程有帮助到您,希望您能点击进去观看一下,而且现在注册成为极客学院的会员,可以免费领取30天学习时间,免费拿极客学院VIP,1000+高清视频,学习Android、HTML5、iOS各种开发技术,限时领取,手快的戳:http://e.jikexueyuan.com/invite/index.html?ZnJvbV9jb2RlPVkxblJUZSZ1bmFtZT1TdW9vTCZjaGFubmVsPWludml0ZV8xMDB3X3NoYXJlYnV0dG9uX2RpcmVjdDE=,验证手机号码和邮箱号码会赠送三天的会员时间,手机端首次也可以领取五天的会员时间哦(即使是购买年会员目前也仅仅是年费260),成为极客学院学习会员可以无限制的下载和观看所有的学院网站的视频,谢谢您的支持!

转载请注明出处:http://blog.csdn.net/suool/article/details/46851335

前言

经过前面五节课的学习我们目前还剩的未完成的工作就是游戏的核心场景——游戏场景。这节课我们就来学习如何实现游戏的核心场景。(核心场景的逻辑功能完成放在下一课。)

根据我们在第一课中对整个核心游戏场景的基本分析和分解可以知道,游戏场景主要分为三层,分别是:
地图层:包含一个多层滚动视差地图以及我们的游戏实体
控制层:控制英雄动作的按钮以及游戏暂停的按钮所在的层
实体状态展示层:展示实体和怪物当前状态的层

所以,本节课我们主要要学习的就是如何分析和实现这三个层。

游戏主场景地图层的实现

这一部分主要是两个知识点:

  • 视差节点ParallaxNode学习
  • 地图层的分析和实现
    因为我们游戏的地图场景要模仿现实世界中的物理规则,所以游戏场景不可能是一张背景图片就可以解决的。整个游戏的环境是由四层图片贴成的,一个是不会动的”远处“背景,剩下三个是按照现实世界视差效果移动的三层地图:人物前面的草丛,人物所在的地面,任务后面的房屋。
    如下图示:
    【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现

视差节点ParallaxNode学习

首先要知道什么是视差?
视差的含义是指对象的位置相对于背景的变化取决于观察者的位置。毕竟三维世界的特性被广泛的应用于在二维游戏创造出景深的效果。
示意图如下:
【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现
在Cocos2d-x中有一个视差节点ParallaxNode提供了根据他视差比例决定子节点卷动速度变快或变慢。
其次就是视差节点 ParallaxNode类的学习

  • 重点API函数
  • 使用场景和示例
//Parallax(视差) 

#ifndef __CCPARALLAX_NODE_H__
#define __CCPARALLAX_NODE_H__

#include "base_nodes/CCNode.h"
/*#include "support/data_support/ccArray.h"*/

NS_CC_BEGIN

struct _ccArray;

/**
* @addtogroup tilemap_parallax_nodes
* @{
*/


/** @brief ParallaxNode: A node that simulates a parallax scroller //模拟视差滚动的节点

children 移动的 faster / slower 是根据 parent 视差比确定的

*/

class CC_DLL ParallaxNode : public Node
{
public:
// Create a Parallax(视差) node
static ParallaxNode * create();

/** 使用 z-顺序,视差比和位置偏移 在内容里面添加一个 child
It returns self, 你可以连接几个 addChilds.
@since v0.8
* @js ctor
*/

ParallaxNode();
/**
* @js NA
* @lua NA
*/

virtual ~ParallaxNode();

// 防止编译器警告:“包括函数隐藏重载虚函数”
using Node::addChild;
// 将节点添加到ParallaxNode上边,各个参数的意义:第一个参数是要添加的节点,第二个参数是zorder,决定显示的顺序,第三个参数是速率,这个如何理解,就是如果你得node移动的速度是1,那么你得速度是相对于这个1的多少,这里写得是(0.5,0)意思就是当我的parallax向左移动的1个单位的时候,该子节点移动的就是0.5个单位,y方向上没有速度,最后一个是坐标,注意这个坐标是相对于node节点的坐标,而不是当前的层
void addChild(Node * child, int z, const Point& parallaxRatio, const Point& positionOffset);

/** 为 Parallax(视差) 节点设置一个 layer 数组 */
void setParallaxArray( struct _ccArray *parallaxArray) { _parallaxArray = parallaxArray; }
/** Returns Parallax(视差) 节点的 layer 数组 */
struct _ccArray* getParallaxArray() { return _parallaxArray; }
const struct _ccArray* getParallaxArray() const { return _parallaxArray; }

//
// Overrides
//
virtual void addChild(Node * child, int zOrder, int tag) override;
virtual void removeChild(Node* child, bool cleanup) override;
virtual void removeAllChildrenWithCleanup(bool cleanup) override;
virtual void visit(void) override;

protected:
Point absolutePosition();

Point _lastPosition;
struct _ccArray* _parallaxArray;
};

// end of tilemap_parallax_nodes group
/// @}

NS_CC_END

#endif //__CCPARALLAX_NODE_H__

再看下他的实现源码:

#include "CCParallaxNode.h"
#include "ccCArray.h"

NS_CC_BEGIN
/**
PointObject用于记录CCParallaxNode孩子节点的ratio和offset属性
**/


class PointObject : public Ref
{
public:
static PointObject * create(Point ratio, Point offset)
{
PointObject *ret = new PointObject();
ret->initWithPoint(ratio, offset);
ret->autorelease();
return ret;
}

bool initWithPoint(Point ratio, Point offset)
{
_ratio = ratio;
_offset = offset;
_child = nullptr;
return true;
}

inline const Point& getRatio() const { return _ratio; };
inline void setRatio(const Point& ratio) { _ratio = ratio; };

inline const Point& getOffset() const { return _offset; };
inline void setOffset(const Point& offset) { _offset = offset; };

inline Node* getChild() const { return _child; };
inline void setChild(Node* child) { _child = child; };

private:
Point _ratio;
Point _offset;
Node *_child; // weak ref
};
// 构造函数
ParallaxNode::ParallaxNode()
{
_parallaxArray = ccArrayNew(5);
_lastPosition = Point(-100,-100);
}
// 析构函数
ParallaxNode::~ParallaxNode()
{
if( _parallaxArray )
{
ccArrayFree(_parallaxArray);
_parallaxArray = nullptr;
}
}
// 创建函数
ParallaxNode * ParallaxNode::create()
{
ParallaxNode *ret = new ParallaxNode();
ret->autorelease();
return ret;
}
// 添加子节点
void ParallaxNode::addChild(Node * child, int zOrder, int tag)
{
CC_UNUSED_PARAM(zOrder);
CC_UNUSED_PARAM(child);
CC_UNUSED_PARAM(tag);
CCASSERT(0,"ParallaxNode: use addChild:z:parallaxRatio:positionOffset instead");
}
//
void ParallaxNode::addChild(Node *child, int z, const Point& ratio, const Point& offset)
{
CCASSERT( child != nullptr, "Argument must be non-nil");
// 记录属性
PointObject *obj = PointObject::create(ratio, offset);
obj->setChild(child);
// 扩容
ccArrayAppendObjectWithResize(_parallaxArray, (Ref*)obj);
// 当ParallaxNode的位置不是(0,0)时添加孩子,会发生比较诡异的事情
Point pos = this->absolutePosition();
pos.x = -pos.x + pos.x * ratio.x + offset.x;
pos.y = -pos.y + pos.y * ratio.y + offset.y;
child->setPosition(pos);

Node::addChild(child, z, child->getTag());
}

void ParallaxNode::removeChild(Node* child, bool cleanup)
{
// 删除属性
for( int i=0;i < _parallaxArray->num;i++)
{
PointObject *point = (PointObject*)_parallaxArray->arr[i];
if (point->getChild() == child)
{
ccArrayRemoveObjectAtIndex(_parallaxArray, i, true);
break;
}
}
// 删除Node
Node::removeChild(child, cleanup);
}

void ParallaxNode::removeAllChildrenWithCleanup(bool cleanup)
{
ccArrayRemoveAllObjects(_parallaxArray);
Node::removeAllChildrenWithCleanup(cleanup);
}

Point ParallaxNode::absolutePosition()
{
Point ret = _position;
Node *cn = this;
//层层向上计算,获得绝对坐标,至于为什么需要这样,下面有段注释
while (cn->getParent() != nullptr)
{
cn = cn->getParent();
ret = ret + cn->getPosition();
}
return ret;
}

/*
The positions are updated at visit because:
- using a timer is not guaranteed that it will called after all the positions were updated
- overriding "draw" will only precise if the children have a z > 0
*/

void ParallaxNode::visit(Renderer *renderer, const kmMat4 &parentTransform, bool parentTransformUpdated)
{
// Point pos = position_;
// Point pos = [self convertToWorldSpace:Point::ZERO];
Point pos = this->absolutePosition();
if( ! pos.equals(_lastPosition) )
{
// 计算所有孩子相对于CCParallaxNode的位置,注意当我们移动CCParallaxNode位置时,表现出来的其实是孩子位置的改变,这种变化是本类的核心设计。
for( int i=0; i < _parallaxArray->num; i++ )
{
PointObject *point = (PointObject*)_parallaxArray->arr[i];
//例如CCParallaxNode绝对位置为100,表现出来的是孩子位置为-100,CCParallaxNode的移动我们不能感知,但孩子的位置却发生了变化。
//简单点就是类似于一个摄像头场景的移动,摄像头未动,风景变了
//如果ratio为1,则postion == offset
//如果ratio为(0,1),则position < offset,移动速度慢
//如果ratio为(1,xx),则postion > offset,移动速度快
float x = -pos.x + pos.x * point->getRatio().x + point->getOffset().x;
float y = -pos.y + pos.y * point->getRatio().y + point->getOffset().y;
//孩子的位置是通过上面两行计算出来的,因此手动设置其postion不会有任何作用
point->getChild()->setPosition(Point(x,y));
}
// 更新位置
_lastPosition = pos;
}
Node::visit(renderer, parentTransform, parentTransformUpdated);
}

NS_CC_END

以上就是Cocos2d-x的视差节点的实现过程。使用起来非常简单,但是实现过程值得我们去借鉴和思考。

地图层的分析和实现

下面就是我们的游戏的地图层的实现代码:

/*!
* \file GameMap.h
* \date 2015/06/08 11:19
*
* \author SuooL
* Contact: hu1020935219@gmail.com
*
* \brief
*
* TODO: long description
*
* \note
*/


#ifndef __GameMap__H__
#define __GameMap__H__

#include "cocos2d.h"
USING_NS_CC;

class Hero;

class GameMap : public Node
{
public:
GameMap();
~GameMap();
// 初始化地图
void InitMap(const char *map_name1,const char *map_name2, const char *map_name3);
//根据精灵的位置移动地图,visibleSize为当前窗口的大小
void MoveMap(Hero *hero);
//判断地图是否到达边缘
bool JudgeMap(Hero *hero);

CREATE_FUNC(GameMap);
private:
Sprite* m_map1;
Sprite* m_map2;
Sprite* m_map3;
ParallaxNode* parallax;
};

#endif

cpp文件:

/*!
* \class GameMap
*
* \ingroup GroupName
*
* \brief
*
* TODO: long description
*
* \note
*
* \author SuooL
*
* \version 1.0
*
* \date 六月 2015
*
* Contact: hu1020935219@gmail.com
*
*/


#include "GameMap.h"
#include "GlobalDefine.h"
#include "Hero.h"
#include "cocos2d.h"

USING_NS_CC;

GameMap::GameMap()
{
m_map1 = NULL;
m_map2 = NULL;
m_map3 = NULL;
}
GameMap::~GameMap()
{
}

void GameMap::InitMap(const char *map_name1,const char *map_name2,const char *map_name3)
{
this->m_map1 = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(map_name1));
this->m_map2 = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(map_name2));
this->m_map3 = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(map_name3));

m_map1->setAnchorPoint(Point(0, 0));
m_map1->setTag(11);
m_map2->setAnchorPoint(Point(0, 0));
m_map3->setAnchorPoint(Point(0, 0));

parallax = ParallaxNode::create();
parallax->addChild(m_map1, 1, Point(1.18, 0), Point(0,360));
parallax->addChild(m_map2, 2, Point(1, 0), Point(0,0));
parallax->addChild(m_map3, 3, Point(0.7, 0), Point(0, 0));

this->setAnchorPoint(ccp(0, 0));
this->addChild(parallax);
log("%f%f", parallax->getPositionX(), parallax->getPositionY());
log("%f%f", parallax->getContentSize().width, parallax->getContentSize().height);
log("%f%f", m_map1->getContentSize().width, m_map1->getContentSize().height);
}

void GameMap::MoveMap(Hero *hero)//
{
auto map = (Sprite*)parallax->getChildByTag(11);

if (hero->JudgePosition(WINSIZE) && hero->HeroDirecton == false)//精灵运动到中间,地图才移动
{
if (this->getPositionX() >= -(m_map2->getContentSize().width - WINSIZE.width))//防止地图左边运动后超出边缘
this->setPosition(this->getPositionX() - hero->m_iSpeed, this->getPositionY());
log("map is %f", this->getPositionX());
}
if (hero->JudgePosition(WINSIZE) && hero->HeroDirecton == true)//精灵运动到中间,地图才移动
{
log("Hero Walk Left %f", hero->getPositionX());
log("map is %f", this->getPositionX());
if (this->getPositionX() <= -10) //防止地图左边运动后超出边缘
this->setPosition(this->getPositionX() + hero->m_iSpeed, this->getPositionY());
}
}
bool GameMap::JudgeMap(Hero *hero)
{
if (this->getPositionX() >= -(m_map2->getContentSize().width - WINSIZE.width) && hero->HeroDirecton == false)//防止地图左边运动后超出边缘
return false;
else if (this->getPositionX() <= -10 && hero->HeroDirecton == true) //防止地图左边运动后超出边缘
return false;
else //地图已经移动到达边缘
return true;
}

游戏主场景控制层的分析和实现

这一部分也是有两个点:

  • ControlButton的学习和使用
  • 控制层的分析和实现
    因为整个控制的组成如下:(暂停按钮没有框出来)
    【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现
    可以看出都是按钮。其中被框出来的按钮时ControlButton制作的,而暂停按钮则是以前的MenuItemSprite制作的。
    为什么要用ControlButton呢?因为用户按按钮的时候有很多种情况判断,但是MenuItem系的按钮事件都封装的很简单,如果此处采用MenuItem会实际用手操作的时候发现有一堆的问题。

ControlButton的学习和使用

【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现
上面就是ControlButton的类图。可以看出其继承自Control控件类,这个类在之前讲ControlSlider的时候就说过。
ControlButton使用的背景图片是点九图CCScale9Sprite,可以使得按钮在变大的情况下,尽量保持棱角不失真。
1、按钮状态

    /** The possible state for a control. */
enum class State
{
NORMAL = 1 << 0, // The normal, or default state of a control—that is, enabled but neither selected nor highlighted.
HIGH_LIGHTED = 1 << 1, // Highlighted state of a control. A control enters this state when a touch down, drag inside or drag enter is performed. You can retrieve and set this value through the highlighted property.
DISABLED = 1 << 2, // Disabled state of a control. This state indicates that the control is currently disabled. You can retrieve and set this value through the enabled property.
SELECTED = 1 << 3 // Selected state of a control. This state indicates that the control is currently selected. You can retrieve and set this value through the selected property.
};

2、按钮事件

    enum class EventType
{
TOUCH_DOWN = 1 << 0, // A touch-down event in the control.
DRAG_INSIDE = 1 << 1, // An event where a finger is dragged inside the bounds of the control.
DRAG_OUTSIDE = 1 << 2, // An event where a finger is dragged just outside the bounds of the control.
DRAG_ENTER = 1 << 3, // An event where a finger is dragged into the bounds of the control.
DRAG_EXIT = 1 << 4, // An event where a finger is dragged from within a control to outside its bounds.
TOUCH_UP_INSIDE = 1 << 5, // A touch-up event in the control where the finger is inside the bounds of the control.
TOUCH_UP_OUTSIDE = 1 << 6, // A touch-up event in the control where the finger is outside the bounds of the control.
TOUCH_CANCEL = 1 << 7, // A system event canceling the current touches for the control.
VALUE_CHANGED = 1 << 8 // A touch dragging or otherwise manipulating a control, causing it to emit a series of different values.
};

3、绑定按钮事件的方法

    /**
* Adds a target and action for a particular event (or events) to an internal
* dispatch table.
* The action message may optionnaly include the sender and the event as
* parameters, in that order.
* When you call this method, target is not retained.
*
* @param target The target object that is, the object to which the action
* message is sent. It cannot be nil. The target is not retained.
* @param action A selector identifying an action message. It cannot be NULL.
* @param controlEvents A bitmask specifying the control events for which the
* action message is sent. See "CCControlEvent" for bitmask constants.
*/

virtual void addTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents);

/**
* Removes a target and action for a particular event (or events) from an
* internal dispatch table.
*
* @param target The target object梩hat is, the object to which the action
* message is sent. Pass nil to remove all targets paired with action and the
* specified control events.
* @param action A selector identifying an action message. Pass NULL to remove
* all action messages paired with target.
* @param controlEvents A bitmask specifying the control events associated with
* target and action. See "CCControlEvent" for bitmask constants.
*/

virtual void removeTargetWithActionForControlEvents(Ref* target, Handler action, EventType controlEvents);

常用操作如下

//
class ControlButton : public Control
{
/**
* 创建ControlButton的方法
*/

static ControlButton* create();
static ControlButton* create(Scale9Sprite* sprite);
static ControlButton* create(Node* label, Scale9Sprite* backgroundSprite);
static ControlButton* create(const std::string& title, const std::string& fontName, float fontSize);
//###############################################################################

//使用点九图CCScale9Sprite,设置在指定State下的 背景精灵
virtual void setBackgroundSpriteForState(Scale9Sprite* sprite, State state);


//使用精灵帧SpriteFrame,设置在指定State下的 背景精灵
//其实在内部实现的代码,实际上是利用精灵帧spriteFrame创建了点九图Scale9Sprite作为背景精灵
virtual void setBackgroundSpriteFrameForState(SpriteFrame* spriteFrame, State state);


//获取在指定State下的 背景图
virtual CCScale9Sprite* getBackgroundSpriteForState(State state);
/**
* 继承于父类
*/

virtual void setEnabled(bool enabled); //是否启用
virtual void setSelected(bool enabled); //是否选中
virtual void setHighlighted(bool enabled); //是否高亮
};
//

更多操作参见源码。
关于Control控件类大家可以看下这篇文章的分析:http://www.2cto.com/kf/201407/313448.html
关于ControlButton的分析参见这篇文章:http://shahdza.blog.51cto.com/2410787/1543349
看过之后就会对这些有一个差不多的理解了。
具体控制层的代码在下面和展示层一起贴出来。

实体状态展示层的分析和实现

主要组成如下:
【Cocos游戏实战】功夫小子第六课之游戏主功能场景的分析和实现
可以看出其实就两个进度条的使用。因此我们用到了Cocos2d-x提供的ProgressTimer控件。

ProgressTimer的学习和使用

这个类的学习和使用已经有人写了非常好的说明教程,参加此处:http://shahdza.blog.51cto.com/2410787/1546707, 我这里就不做复用性的工作了。

下面是整个主场景的分析和实现代码(无逻辑处理部分)

// 头文件
/*!
* \file GameLayer.h
* \date 2015/06/13 16:55
*
* \author SuooL
* Contact: hu1020935219@gmail.com
*
* \brief 游戏场景
*
* TODO: long description
*
* \note
*/


#ifndef __GameLayer__H__
#define __GameLayer__H__

#include <iostream>
#include "cocos2d.h"
#include "SimpleAudioEngine.h"
#include "ActionTool.h"
#include "GlobalData.h"
#include "GlobalDefine.h"
#include "extensions/cocos-ext.h"
#include "Monster.h"

USING_NS_CC;
using namespace extension;

class Hero;
class ProgressBar;
class GameMap;

class GameLayer : public Layer
{
public:

static Scene* createScene();
virtual bool init();

// 暂停
void gamePause(Ref* pSender);
void gameOver(float delta);
void gameVictory(float delta);

// 技能--拳击--脚踢--超级技能--蹦
void fistAttack(Ref* pSender, Control::EventType type);
void footAttack(Ref* psender, Control::EventType type);
void comboAttack(Ref* pSender, Control::EventType type);
void jump(Ref* pSender, Control::EventType type);

// 前进,后退
void forward(Ref* pSender, Control::EventType type);
void backward(Ref* pSender, Control::EventType type);

virtual void update(float delta);

CREATE_FUNC(GameLayer);

private:

// 英雄&怪物
Hero* m_pHero;
Monster* m_pMonster1;

GameMap* myMap;

// 背景条
Sprite* m_pBG;
// 血条,能量前景条
ProgressTimer* m_pHPBar;
ProgressTimer* m_pMPBar;

ControlButton * m_pComboBtn;
Sprite* m_pComboPic;

};

#endif

cpp文件

/*!
* \class GameLayer
*
* \ingroup GroupName
*
* \brief
*
* TODO: long description
*
* \note
*
* \author SuooL
*
* \version 1.0
*
* \date 六月 2015
*
* Contact: hu1020935219@gmail.com
*
*/

#include "GameLayer.h"
#include "GameMap.h"
#include "Hero.h"
#include "Monster.h"
#include "PauseLayer.h"
#include "GateMapLayer.h"
#include "MonsterOne.h"
#include "extensions/cocos-ext.h"
#include "cocostudio/CocoStudio.h"

USING_NS_CC;
using namespace CocosDenshion;
using namespace cocos2d::extension; //引用cocos2d::extension命名空间

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

return scene;
}

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

if (getBoolFromXML(MUSIC_KEY))
{
float music = getFloatFromXML(MUSICVOL)*100.0f;
aduioEngine->setBackgroundMusicVolume(getFloatFromXML(MUSICVOL));
if (SimpleAudioEngine::getInstance()->isBackgroundMusicPlaying())
{
aduioEngine->pauseBackgroundMusic();
aduioEngine->playBackgroundMusic("Sound/gameBGM.wav", true);
}
else
aduioEngine->playBackgroundMusic("Sound/gameBGM.wav", true);
}
else
aduioEngine->pauseBackgroundMusic();

velocity = 10.0f;
m_bDirection = false;
m_bRun = false;
m_bJump = false;

SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapBefore.plist");
SpriteFrameCache::getInstance()->addSpriteFramesWithFile("pnglist/mapRoad.plist");

String *bgName = String::createWithFormat("bgmap%d.png", m_iSelectGate);
String *midName = String::createWithFormat("MapMiddle%d.png", m_iSelectGate);
String *groundName = String::createWithFormat("MapGround%d.png", m_iSelectGate);
String *beforeName = String::createWithFormat("MapBefore%d.png", m_iSelectGate);
String *comoboName = String::createWithFormat("comboBtn%d.png", m_iSelectGate);

auto bgPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(bgName->getCString()));
bgPic->setPosition(WINSIZE.width / 2, WINSIZE.height / 2);
this->addChild(bgPic, 0);
myMap = GameMap::create();
myMap->InitMap(midName->getCString(), groundName->getCString(), beforeName->getCString());
this->addChild(myMap, 1);

// 界面控制键初始化
// 技能键
auto m_pFistBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("fist.png"));
auto m_pFistBtn = ControlButton::create(m_pFistBG);
m_pFistBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("fist.png"))->getContentSize());

auto m_pFootBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("foot.png"));
auto m_pFootBtn = ControlButton::create(m_pFootBG);
m_pFootBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("foot.png"))->getContentSize());

auto m_pJumpBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jump.png"));
auto m_pJumpBtn = ControlButton::create(m_pJumpBG);
m_pJumpBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jump.png"))->getContentSize());

auto m_pComboBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(comoboName->getCString()));
m_pComboBtn = ControlButton::create(m_pComboBG);
m_pComboBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(comoboName->getCString()))->getContentSize());

// 按键背景
auto m_pFistPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("quan.png"));
auto m_pFootPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("jiao.png"));
auto m_pJumpPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tiao.png"));
m_pComboPic = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("tiao.png"));

auto m_pFistPicSize = m_pFistPic->getContentSize();
m_pFistBtn->setPosition(ccp(m_pFistPicSize.width / 2, m_pFistPicSize.height / 2));
m_pFistBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::fistAttack), Control::EventType::TOUCH_UP_INSIDE);

auto m_pFootPicSize = m_pFootPic->getContentSize();
m_pFootBtn->setPosition(ccp(m_pFootPicSize.width / 2, m_pFootPicSize.height / 2));
m_pFootBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::footAttack), Control::EventType::TOUCH_UP_INSIDE);

auto m_pJumpPicSize = m_pJumpPic->getContentSize();
m_pJumpBtn->setPosition(ccp(m_pJumpPicSize.width / 2.0 - 1.5, m_pJumpPicSize.height / 2));
m_pJumpBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::jump), Control::EventType::TOUCH_UP_INSIDE);

auto m_pComboPicSize = m_pComboPic->getContentSize();
m_pComboBtn->setPosition(ccp(m_pComboPicSize.width / 2 - 1.5, m_pComboPicSize.height / 2));
m_pComboBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::comboAttack), Control::EventType::TOUCH_UP_INSIDE);

m_pFistPic->addChild(m_pFistBtn, 1);
m_pFootPic->addChild(m_pFootBtn, 1);
m_pJumpPic->addChild(m_pJumpBtn, 1);
m_pComboPic->addChild(m_pComboBtn, 1);

m_pFistPic->setPosition(WINSIZE.width - 230, 76);
m_pFootPic->setPosition(WINSIZE.width - 73, 76);
m_pJumpPic->setPosition(WINSIZE.width - 60, 220);
m_pComboPic->setPosition(WINSIZE.width - 387, 76);

m_pComboPic->setVisible(false);


this->addChild(m_pFistPic, 1);
this->addChild(m_pFootPic, 1);
this->addChild(m_pJumpPic, 1);
this->addChild(m_pComboPic, 1);

// 行走控制键,暂停键
auto puaseGameItem = MenuItemSprite::create(
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseNormal.png")),
Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("pauseSelected.png")),
CC_CALLBACK_1(GameLayer::gamePause, this)); // Pause

auto backwardBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionNormal.png"));
auto backwardSelBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionSelected.png"));
auto backwardBtn = ControlButton::create(backwardBG);
backwardBtn->setBackgroundSpriteForState(backwardSelBG, Control::State::HIGH_LIGHTED);
backwardBtn->setZoomOnTouchDown(false);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::TOUCH_DOWN);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::TOUCH_UP_INSIDE);
backwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::backward), Control::EventType::DRAG_OUTSIDE);
backwardBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directionNormal.png"))->getContentSize());

auto forwardBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForNor.png"));
auto forwardSelBG = Scale9Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForSel.png"));
auto forwardBtn = ControlButton::create(forwardBG);
forwardBtn->setBackgroundSpriteForState(forwardSelBG, Control::State::HIGH_LIGHTED);
forwardBtn->setZoomOnTouchDown(false);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::TOUCH_DOWN);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::TOUCH_UP_INSIDE);
forwardBtn->addTargetWithActionForControlEvents(this, cccontrol_selector(GameLayer::forward), Control::EventType::DRAG_OUTSIDE);
forwardBtn->setPreferredSize(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("directForNor.png"))->getContentSize());

puaseGameItem->setPosition(WINSIZE.width - 50, WINSIZE.height - 48);
backwardBtn->setPosition(117, 70);
forwardBtn->setPosition(304, 70);

auto menuWalk = Menu::create(puaseGameItem, NULL);
menuWalk->setPosition(Point::ZERO);
this->addChild(backwardBtn, 1);
this->addChild(forwardBtn, 1);
this->addChild(menuWalk, 1);

// 状态条
m_pBG = Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("barGround.png"));

m_pHPBar = ProgressTimer::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("HPBar.png")));
m_pHPBar->setType(ProgressTimer::Type::BAR);
m_pHPBar->setMidpoint(ccp(0, 0.5));
m_pHPBar->setBarChangeRate(ccp(1, 0));
m_pHPBar->setPercentage(100);

m_pMPBar = ProgressTimer::create(Sprite::createWithSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName("MPBar.png")));
m_pMPBar->setType(ProgressTimer::Type::BAR);
m_pMPBar->setMidpoint(ccp(0, 0.5));
m_pMPBar->setBarChangeRate(ccp(1, 0));
m_pMPBar->setPercentage(0);

m_pHPBar->setPosition(240, 45);
m_pMPBar->setPosition(226, 30);

m_pBG->addChild(m_pHPBar);
m_pBG->addChild(m_pMPBar);

m_pBG->setPosition(260, WINSIZE.height - 60);

this->addChild(m_pBG, 1);

// 英雄
m_pHero = Hero::create();
m_pHero->InitHeroSprite("idle.png", 1);
m_pHero->setPosition(100, 360);
this->addChild(m_pHero, 3);


// MonsterOne *monster = MonsterOne::createWithMapAndHero(myMap, m_pHero);

this->scheduleUpdate();
return true;
}

// 拳击
void GameLayer::fistAttack(Ref* pSender, Control::EventType type)
{
}

// 腿击
void GameLayer::footAttack(Ref* psender, Control::EventType type)
{

}

//
void GameLayer::jump(Ref* pSender, Control::EventType type)
{
}

void GameLayer::comboAttack(Ref* pSender, Control::EventType type)
{

}



void GameLayer::gamePause(Ref* pSender)
{
}


void GameLayer::backward(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsAttack && m_pHero->m_bIsJumping == true)
{
return;
}
switch (type)
{
case cocos2d::extension::Control::EventType::TOUCH_DOWN:
//m_bRun = true;
//m_bDirection = true;
break;
case cocos2d::extension::Control::EventType::DRAG_INSIDE:
break;
case cocos2d::extension::Control::EventType::DRAG_OUTSIDE:
//m_bRun = false;
//m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::DRAG_ENTER:
break;
case cocos2d::extension::Control::EventType::DRAG_EXIT:
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_INSIDE:
//m_bRun = false;
//m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_OUTSIDE:
break;
case cocos2d::extension::Control::EventType::TOUCH_CANCEL:
break;
case cocos2d::extension::Control::EventType::VALUE_CHANGED:
break;
default:
break;
}
}

void GameLayer::forward(Ref* pSender, Control::EventType type)
{
if (m_pHero->IsAttack && m_pHero->m_bIsJumping == true)
{
return;
}
switch (type)
{
case cocos2d::extension::Control::EventType::TOUCH_DOWN:
//m_bRun = true;
//m_bDirection = false;
break;
case cocos2d::extension::Control::EventType::DRAG_INSIDE:
break;
case cocos2d::extension::Control::EventType::DRAG_OUTSIDE:
//m_bRun = false;
//m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::DRAG_ENTER:
break;
case cocos2d::extension::Control::EventType::DRAG_EXIT:
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_INSIDE:
//m_bRun = false;
//m_pHero->StopAnimation();
break;
case cocos2d::extension::Control::EventType::TOUCH_UP_OUTSIDE:
break;
case cocos2d::extension::Control::EventType::TOUCH_CANCEL:
break;
case cocos2d::extension::Control::EventType::VALUE_CHANGED:
break;
default:
break;
}
}

void GameLayer::gameOver(float delta)
{

}

void GameLayer::gameVictory(float delta)
{

}

bool GameLayer::isAttackMonster(Hero * hero, Monster* monster)
{
}

void GameLayer::update(float delta)
{

}

以上就是本节课的主要内容,转载请注明出处:http://blog.csdn.net/suool/article/details/46851335
下节课我们将学习游戏项目中的核心功能场景的逻辑功能分析与实现。

本节课的视频教程地址是:第六课在此
如果本教程有帮助到您,希望您能点击进去观看一下,而且现在注册成为极客学院的会员,验证手机号码和邮箱号码会赠送三天的会员时间,手机端首次也可以领取五天的会员时间哦(即使是购买年会员目前也仅仅是年费260),成为极客学院学习会员可以无限制的下载和观看所有的学院网站的视频,谢谢您的支持!