cocos2dx - 伤害实现


http://www.cnblogs.com/stratrail/p/5065911.html

本节主要讲如何通过创建简单的矩形区域来造成伤害

  在小游戏中简单的碰撞需求应用Box2d等引擎会显得过于臃肿复杂,且功能不是根据需求定制,还要封装,为此本节讲述一下如何自己实现简单的碰撞,来达到伤害效果

这里先看下效果图:

一、定义小组类别

  定义如下:

// 组别mask enum enGroupMask { GROUP_NONE = 0x0000,GROUP_PLAYER = 0x00010x0002 
    
  

  用二进制位来定义小组,方便后面判断用位快速判断。

二、定义CBody类用于碰撞实现

  代码如下:

#ifndef __CBody_H__
#define __CBody_H__
#include "IGameDef.h"
#include cocos2d.h"
#define DRAW_BODY 1
#ifdef DRAW_BODY 
#include GLES-Render.h#endif

USING_NS_CC;
class CBody : public Node
{
public:
    // implement the "static create()" method manually
    CREATE_FUNC(CBody);

    virtual bool init();

    void SetRect(float x,float y,255); line-height:1.5!important">float w,255); line-height:1.5!important">float h){ m_cRect = Rect(x,y,w,h); }

    void SetGroupMask(enGroupMask nGroupMask){ m_nGroupMask = nGroupMask; }

    enGroupMask GetGroupMask() const{ return m_nGroupMask; }

    enGroupMask CanContactGroup() const;

    判断是否可以碰撞该类别
    bool IsGroupCanContact(enGroupMask nGroupMask)  const Rect GetRect()  判断矩形是否交叉
    bool IntersectsRect(const Rect& rect)  void SetContactCallback(const std::function<void(CBody*)>& callback){ m_constactFunc = callback; }

     碰撞回调函数
    void OnContact(CBody* pBody);


     绘制矩形区域
#ifdef DRAW_BODY 
    void draw(Renderer *renderer,255); line-height:1.5!important">const Mat4& transform,uint32_t flags);
    virtual    void onDraw(const Mat4 &transform,uint32_t flags);
#endif

private:

    CBody();
    ~CBody();

#ifdef DRAW_BODY 
    CustomCommand m_pCustomCommand;
    b2Draw* m_debugDraw;
#endif
     
    Rect m_cRect;

    std::function<void(CBody*)> m_constactFunc;

    enGroupMask        m_nGroupMask;
};


#endif __CBody_H__

关键实现有以下几个:

  1、用位快速判断是否可以产生碰撞

bool CBody::IsGroupCanContact(enGroupMask nGroupMask)  const { return nGroupMask&CanContactGroup(); }

  2、获取矩形实际的坐标,利用cocos2dx矩形相交判断方法,判断重叠

const Rect CBody::GetRect() constVec2& pt =this->convertToWorldspace(this->getPosition()); return Rect(pt.x + m_cRect.origin.x,pt.y + m_cRect.origin.y,m_cRect.size.width,m_cRect.size.height); } bool CBody::IntersectsRect(const Rect& rect) const { return GetRect().intersectsRect(rect); }

  3、将创建的CBody类添加到管理中vector的实例m_vBody管理

CBody::~CBody() { CBattleMgr::getInstance()->EreaseBody(this); #ifdef DRAW_BODY if (m_debugDraw) { delete m_debugDraw; m_debugDraw = NULL; } #endif } bool CBody::init() { #ifdef DRAW_BODY m_debugDraw = new GLESDebugDraw(1.0); #endif CBattleMgr::getInstance()->InsertBody(this); return true; }

  同时每帧在管理类中的update进行碰撞判断如下:

void CBattleMgr::update(float dt) { while (m_vBody.size()>0) { size_t nLast = m_vBody.size() - 1; CBody* pBody = m_vBody[nLast]; m_vBody.pop_back(); if (pBody) { m_vSwapBody.push_back(pBody); for (size_t i = 0; i < nLast; ++i) { CBody* pTempBody = m_vBody[i]; if (pTempBody ) { bool hurt1 = pTempBody->IsGroupCanContact(pBody->GetGroupMask()); bool hurt2 = pBody->IsGroupCanContact(pTempBody->GetGroupMask()); if ((hurt1 || hurt2)&&pTempBody->IntersectsRect(pBody->GetRect())) { if (hurt1) { pTempBody->OnContact(pBody); } if (hurt2) { pBody->OnContact(pTempBody); } } } } } } m_vSwapBody.swap(m_vBody); }

  上述代码通过2个vector管理CBody,在update时进行一次判断碰撞并调用OnContact方法

  4、为了方便显示上图的灰色矩形框需要用以下的类进行显示图形

/*
* copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
*
* iPhone port by Simon Oliver - http://www.simonoliver.com - http://www.handcircus.com
*
* This software is provided 'as-is',without any express or implied
* warranty.  In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,* including commercial applications,and to alter it and redistribute it
* freely,subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product,an ackNowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such,and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/

#ifndef RENDER_H
#define RENDER_H

#include Box2D/Box2D.h"

struct b2AABB;

 This class implements debug drawing callbacks that are invoked
 inside b2World::Step.
class GLESDebugDraw : public b2Draw
{
    float32 mRatio;
    cocos2d::GLProgram* mShaderProgram;
    GLint        mColorLocation;

    void initShader( void );
public:
    GLESDebugDraw();

    GLESDebugDraw( float32 ratio );

    void Drawpolygon(const b2Vec2* vertices,255); line-height:1.5!important">int vertexCount,255); line-height:1.5!important">const b2Color& color);

    void DrawSolidpolygon(void DrawCircle(const b2Vec2& center,float32 radius,255); line-height:1.5!important">void DrawSolidCircle(const b2Vec2& axis,255); line-height:1.5!important">void DrawSegment(const b2Vec2& p1,255); line-height:1.5!important">const b2Vec2& p2,255); line-height:1.5!important">void DrawTransform(const b2Transform& xf);

    void DrawPoint(const b2Vec2& p,float32 size,255); line-height:1.5!important">void DrawString(int x,255); line-height:1.5!important">int y,255); line-height:1.5!important">char* string,...); 

    void DrawAABB(b2AABB* aabb,255); line-height:1.5!important">const b2Color& color);
};


#endif

 * copyright (c) 2006-2007 Erin Catto 
 *
 * iPhone port by Simon Oliver - 
 *
 * This software is provided 'as-is',without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * Permission is granted to anyone to use this software for any purpose,and to alter it and redistribute it
 * freely,subject to the following restrictions:
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product,an ackNowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such,and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

#include "
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

USING_NS_CC;

GLESDebugDraw::GLESDebugDraw()
    : mRatio( 1.0f )
{
    this->initShader();
}

GLESDebugDraw::GLESDebugDraw( float32 ratio )
    : mRatio( ratio )
{
    this->initShader();
}

void GLESDebugDraw::initShader( void )
{
    mShaderProgram = GLProgramCache::getInstance()->getGLProgram(GLProgram::SHADER_NAME_POSITION_U_COLOR);

    mColorLocation = glGetUniformlocation( mShaderProgram->getProgram(),u_color");
}

void GLESDebugDraw::Drawpolygon(const b2Vec2* old_vertices,255); line-height:1.5!important">const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    b2Vec2* vertices = new b2Vec2[vertexCount];
    for( int i=0;i<vertexCount;i++) 
    {
        vertices[i] = old_vertices[i];
        vertices[i] *= mRatio;
    }

    mShaderProgram->setUniformlocationWith4f(mColorLocation,color.r,color.g,color.b,128); line-height:1.5!important">1);

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,2,GL_FLOAT,GL_FALSE,128); line-height:1.5!important">0,vertices);
    glDrawArrays(GL_LINE_LOOP,vertexCount);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,vertexCount);


    CHECK_GL_ERROR_DEBUG();

    delete[] vertices;
}

void GLESDebugDraw::DrawSolidpolygon(0;i<vertexCount;i++) {
        vertices[i] = old_vertices[i];
        vertices[i] *= mRatio;
    }
    
    mShaderProgram->setUniformlocationWith4f(mColorLocation,color.r*0.5f,color.g*0.5f);

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,vertices);

    glDrawArrays(GL_TRIANGLE_FAN,vertexCount);

    mShaderProgram->setUniformlocationWith4f(mColorLocation,128); line-height:1.5!important">1);
    glDrawArrays(GL_LINE_LOOP,vertexCount*2);

    CHECK_GL_ERROR_DEBUG();

    void GLESDebugDraw::DrawCircle(const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    const float32 k_segments = 16.0f;
    int vertexCount=16;
    const float32 k_increment = 2.0f * b2_pi / k_segments;
    float32 theta = 0.0f;
    
    GLfloat*    glVertices = new GLfloat[vertexCount*2];
    int i = 0; i < k_segments; ++i)
    {
        b2Vec2 v = center + radius * b2Vec2(cosf(theta),sinf(theta));
        glVertices[i*2]=v.x * mRatio;
        glVertices[i*2+1]=v.y * mRatio;
        theta += k_increment;
    }
    
    mShaderProgram->setUniformlocationWith4f(mColorLocation,128); line-height:1.5!important">1);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,glVertices);

    glDrawArrays(GL_LINE_LOOP,vertexCount);

    CHECK_GL_ERROR_DEBUG();

    delete[] glVertices;
}

void GLESDebugDraw::DrawSolidCircle(0.5f);
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,glVertices);
    glDrawArrays(GL_TRIANGLE_FAN,vertexCount);


    mShaderProgram->setUniformlocationWith4f(mColorLocation,vertexCount);

     Draw the axis line
    DrawSegment(center,center+radius*axis,color);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(void GLESDebugDraw::DrawSegment(const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformsForBuiltins();

    mShaderProgram->setUniformlocationWith4f(mColorLocation,128); line-height:1.5!important">1);

    GLfloat    glVertices[] = 
    {
        p1.x * mRatio,p1.y * mRatio,p2.x * mRatio,p2.y * mRatio
    };
    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,glVertices);

    glDrawArrays(GL_LInes,128); line-height:1.5!important">0,128); line-height:1.5!important">2);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,128); line-height:1.5!important">2);

    CHECK_GL_ERROR_DEBUG();
}

void GLESDebugDraw::DrawTransform(const b2Transform& xf)
{
    b2Vec2 p1 = xf.p,p2;
    const float32 k_axisScale = 0.4f;
    p2 = p1 + k_axisScale * xf.q.GetXAxis();
    DrawSegment(p1,p2,b2Color(0));

    p2 = p1 + k_axisScale * xf.q.GetYAxis();
    DrawSegment(p1,128); line-height:1.5!important">0));
}

void GLESDebugDraw::DrawPoint(1);

        glPointSize(size);

    GLfloat                glVertices[] = {
        p.x * mRatio,p.y * mRatio
    };

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,glVertices);

    glDrawArrays(GL_POINTS,128); line-height:1.5!important">1);
        glPointSize(1.0f);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1);

    CHECK_GL_ERROR_DEBUG();
}

void GLESDebugDraw::DrawString(char *    NSLog(@"DrawString: unsupported: %s",string);
    printf(string);
     Unsupported as yet. Could replace with bitmap font renderer at a later date */
}

void GLESDebugDraw::DrawAABB(b2AABB* aabb,128); line-height:1.5!important">1);

    GLfloat                glVertices[] = {
        aabb->lowerBound.x * mRatio,aabb->lowerBound.y * mRatio,aabb->upperBound.x * mRatio,aabb->upperBound.y * mRatio,aabb->lowerBound.x * mRatio,aabb->upperBound.y * mRatio
    };

    glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION,glVertices);
    glDrawArrays(GL_LINE_LOOP,128); line-height:1.5!important">4);

    CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(4);

    CHECK_GL_ERROR_DEBUG();
}

  然后在CBodydraw中做如下处理进行绘制

#ifdef DRAW_BODY 
void CBody::onDraw(if (m_debugDraw)
    {
        b2Vec2 vs[4];
        const Rect rect = GetRect();
        vs[0].Set(rect.origin.x,rect.origin.y);
        vs[1].Set(rect.origin.x + rect.size.width,128); line-height:1.5!important">2].Set(rect.origin.x + rect.size.width,rect.origin.y + rect.size.height);
        vs[3].Set(rect.origin.x,rect.origin.y + rect.size.height);
        m_debugDraw->DrawSolidpolygon(vs,128); line-height:1.5!important">4,b2Color(0.6f,128); line-height:1.5!important">0.6f));
    }
}
void CBody::draw(Renderer *renderer,uint32_t flags)
{
    _globalZOrder
    m_pCustomCommand.init(30);
    m_pCustomCommand.func = CC_CALLBACK_0(CBody::onDraw,255); line-height:1.5!important">this,transform,flags);
    renderer->addCommand(&m_pCustomCommand);
}
#endif

  5、最后在Monster实体类init添加CBody的实例,即可为其添加碰撞形状。

如下:

        m_pBody = CBody::create();
        m_pBody->SetGroupMask(enGroupMask::GROUP_MONSTER);
        m_pBody->SetRect(-100,-200,128); line-height:1.5!important">200);
        this->addChild(m_pBody);

三、定义Cdamage用于创建伤害

主要实现以下方法:

#ifndef __Cdamage_H__
#define __Cdamage_H__
#include Body.h"
#include <set>
USING_NS_CC;
class Cdamage : public Node
{
 implement the "static create()" method manually
    CREATE_FUNC(Cdamage);

    void update(float dt);

    float h);

    void SetGroupMask(enGroupMask nGroupMask);

    void OnContact(CBody* pBody);
private:

    Cdamage();
    ~Cdamage();

    int m_nDieTime;  伤害区域消失时间
 CBody  *m_pBody;

    std::set<CBody*>    m_sContact;
};
#endif __Cdamage_H__

关键点:
  1、m_nDieTime在update中实现控制伤害区域存在时间

  2、m_sContact控制一个Cdamage实例对每个实体仅造成一次伤害。

在怪物等攻击动作中添加事件并在事件回调中添加如下代码创建伤害

void CEntity::ActionEvent(Frame *frame) { cocostudio::timeline::EventFrame* evnt = dynamic_cast<cocostudio::timeline::EventFrame*>(frame); if (!evnt) return; std::string str = evnt->getEvent(); if (str == attack") { auto damage = Cdamage::create(); damage->SetRect(-200); damage->SetGroupMask(m_nGroupMask); if (this->getScaleX()<0) { damage->setPositionX(-100); } this->addChild(damage); } }

添加事件方法,即在特定帧添加以下的帧事件
  

至此游戏的基本元素已经都有了。

剩下的自己可以进行扩展了,如:血量为0时,播放死亡动画,并显示失败等。

  

在怪物死亡创建一个新的怪物:

  

相关文章

    本文实践自 RayWenderlich、Ali Hafizji 的文章《...
Cocos-code-ide使用入门学习地点:杭州滨江邮箱:appdevzw@1...
第一次開始用手游引擎挺激动!!!进入正题。下载资源1:从C...
    Cocos2d-x是一款强大的基于OpenGLES的跨平台游戏开发...
1.  来源 QuickV3sample项目中的2048样例游戏,以及最近《...
   Cocos2d-x3.x已经支持使用CMake来进行构建了,这里尝试...