cocos2dx 3.3 tilemap 缩放滑动并且准确点击对象

之前已经有一篇更基础的tilemap笔记了,这两天用了下3.3的tilemap发现以前有些东西又套用不了。所以又写了一篇札记,顿时感觉自己萌萌哒。

完全没有玩过的童鞋可以看看基础篇

主要实现目标:

1. 能够3倍缩放tiledMap

2. 能够鼠标滑动 tiledMap

3. 在缩放和滑动的情况下,点击一个tile 能够判断出 实际的格子坐标。

缩放和滑动这里就不再详细解释了,有很多的例子,末尾呈上完整代码。主要说一下第三条的实现。

可以从图中看出,我建了一个points对象组,然后建立了两个对象 startPos 和endPos

startPos 大概覆盖了 4个tiled   [0,24] [1,24] [0,25] [1,25]

并且给startPos设置了一个 自定义属性:id 。我需要的就是点击到 上面4块tiled的时候能够 获取到这个对象的id值。

     

首先写了个函数来读地图对象

void HelloWorld::parseTileMap()
{
    CCLOG("parseTileMap");
    if(_tiledMap == NULL)
        return;

    _objectsGroup = _tiledMap->getObjectGroup("points");

    //tileX 0  tileY 24
    ValueMap startPos = _objectsGroup->getObject("startPos");
    std::string name = startPos["name"].asString();
    float pointX = startPos["x"].asFloat();
    float pointY = startPos["y"].asFloat();;
    float PointWidth = startPos["width"].asFloat();
    float PointHeight = startPos["height"].asFloat();

    Size winSize = Director::getInstance()->getWinSize();
    Point mapPoint = _tiledMap->getPosition();
    Point centerPos = covertTiledPointToCenterPoint(Point(0,24));
    Point tilePos = covertPointToTiledPoint(Point(pointX,pointY));
    Point tilePos2 = covertPointToTiledPoint(centerPos);
}

很顺利的拿到startPos对象的 pointX 和  pointY , 但是值却是  (0,296) , 不是期待的(1,768) 忽然有点凌乱 -_- !!了。

直到看了一下源码TMXLayer 的getPositionAt才发现,原来这个(0,296) 是已经经过 “分辨率转换“了。

Vec2 TMXLayer::getPositionAt(const Vec2& pos)
{
    Vec2 ret = Vec2::ZERO;
    switch (_layerOrientation)
    {
    case TMXOrientationOrtho:
        ret = getPositionForOrthoAt(pos);
        break;
    case TMXOrientationIso:
        ret = getPositionForIsoAt(pos);
        break;
    case TMXOrientationHex:
        ret = getPositionForHexAt(pos);
        break;
    case TMXOrientationStaggered:
        ret = getPositionForStaggeredAt(pos);
        break;
    }
    CCLOG("%f,%f,%f",ret.x,ret.y,CC_CONTENT_SCALE_FACTOR());

    ret = <span style="color:#ff0000;">CC_POINT_PIXELS_TO_POINTS</span>( ret );
    return ret;
}

看一下宏的定义:

/** @def CC_POINT_PIXELS_TO_POINTS
 Converts a rect in pixels to points
 */
#define CC_POINT_PIXELS_TO_POINTS(__pixels__)                                    Vec2( (__pixels__).x / CC_CONTENT_SCALE_FACTOR(), (__pixels__).y / CC_CONTENT_SCALE_FACTOR())

/** @def CC_CONTENT_SCALE_FACTOR
On Mac it returns 1;
On iPhone it returns 2 if RetinaDisplay is On. Otherwise it returns 1
*/
#define CC_CONTENT_SCALE_FACTOR() Director::getInstance()->getContentScaleFactor()

从源码可以看到:

1 . 我们可以确定的是tilemap 上面 pixel : point 的比例是  1 : 1, 而设备上面却并不一定。

mac 设备上面 pixel : point = 1: 1 , iphone Retina 是 2 : 1, 低分辨率就会更大。我们就把这个比值像素尺寸因子吧

2. 通过 CC_POINT_PIXELS_TO_POINTS 能够把 tilemap上面的坐标值转换成 设备上面的坐标值。

3. 这个setScale getScale做的是类似的事情,但是要区分开来计算。

此外,因为我们的tilemap可以滑动点击,所以在从触摸点转换 tilemap绝对坐标的时候需要额外做两点:

1.  把tilemapLayer的坐标作为偏移量

bool HelloWorld::onTouchBegan(Touch *touch, Event  *event)
{
    CCLOG("HelloWorld::onTouchBegan");
    Point touchPoint = touch->getLocation();
    Point mapPoint = _tiledMap->getPosition();
  <span style="color:#ff0000;">  Point realPoint = touchPoint - mapPoint;</span>
    Point tilePoint = covertPointToTiledPoint(realPoint);
    CCLOG("tilePoint x:%f y:%f",tilePoint.x,tilePoint.y);

    tryGetObjectPropertyByPosition(realPoint);
    return true;
}

2. &#8;乘以缩放系数

//参数:触摸坐标
string HelloWorld::tryGetObjectPropertyByPosition(Point position)
{
    float scale = _tiledMap->getScale();
    float factor = CC_CONTENT_SCALE_FACTOR();

<span style="color:#ff0000;">    float realPointX = position.x / scale;
    float realPointY = position.y / scale;</span>

    for (auto item : _objectsGroup->getObjects())
    {
        ValueMap curObject = item.asValueMap();
        float pointX = curObject["x"].asFloat();
        float pointY = curObject["y"].asFloat();;
        float PointWidth = curObject["width"].asFloat();
        float PointHeight = curObject["height"].asFloat();

        if(realPointX >= pointX and realPointX <= pointX + PointWidth
           and realPointY >= pointY and realPointY <= pointY + PointHeight)
        {
            string objectId = curObject["id"].asString();
            CCLOG("HelloWorld:tryGetObjectPropertyByPosition: %s",objectId.c_str());
            return objectId;
        }
    }
    return "";
}

接下来再逆推一下从 触摸点 转换到 tilemapPoint 的方法就非常简单了

Point HelloWorld::covertTiledPointToCenterPoint(Point p)
{
    float scale = _tiledMap->getScale();
    float factor = CC_CONTENT_SCALE_FACTOR();

    CCLOG("HelloWorld::covertTiledPointToCenterPoint scale:%f factor:%f",scale,factor);

    int offsetX = _tiledMap->getTileSize().width / (2 * factor);
    int offsetY = _tiledMap->getTileSize().height / (2 * factor);
    TMXLayer* layer = _tiledMap->layerNamed("background");
    Point point = layer->getPositionAt(p);

    point = Point(point.x  + offsetX,point.y - offsetY);
    point = Point(point.x * scale, point.y * scale);
    return point;
}

源码

时间: 2024-08-07 16:04:27

cocos2dx 3.3 tilemap 缩放滑动并且准确点击对象的相关文章

cocos2d-x项目101次相遇:3.0 的点击事件,CCTouchDelegate已经停用了

cocos2d-x 101次相遇 / 目录 1   安装和环境搭建 -xcode 2   Scenes , Director, Layers, Sprites3   建立图片菜单 4   在HelloWorld上--建立新场景 5   增加一个精灵sprite 5.1   缩小sprite并使之完整显示6   action ,移动sprite 7   3.0 的点击事件,CCTouchDelegate已经停用了8   使用触摸事件移动 精灵 cocos2d-x 3.0 不再使用 TouchDel

AndroidのListView之滑动列表项(点击事件和滑动事件共存) - bvin

返回脚本百事通 这里正好在项目有这么一个bt的需求,如下图ListView的item可以响应点击事件也可以响应item的左右滑动事件,两个事件可以相互独立互不影响. 听说iphone的list选项就有这样bt的功能,安卓版的手机QQ和微信和QQ通讯录也有类似的效果,在网上各种寻早方案都试过,要不只能滑动不能点击要么就只能点击不能滑动,而且操作很不灵敏,网上的代码都是在itemView的onTouch方法里处理,判断down和up的像素差.其实这样操作相当不便,down-up这样的其实只能算拖动事

防止滑动的时候触发点击事件

手机端在滑动过程中容易引发点击事件 解决方案: 重新封装一个点击函数 //防止滑动的时候触发点击事件 function tap(sprite, cb) { var tapStartTime = 0, tapEndTime = 0, tapTime = 300, //tap等待时间,在此事件下松开可触发方法 tapStartClientX = 0, tapStartClientY = 0, tapEndClientX = 0, tapEndClientY = 0, tapScollHeight =

【Cocos2dx】使用CCControlButton创建按钮、按钮点击事件,点击事件中的组件获取,setPosition的坐标问题

按钮不仅在游戏,在任何地方都是不可或缺却又是最基本的东西.在游戏引擎Cocos2dx中也不例外. 下面用一个例子说明Cocos2dx中如何使用按钮,同时,如果在Cocos2dx中获取层,也就是场景.舞台中的组件. 如下图,有一个按钮Clickme,被点击时候与不被点击的时间,其背景图片是不同的.其实就是资源文件夹Resource中早就被玩坏的两个图片,一张CloseNormal.png一张CloseSelected.png被拉伸后的惨状. Cocos2dx的资源文件夹在<[Cocos2dx]资源

如何准确计算Java对象的大小

     有时,我们需要知道Java对象到底占用多少内存,有人通过连续调用两次System.gc()比较两次gc前后内存的使用量在计算java对象的大小,也有人根据Java虚拟机规范中的Java对象内存排列估算对象的大小,这两种方法或多或少都有问题,因为System.gc()并不一定促发GC,同一个类型的对象在32位与64位JVM中使用的内存会不一样,在64位虚拟机中是否开启指针压缩也会影响Java对象在内存中的大小. 那么有没有一种既准确又方便的方法计算对象的大小呢?答案是肯定的.在Java

学习笔记:Unity战斗卡牌游戏(二)-----滑动列表及克隆删除对象以及代码添加脚本

鼠标悬浮.点击放大特效 Button Scale: 按钮点击事件 将新建的Login脚本挂到Scene下: 方法一: 1)获取输入框及按钮 2) 注册监听器,绑定的是BoxCollider的gameObject 3) 填写按钮事件 private UIInput input1; private UIInput input2; void Start () { // 1)获取输入框及按钮 input1 = transform.Find("Input1").GetComponent<U

cocos2d-x LUA Binding实现C++里访问LUA的自定义对象

LUA Binding比JSBinding要简单,无论是使用脚本自动绑定还是手动写绑定代码,都能很轻松实现在LUA访问C++的类和对象.但如果想在C++里访问LUA里的自定义类和对象,则需要再自己修改一下C++的代码了. 应用场景: 1.  假设在LUA里有一个类MyLayer,继承了CCLayer,并添加了a,b,c,d这4个属性. 2.在LUA里,创建一个MyLayer的实例对象,并添加到当前的Scene中,然后通过Scene.getChildByTag方法拿出这个MyLayer的实例对象时

tilemap坐标转换

像素点跟tile的索引之间的转换//从cocos2d-x坐标转换为Tilemap坐标CCPoint GameMap::tileCoordForPosition(CCPoint position){ int x = position.x / this->getTileSize().width; int y = (((this->getMapSize().height) * this->getTileSize().height) - position.y) / this->getTil

cocos2d-x使用tile map总结

cocos2d-x使用tile map总结 使用tile map来做游戏能大大提高开发效率的,最近新开发的游戏也使用tile map来开发. 根据自己的使用过tile map的经验和参考一些资料,总结一下用法包括: 1 最基本的是做游戏地图,导入素材之后,用刷子刷出自己需要的地形图:创建地图和背景层的代码例子如下: auto tileMap = TMXTiledMap::create("try1.tmx"); auto backgoround = tileMap->getLaye