游戏思考30:技能碰撞检测分类枚举及逆水寒魔兽老兵服副本攻略(英雄武林风云录,后续更新舞阳城、扬州、清明等副本攻略)

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

文章目录

一、技能碰撞检测方式分类讲解

1AABB

  • 定义
    采用一个长方体将物体包裹起来进行两个物体的相交性检测时仅检测物体对应包围盒包裹物体的长方体的相交性。长方体每一个面都是与某个坐标轴平面平行的因此AABB 包围盒又称了 轴对齐包围盒 。
    在这里插入图片描述

  • 备注
    确定 AABB 包围盒就简单多了仅需要记录 6 个值即可这 6 个值分别代表包围盒在每个坐标轴上的最小值与最大值即 xmin、xmax、ymin、ymax、zmin、zmax。也就是说实际物体上所有的点都必须满足以下条件
    在这里插入图片描述

  • 代码计算
    1C++版本检测AABB碰撞

法一:1包围盒
struct stBoundingBox
{
   stBoundingBox () { min[0] = min[1] = min[2] =
                      max[0] = max[1] = max[2] = 0; }
   float min[3];
   float max[3];
};
//检测点是否在包围盒内
// Point inside box.
bool OnCollision(stBoundingBox bb, float x, float y, float z)
{
	if(bb.max[0] <= x) return false;
	if(bb.min[0] >= x) return false;
   if(bb.max[1] <= y) return false;
	if(bb.min[1] >= y) return false;
	if(bb.max[2] <= z) return false;
	if(bb.min[2] >= z) return false;

   // Return true then we have collision.
	return true;	
}
//检测包围盒相撞
// Box on box.
bool OnCollision(stBoundingBox &bb1, stBoundingBox &bb2)
{
   if((bb1.min[0] > bb2.max[0]) || (bb2.min[0] > bb1.max[0]))
      return false;
   if((bb1.min[1] > bb2.max[1]) || (bb2.min[1] > bb1.max[1]))
      return false;
   if((bb1.min[2] > bb2.max[2]) || (bb2.min[2] > bb1.max[2]))
      return false;

   return true;
}
法二:立方体检测
一优点对结构而言对边界框使用4个浮点数需要的空间较少而这是较合理的空间坐标。
二缺点盒子变成了立方体。这样在尝试封装物体时会浪费更多的空间因为需要为深度、宽度和高度使用最
大的尺寸值而不是使用每个方向上所必须的扩展值
这里给出了一个使用4个浮点数以及一个最大、最小数值对来定义和创建边框的方法
struct stBoundingBox
{
    CVector3 min, max;
};

struct stBoundingBox
{
    CVector3 center;
    float size;
};
法三边界求检测
一定义边界球完全围绕在一些几何图形周围它除了不用方
框之外和边界框结构非常相似。边界球结构可以使用4个浮点值
确定。前3个浮点值代表了边界球的中心位置第四个浮点数代表
了边界球的半径
二优点边界框相比较而言边界球在处理碰撞检测和可见度时速度更快
三缺点环绕造成的空间浪费要比边界框多
struct stBoundingSphere
{
    CVector3 center;
    double radius;
};


stBoundingSphere CalculateBoundingSphere(CVector3 *vList, int totalVerts)
{
   float d, maxDistance = 0.0f;
   stBoundingSphere sphere;

   for(int i = 0; i < totalVerts; i++)
      {
         if(vList[i].x < min[0]) min[0] = vList[i].x;
         if(vList[i].x > max[0]) max[0] = vList[i].x;

         if(vList[i].y < min[1]) min[1] = vList[i].y;
         if(vList[i].y > max[1]) max[1] = vList[i].y;

         if(vList[i].z < min[2]) min[2] = vList[i].z;
         if(vList[i].z > max[2]) max[2] = vList[i].z;
      }

   CVector3 center = (max + min) * 0.5f;

   for(i = 0; i < totalVerts; i++)
      {
         d = ((vList[i].x - center.x) * (vList[i].x - center.x)) +
             ((vList[i].y - center.y) * (vList[i].y - center.y)) +
             ((vList[i].z - center.z) * (vList[i].z - center.z));

           if(d > maxDistance)
            maxDistance = d;
      }

   sphere.radius = sqrt(maxDistance);
   sphere.center = center;
   
   return sphere;
}
  • 球体检测综合评价
    如前所述边界球要比边界框更容易处理(碰撞、能见度等)因为对球所做的操作都是比较便宜的CPU相关的。这样在想要快速确定一个物体是否和其他物体发生碰撞或是那个物体是否可见的情况下就最有可能选择使用边界球。某些混合法包括先使用边界球快速拒绝几何图形然后使用边界框进行更准确的测试。如果这两个测试都通过了那么接下来的操作要么是接受物体测试成功要么是将物体分解成更小的块然后分别对围绕这些块的边界框进行测试。当然使用的方法很大程度上取决于程序的要求。取代使用大的球然后是大的边界框可以先使用大的边界球然后再直接使用小一些的边界框。无论如何最初使用边界球进行测试经过证明十分有用因为进行碰撞和可见度测试使用的大量时间对包含大量物体的场景而言都是不够的

2java版本

13D结构体定义
public class Vector3f {
    float x;//三维变量中的x值
    float y;//三维变量中的y值
    float z;//三维变量中的z值
    public Vector3f(float x,float y,float z)
    {
        this.x=x;
        this.y=y;
        this.z=z;
    }
    public void add(Vector3f temp)
    {
        this.x+=temp.x;
        this.y+=temp.y;
        this.z+=temp.z;
    }
}
2包围盒定义
public class AABBBox {
    float minX;//x轴最小位置
    float maxX;//x轴最大位置
    float minY;//y轴最小位置
    float maxY;//y轴最大位置
    float minZ;//z轴最小位置
    float maxZ;//z轴最大位置

    public AABBBox(float[] vertices)
    {
        init();
        findMinAndMax(vertices);
    }

    public AABBBox(float minX,float maxX,float minY,float maxY,float minZ,float maxZ)
    {
        this.minX=minX;
        this.maxX=maxX;
        this.minY=minY;
        this.maxY=maxY;
        this.minZ=minZ;
        this.maxZ=maxZ;
    }
    //初始化包围盒的最小以及最大顶点坐标
    public void init()
    {
        minX=Float.POSITIVE_INFINITY; // 正无穷
        maxX=Float.NEGATIVE_INFINITY; // 负无穷
        minY=Float.POSITIVE_INFINITY;
        maxY=Float.NEGATIVE_INFINITY;
        minZ=Float.POSITIVE_INFINITY;
        maxZ=Float.NEGATIVE_INFINITY;
    }
    //获取包围盒的实际最小以及最大顶点坐标
    public void findMinAndMax(float[] vertices)
    {
        for(int i=0;i<vertices.length/3;i++)
        {
            //判断X轴的最小和最大位置
            if(vertices[i*3]<minX)
            {
                minX=vertices[i*3];
            }
            if(vertices[i*3]>maxX)
            {
                maxX=vertices[i*3];
            }
            //判断Y轴的最小和最大位置
            if(vertices[i*3+1]<minY)
            {
                minY=vertices[i*3+1];
            }
            if(vertices[i*3+1]>maxY)
            {
                maxY=vertices[i*3+1];
            }
            //判断Z轴的最小和最大位置
            if(vertices[i*3+2]<minZ)
            {
                minZ=vertices[i*3+2];
            }
            if(vertices[i*3+2]>maxZ)
            {
                maxZ=vertices[i*3+2];
            }
        }
    }
    //获得物体平移后的AABB包围盒
    public AABBBox getCurrAABBBox(Vector3f currPosition)
    {
        AABBBox result=new AABBBox
                (
                        this.minX+currPosition.x,
                        this.maxX+currPosition.x,
                        this.minY+currPosition.y,
                        this.maxY+currPosition.y,
                        this.minZ+currPosition.z,
                        this.maxZ+currPosition.z
                );
        return result;
    }
}

3碰撞检测函数
 public boolean check(RigidBody ra, RigidBody rb)//true为撞上
    {
        float[] over = calOverTotal
                (
	                // 两个物体的 AABB 包围盒
                        ra.collObject.getCurrAABBBox(ra.currLocation),
                        rb.collObject.getCurrAABBBox(rb.currLocation)
                );
        // 三个方向的交叠值与设定的阈值进行比较
        return over[0] > V_UNIT && over[1] > V_UNIT && over[2] > V_UNIT;
    }
	
	// 传入两个物体的 AABB 包围盒
    public float[] calOverTotal(AABBBox a, AABBBox b) {
        float xOver = calOverOne(a.maxX, a.minX, b.maxX, b.minX);
        float yOver = calOverOne(a.maxY, a.minY, b.maxY, b.minY);
        float zOver = calOverOne(a.maxZ, a.minZ, b.maxZ, b.minZ);
        return new float[]{xOver, yOver, zOver};
    }
	// 计算每个轴方向的交叠值
    public float calOverOne(float amax, float amin, float bmax, float bmin) {
        float minMax = 0;
        float maxMin = 0;
        if (amax < bmax)//a物体在b物体左侧
        {
            minMax = amax;
            maxMin = bmin;
        } else //a物体在b物体右侧
        {
            minMax = bmax;
            maxMin = amin;
        }

        if (minMax > maxMin) {
            return minMax - maxMin;
        } else {
            return 0;
        }
    }

2OBB

  • 定义
    两个凸包多边形当且仅当存在一条线这两个多边形在这条线上的投影不相交则这两个多边形也不相交.
  • 举例
    这里不能取2因为投影会相交可以取1为投影轴
    在这里插入图片描述
    在这里插入图片描述
  • 链接传送门

3像素检测碰撞

  • 使用背景
    1使用像素碰撞检测法算是最精确的算法
    2效率上的低下。除非是在极为特殊的情况下要求使用非常精确的碰撞否则一般情况下在游戏中是不建议使用这种算法特别是在运行效率不太高的HTML5游戏中。

  • 使用顺序
    一般来说在使用像素碰撞检测之前会使用AABB矩形包围盒先检测两个精灵是否有碰撞如果AABB包围盒检测没有碰撞那一定是没有碰撞到反之则不一定需要进一步进行像素检测。如下图所示很明显虽然两个精灵的包围盒发生了碰撞但两个精灵本身没有发生碰撞所以在这种精灵的形状极为不规则的情况下除非使用多边形包围盒并且需要多边形和精灵的形状极为接近才能够获取好的效果而且别忘了多边形只适合凸多边形的情况。
    在这里插入图片描述

  • 定义
    这样我们就只能采用像素检测算法达到精确检测的目的。接下来先来看看像素碰撞的原理首先我们知道所有的精灵都是由像素点组成而在canvas的像素数据中每个点都是由RGBA四个数据组成。如果某个点的Aalpha值透明度为0则表示该点是透明的比如在图6-19中两个精灵的空白部分的点的A值为0。如果两个精灵发生碰撞则表示两个精灵有像素点发生了重叠即两个精灵的像素点坐标相同如下图所示。
    在这里插入图片描述
    根据这个原理基本上我们可以采取以下步骤来进行检测。

1选择需要检测的两个精灵。
2先检测两个精灵是否发生包围盒碰撞如果没有则退出否则获取两个矩形的相交区域并继续。
3把一个精灵绘制到和游戏屏幕等大的空白的后台缓冲区中获取缓冲区中在相交区域的像素数据。
4清除后台缓冲区。
5对另一个精灵进行步骤3的操作。
6得到两个精灵在同一个相交矩形的像素数据后循环比较每一个像素点如果两个精灵在同一位置的透明度不都是0则表示两个精灵有相交退出循环返回真。

  • 备注点
    需要注意的一点是在第3步获取相交区域的像素数据中需要在后台另外的一个和游戏屏幕等大的空白区域中绘制而不能直接获取游戏画面中的相交区域因为两个精灵在相交区域中的像素已经发生了重叠【包围盒】。
  • 注意点
    由以上的算法可以看出在进行像素检测的时候需要另外一个缓冲区把需要检测的精灵绘制一次需要清空缓冲区最后还要使用一个for循环检测像素。如果相交区域为100×100个像素点则最坏的情况需要循环10 000 次由此看来这真不是一个省时的工作。
  • 代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
    <meta charset="UTF-8">
    <title>盒包围碰撞算法-像素检测算法</title>
    <style>
        #stage {
            border: 1px solid lightgray;
        }
    </style>
</head>
<body>
<h1>包围盒是否碰撞<span class="hitTestBox"></span></h1>
<h1>像素检测是否碰撞<span class="hitTestPixel"></span></h1>
<canvas id="stage"></canvas>
<img src="./images/penguin.png" alt="penguinImg" id="penguinImg" style="display:none" />
<img src="./images/giraffe.png" alt="giraffeImg" id="giraffeImg" style="display:none" />
</body>
<script>
    window.onload = function () {
        var stage = document.querySelector('#stage'),
            ctx = stage.getContext('2d');
        stage.width = 600;
        stage.height = 600;
 
        //创建后台canvas
        var bC = document.createElement("canvas");
        bC.width = stage.width;
        bC.height = stage.height;
        var backBuf = bC.getContext("2d");
 
        var penguin = document.querySelector('#penguinImg'),giraffe = document.querySelector('#giraffeImg');
        var penguinImg = {
            x:stage.width/2,
            y:stage.height/2,
            r:128,
            data:null
        },giraffeImg = {
            x:100,
            y:100,
            r:128,
            data:null
        };
 
        function drawImageBox(img,x,y,width,height){
            ctx.beginPath();
            ctx.rect(x,y,width,height);
            ctx.stroke();
            ctx.drawImage(img,x,y,width,height);
        }
        //缓存画布绘制方法
        function drawImageBC(img,x,y,width,height){
            backBuf.clearRect(0,0,stage.width,stage.height);
            backBuf.save();
            backBuf.drawImage(img,x,y,width,height);
            backBuf.restore();
        }
 
        //获取两个矩形相交区域
        function getInRect(x1,y1,x2,y2,x3,y3,x4,y4) {
            return [Math.max(x1,x3),Math.max(y1,y3),Math.min(x2,x4),Math.min(y2,y4)];
        }
 
 
        document.onkeydown = function (event) {
            var e = event || window.event || arguments.callee.caller.arguments[0];
            //根据地图数组碰撞将测
            switch (e.keyCode) {
                case 37:
                    console.log("Left");
                    if (penguinImg.x > 0) {
                        penguinImg.x -= 2;
                    }
                    break;
                case 38:
                    console.log("Top");
                    if (penguinImg.y > 0) {
                        penguinImg.y -= 2;
                    }
                    break;
                case 39:
                    console.log("Right");
                    if (penguinImg.x < stage.width) {
                        penguinImg.x += 2;
                    }
                    break;
                case 40:
                    console.log("Bottom");
                    if (penguinImg.y < stage.height) {
                        penguinImg.y += 2;
                    }
                    break;
 
                default:
                    return false;
            }
        };
        
        stage.addEventListener('click', function (event) {
            var x = event.clientX - stage.getBoundingClientRect().left;
            var y = event.clientY - stage.getBoundingClientRect().top;
            penguinImg.x = x;
            penguinImg.y = y;
        });
 
 
        function update() {
            ctx.clearRect(0, 0, 600, 600);
            drawImageBox(giraffe,giraffeImg.x,giraffeImg.y,giraffeImg.r,giraffeImg.r);
            drawImageBox(penguin,penguinImg.x,penguinImg.y,penguinImg.r,penguinImg.r);
            document.querySelector('.hitTestBox').innerHTML = "否";
            document.querySelector('.hitTestPixel').innerHTML = "否";
            var rect = getInRect(giraffeImg.x,giraffeImg.y,giraffeImg.x+giraffeImg.r,giraffeImg.y+giraffeImg.r,penguinImg.x,penguinImg.y,penguinImg.x+penguinImg.r,penguinImg.y+penguinImg.r)
 
            //如果没有相交则退出
            if(rect[0]>=rect[2]||rect[1]>=rect[3]) {
 
            } else{
                document.querySelector('.hitTestBox').innerHTML = "是";
                giraffeImg.data = null;
                penguinImg.data = null;
                //获取精灵在相交矩形像素数据
                drawImageBC(giraffe,giraffeImg.x,giraffeImg.y,giraffeImg.r,giraffeImg.r);
                giraffeImg.data = backBuf.getImageData(rect[0],rect[1],rect[2],rect[3]).data;
                drawImageBC(penguin,penguinImg.x,penguinImg.y,penguinImg.r,penguinImg.r);
                penguinImg.data = backBuf.getImageData(rect[0],rect[1],rect[2],rect[3]).data;
                for(var i=3;i<giraffeImg.data.length;i+=4)
                {
                    if(giraffeImg.data[i]>0&&penguinImg.data[i]>0){
                        document.querySelector('.hitTestPixel').innerHTML = "是";
                    }
                }
 
            }
            requestAnimationFrame(update);
        }
 
        update();
    };
</script>
</html>

4矩阵变换检测碰撞(打住略)

5Tile地形检测碰撞其实就是九方格遍历查找攻击对象

1头文件中

#include <iostream>

#include "cocos2d.h"

using namespace cocos2d;



class AA:public CCLayer

{

public:

    virtual bool init();

    static CCScene *scene();

    CREATE_FUNC(AA);

  

     CCSprite *_player;

    int count;

    bool mode;

    

    CCArray *bulletArray;

    CCArray *enemyArray;

    CCTMXTiledMap *_tileMap;

    CCTMXTiledMap *_titleMap;

    CCTMXLayer *wall,*foreground;

    CCPoint mapPoint,heroPoint,beginPoint;

     CCLabelTTF *label;

    //碰撞检测

    void detection();

    bool iscallision(CCSprite *mysprite,CCSprite *testsprite);

    CCRect getRect(CCSprite *sprite);



    //触摸事件

    virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);

    virtual void ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent);

    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);

    virtual void ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent);

    

   

    void goon(CCNode *pSender);

    void toggleGame(CCObject *pSender);

    void targetFinish(CCNode *pSender);

};

2实现文件中
//

//  AA.cpp

//  date10

//

//  Created by Student on 14-9-22.

//

//



#include "AA.h"



CCScene *AA::scene()

{

    CCScene *s=CCScene::create();

    AA *layer=AA::create();

    s->addChild(layer);

    return s;

}



bool AA::init()

{

    if(!CCLayer::init())

    {

        return false;

    }

    mode=true;

    //初始化数组

    bulletArray = CCArray::create();

    bulletArray->retain();

    enemyArray = CCArray::create();

    enemyArray->retain();

    //加载瓦片地图

    _tileMap=CCTMXTiledMap::create("ThefirstTiled1.tmx");

    _tileMap->setPosition(mapPoint);

    addChild(_tileMap);

    //读取瓦片地图中的层和对象

    wall=_tileMap->layerNamed("wall");

    foreground=_tileMap->layerNamed("water");

    CCTMXObjectGroup *objects=_tileMap->objectGroupNamed("hero");

    CCDictionary  *spawnPoint=objects->objectNamed("pa");

    heroPoint.x=spawnPoint->valueForKey("x")->floatValue();

    heroPoint.y=spawnPoint->valueForKey("y")->floatValue();

    CCLog("x=%f,y=%f",heroPoint.x,heroPoint.y);

    //加载英雄到界面

    _player=CCSprite::create("www.png");

    _player->setAnchorPoint(CCPoint(0,0));

    _player->setPosition(heroPoint);

    _tileMap->addChild(_player,0);

    //加载敌人到界面

    for(int i=0;i<int(objects->getObjects()->count());i++) //得到敌人的数量

    {

        CCDictionary *enemy=(CCDictionary *)objects->getObjects()->objectAtIndex(i);

        if(enemy->valueForKey("n")->intValue()==1)

        {

            CCSprite *s=CCSprite::create("enemy1.png");

            float x=enemy->valueForKey("x")->floatValue();

            float y=enemy->valueForKey("y")->floatValue();

            s->setPosition(ccp(x,y));

            s->setAnchorPoint(CCPoint(0,0));

            _tileMap->addChild(s,4);

            enemyArray->addObject(s);

            CCActionInterval *move=CCMoveBy::create(0.5,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));

            //goon 表示不断的移动

            CCFiniteTimeAction *func=CCCallFuncN::create(this,callfuncN_selector(AA::goon));

            s->runAction(CCSequence::create(move,func,NULL));

        }

    }

    //加载开关选项

    CCMenuItem *oon,*ooff;

    oon=CCMenuItemImage::create("projectile-button-on.png","projectile-button-on.png");

    ooff=CCMenuItemImage::create("projectile-button-off.png","projectile-button-off.png");

    CCMenuItemToggle *toggle=CCMenuItemToggle::createWithTarget(this,

                                                                menu_selector(AA::toggleGame),

                                                                ooff,oon,NULL);

    CCMenu *menu=CCMenu::create(toggle,NULL);

    menu->setPosition(ccp(oon->getContentSize().width/2,oon->getContentSize().height/2));

    addChild(menu);

    //加入触摸的单例

   CCDirector::sharedDirector()->getTouchDispatcher()->addTargetedDelegate(this, 1, true);

    //碰撞检测的调用

    this->schedule(schedule_selector(AA::detection), 0.2);

    

    

    label=CCLabelTTF::create("0","Arial",20);

    label->setPosition(ccp(CCDirector::sharedDirector()->getWinSize().width-label->getContentSize().width/2,label->getContentSize().height/2));

    addChild(label,10);

    return true;

}

//表示敌人不断移动的距离

void AA::goon(CCNode *pSender)

{

    CCLOG("goon");

CCSprite *s=(CCSprite *)pSender;

    CCActionInterval *move=CCMoveBy::create(0.5,CCPoint(_player->getPosition().x-s->getPosition().x>0?10:-10,_player->getPosition().y-s->getPosition().y>0?10:-10));

    CCFiniteTimeAction *func=CCCallFuncN::create(this,callfuncN_selector(AA::goon));

    s->runAction(CCSequence::create(move,func,NULL));

}



void AA::toggleGame(CCObject *pSender)

{

    mode=mode?false:true;

}



bool AA::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)

{

    beginPoint=pTouch->getLocation();

    return true;

}



void AA::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)

{

    /*

    if(mode)

    {

        //得到先前的坐标00

        CCPoint PP=pTouch->getPreviousLocation();

        //得到当前的坐标

        CCPoint np=pTouch->getLocation();

        //两坐标相减

        CCPoint dp=ccpSub(np, PP);

        //向左为负 右侧为正

        if(_titleMap->getPosition().x+dp.x>-480 &&  _titleMap->getPosition().x+dp.x<0)

        {

            mapPoint=ccp(_titleMap->getPosition().x+dp.x,0);

            _titleMap->setPosition(mapPoint);

        }

    }

     */

    if(mode)

{

        CCPoint pp=pTouch->getPreviousLocation();

        CCPoint np=pTouch->getLocation();

        CCPoint dp=ccpSub(np,pp);

        

        if(_tileMap->getPosition().x+dp.x>-480&&_tileMap->getPosition().x+dp.x<0)

        {

            mapPoint=ccp(_tileMap->getPosition().x+dp.x,0);

            _tileMap->setPosition(mapPoint);

        }

}

}

void AA::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)

{

    /*

     //地图里的坐标00是从左上角开始的

    步骤

    1、判断是否点击

    2、判断点击的位置与英雄的位置的X,Y的差值     比较DX与DY的大小

    3、判断英雄的X做标要大于点击的X坐标  才能向左

    4、判断移动时是否撞击墙和移出地图外

     */

   //获得点击的位置

   

    /*

    CCPoint pp=pTouch->getLocation();

    if(mode)

    {

         //是点击不是滑动  在原地点击下又点击离开

        if(beginPoint.x==pp.x && beginPoint.y==pp.y)//beginPoint是开始触摸的位置

        {

            //—player的位置

            CCPoint pt=_player->getPosition();

           //判断是否 x>y

            if(fabs(pt.x-(pp.x-mapPoint.x))>=fabs( pt.y-(pp.y-mapPoint.y))    )

            {

               点击点向左移动   英雄的X做标要大于点击的X坐标  才能向左

                if(pt.x>=pp.x-mapPoint.x)

                {

                    

                    if(9-_player->getPosition().y/32<10 && 9-_player->getPosition().y/32>=0&&

                       _player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&

                       !(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))//判断是否是地图外面或者是不是墙

                    {

                        _player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

                            count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                    

                }

                else

                {

                    if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&_player->getPosition().x/32+1<50&&_player->getPosition().x/32+1>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32+1,9-_player->getPosition().y/32))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x+32,_player->getPosition().y));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                    

                }

            }

            else

            {

                if(pt.y>=pp.y-mapPoint.y)

                {

                    if(9-_player->getPosition().y/32+1<10&&9-_player->getPosition().y/32+1>=0&&_player->getPosition().x/32<50&&_player->getPosition().x/32>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32+1))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y-32));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                }

                else

                {

                    if(9-_player->getPosition().y/32-1<10&&9-_player->getPosition().y/32-1>=0&&_player->getPosition().x/32<50&&_player->getPosition().x/32>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32-1))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y+32));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                    

                }

            }

            

        }

}

    else

{

CCSprite *s=CCSprite::create("Projectile.png");

s->setPosition(_player->getPosition());

_tileMap->addChild(s,4);

        bulletArray->addObject(s);

float dx=pp.x-_player->getPosition().x;

float dy=pp.y-_player->getPosition().y;

if(dx>0)

{

float lx=32*30-_player->getPosition().x;

float ly=dy/dx*lx;

CCActionInterval *move=CCMoveBy::create(3,ccp(lx+s->getContentSize().width,ly));

CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(AA::targetFinish));

s->runAction(CCSequence::create(move,ff,NULL));

}

else

{

float lx=0-_player->getPosition().x;

float ly=dy/dx*lx;

CCActionInterval *move=CCMoveBy::create(3,ccp(lx-s->getContentSize().width,ly));

CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(AA::targetFinish));

s->runAction(CCSequence::create(move,ff,NULL));

}

}

    */

    

   CCPoint pp=pTouch->getLocation();

if(mode)//移动

{

        if(beginPoint.x==pp.x&&beginPoint.y==pp.y)

        {

            cocos2d::CCPoint pt=_player->getPosition();

            //dx>dy

            if(fabs(pt.x-(pp.x-mapPoint.x))>=fabs(pt.y-(pp.y-mapPoint.y)))

            {

                //左移

                if(pt.x>=pp.x-mapPoint.x)

                {

                    if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&

                       _player->getPosition().x/32-1<50&&_player->getPosition().x/32-1>=0&&

                       !(wall->tileGIDAt(ccp(_player->getPosition().x/32-1,9-_player->getPosition().y/32))))//判断是否是地图外面或者是不是墙  //tileGIDAt表示有没有的意思

                    {

                        //32表示32个像素  表示向左挪动了1个单位

                        _player->setPosition(ccp(_player->getPosition().x-32,_player->getPosition().y));

                         //判断西瓜的和_player相撞

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            //西瓜的位置消失

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

                            count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                }

                //右移

                else

                {

                    if(9-_player->getPosition().y/32<10&&9-_player->getPosition().y/32>=0&&_player->getPosition().x/32+1<50&&_player->getPosition().x/32+1>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32+1,9-_player->getPosition().y/32))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x+32,_player->getPosition().y));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                    

                }

            }

             //dx<dy

            else

            {

                //下移

                if(pt.y>=pp.y-mapPoint.y)

                {

                    if(9-_player->getPosition().y/32+1<10&&9-_player->getPosition().y/32+1>=0&&_player->getPosition().x/32<50&&_player->getPosition().x/32>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32+1))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y-32));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                }

                 //上移

                else

                {

                    if(9-_player->getPosition().y/32-1<10&&9-_player->getPosition().y/32-1>=0&&_player->getPosition().x/32<50&&_player->getPosition().x/32>=0&&!(wall->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32-1))))

                    {

                        _player->setPosition(ccp(_player->getPosition().x,_player->getPosition().y+32));

                        if(foreground->tileGIDAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32)))

                        {

                            foreground->removeTileAt(ccp(_player->getPosition().x/32,9-_player->getPosition().y/32));

count++;

                            CCString *temp=CCString::createWithFormat("%d",count);

                            label->setString(temp->getCString());

                        }

                    }

                    

                }

            }

            

        }

}

    //英雄发射子弹

else

{

CCSprite *s=CCSprite::create("Projectile.png");

s->setPosition(_player->getPosition());

_tileMap->addChild(s,4);

        bulletArray->addObject(s);

float dx=pp.x-_player->getPosition().x;

float dy=pp.y-_player->getPosition().y;

if(dx>0)

{

float lx=32*30-_player->getPosition().x;

float ly=dy/dx*lx;

CCActionInterval *move=CCMoveBy::create(3,ccp(lx+s->getContentSize().width,ly));

CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(AA::targetFinish));

s->runAction(CCSequence::create(move,ff,NULL));

}

else

{

float lx=0-_player->getPosition().x;

float ly=dy/dx*lx;

CCActionInterval *move=CCMoveBy::create(3,ccp(lx-s->getContentSize().width,ly));

CCFiniteTimeAction *ff=CCCallFuncN::create(this,callfuncN_selector(AA::targetFinish));

s->runAction(CCSequence::create(move,ff,NULL));

}

}

}



void AA::targetFinish(CCNode *pSender)

{

    pSender->removeFromParent();

}

void AA::ccTouchCancelled(CCTouch *pTouch, CCEvent *pEvent)

{



}

//碰撞检测

void AA::detection()

{

    /*

     1、英雄与敌人碰撞

     2、子弹与敌人碰撞

     */

    //遍历敌人

    for(int i=0;i<enemyArray->count();i++)

    {

        CCSprite *s=(CCSprite *)enemyArray->objectAtIndex(i);

        //判断英雄是否和敌人碰撞

        if(iscallision(_player, s))

        {

            CCLog("--------aaaaaaaa-------------");

        }

    }

    //创建临时的数组

    CCArray *bulletA=CCArray::create();

    CCArray *enemyA=CCArray::create();

    //遍历子弹

    for(int i=0;i<bulletArray->count();i++)

    {

        CCSprite *bullet=(CCSprite *)bulletArray->objectAtIndex(i);

        //遍历敌人

        for(int j=0;j<enemyArray->count();j++)

        {

            CCSprite *enemy=(CCSprite *)enemyArray->objectAtIndex(i);

            //判断子弹是否和敌人相撞

            if(iscallision(bullet, enemy))

            {

                //这里移除后应该加入数组  否则会崩溃

                enemy->removeFromParent();

                bullet->removeFromParent();

                bulletA->addObject(bullet);

                enemyA->addObject(enemy);

            }

        }

    }

    //从数组中移除子弹

    for(int i=0;i<bulletA->count();i++)

    {

        CCSprite *bullet = (CCSprite *) bulletA->objectAtIndex(i);

        bulletArray->removeObject(bullet);

    }

     //从数组中移除敌人

    for(int i=0;i<enemyA->count();i++)

    {

        CCSprite *enemy = (CCSprite *) enemyA->objectAtIndex(i);

        enemyArray->removeObject(enemy);

    }

}

//碰撞检测

bool AA::iscallision(CCSprite *mysprite,CCSprite *testsprite)

{

    CCRect myrect=mysprite->boundingBox();

    CCRect testrect=testsprite->boundingBox();

    return myrect.intersectsRect(testrect);

}











-----------------------------------
©著作权归作者所有来自51CTO博客作者春蕾夏荷的原创作品请联系作者获取转载授权否则将追究法律责任
Cocos2d-X 瓦片地图使用的实例项目包含碰撞检测移动
https://blog.51cto.com/u_10486491/3217098

二、武林风云录

1老一陈斩槐只有四个机制dps压力不大留爆发打影子就行

1点名红色扇形区域

在这里插入图片描述

2点名红色长条注意最后还有一段大劈

在这里插入图片描述
在这里插入图片描述

3BOSS在百分之80 、50、20血量时会击退玩家会刷新三个输出位置

  • 应对策略
    需要三个输出职业进入篮圈击杀影子
  • 注意点
    ①每个篮圈只能进一个人
    ②如果没在30s内击杀影子影子会爆炸BOSS将释放地图炮导致团灭
    ③进去打影子的队友奶妈是奶不了的需要躲好红圈躲不了平A
    在这里插入图片描述

4BOSS在百分之35血时会吸玩家到其周围释放旋风斩得交解控技能。但是不要着急回去还有一个圆圈的下坠伤害

在这里插入图片描述
在这里插入图片描述

  • 额外注意
    boss释放完技能后原地会生成一个龙卷风靠近会暴毙需要T尽可能的往副本初始位置拉boss
    在这里插入图片描述

2老二醉仙

  • 机制讲解
    boss是软狂暴boss每一次喝酒都会叠加后劲不足buff叠加到12层后会一直放技能而不会平A解茶小厮也不会出现
    在这里插入图片描述
  • 备注
    ①奶妈一定要切天问打好飘絮给boss百分之25增伤
    在这里插入图片描述
    ②四个输出位置平均喝酒后需要3w的秒伤T是第二轮供酒可以喝不然吸引不了仇恨
    在这里插入图片描述
    ③奶妈不要喝酒
    ④喝酒叠加的buff不要满了否则点名必死
    在这里插入图片描述
    ⑤小二都刷新在周边需要把boss往中心拉否则容易误伤小二

1红圈和点名略过

在这里插入图片描述

2输出记得喝酒龙吟内功铁衣外功等

在这里插入图片描述

3每一个奉茶小厮都有名字得按照诗词来按照顺序击杀小二

在这里插入图片描述

3老三楚相玉

  • 备注
    ①老三技能不按照顺序有时得同时处理多个boss

1boss有狂暴机制冰火玄功达到极致倒数360s将直接团灭人均得有1.2Wdps

在这里插入图片描述

2地上出现红圈0.5s后将冒出冰柱击飞造成一段伤害落地造成二段伤害估计代码是设计成击飞后掉落下来还在圆圈内

在这里插入图片描述

3点名T红色长条多段伤害

在这里插入图片描述
在这里插入图片描述

  • 备注
    若红条击中冰柱则冰柱直接消失
    在这里插入图片描述

4烈焰焚身需要交减伤或无敌规避伤害

在这里插入图片描述

5冰风火凤融合产生圆形爆炸区域

在这里插入图片描述

  • 应对
    铁衣或神像击飞或吹走

6赤炎寒光破

全图玩家都被吸附到boss周围得躲到冰柱后面注意得站在冰柱后面否则服务器判断坐标和冰柱重合或稍微飘逸则会死亡这很坑爹
在这里插入图片描述

7暴风雪

得站在地图的火焰点处
在这里插入图片描述

4老四刀狂

1略过半圆斩、三段长条大劈、落地红圈、黑水机制不在赘述

在这里插入图片描述

2达到百分之90血时地上出现追忆碎片分内外场地血河上马溜boss需要奶妈往返内网场用追忆碎片奶安抚boss并奶白剑

在这里插入图片描述

3刀狂有怒气机制到百分之100时增加移速和攻击力

在这里插入图片描述
内场会出现安抚之力需要奶妈拾取
在这里插入图片描述
对boss使用安抚之力boss怒气值清零地上将会掉落追忆草失去后增加玩家治疗量
在这里插入图片描述

4内场讲解

内场将会有白剑npc和各种小怪

白剑场中npc需要玩家治疗她奶满后击败boss后通关
在这里插入图片描述
小怪集火秒掉就行

嗔打死后出现追忆碎片使用后出现治疗圆圈可以治疗玩家和白剑
痴减疗怪
狂秒人怪
贪会回血且会吃掉场上没被使用的追忆碎片

三、舞阳城

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“游戏思考30:技能碰撞检测分类枚举及逆水寒魔兽老兵服副本攻略(英雄武林风云录,后续更新舞阳城、扬州、清明等副本攻略)” 的相关文章