cocos2d-x+lua 实现两点触控缩放

来源:互联网 发布:石器时代linux服务端 编辑:程序博客网 时间:2024/06/05 18:19

cocos2d-x 版本为 3.0

刚开始要做这个效果时个人觉得这种效果网上应该有现成的就搜了一个来用,结果不是那么回事,后来就自己写了,个人觉得效果还不错

先看看我是怎么把C++绑定到lua中的吧

  const luaL_reg global_functions [] = {        {"fuck", fuck},        {NULL, NULL}    };

下面这个得是静态的

int AppDelegate::fuck(lua_State* lua_state){    auto layer = (Layer*)tolua_tousertype(lua_state, 1, 0);    // 被拖拽的大地图    auto home_layer = (Layer*)tolua_tousertype(lua_state, 2, 0);    HomeLayer* fuck = HomeLayer::create(layer, home_layer);    layer->addChild(fuck);    return 0;}
好了,这样就可心在lua中调用这个fuck了,唉。。。。对luabinding不熟,团队出急于出效果,看了看引擎中自己绑定的print我就依葫芦画瓢来了这么几句,选这么着吧,以后慢慢研究,我要实现的是类COC中的大地图的缩放以及拖拽效果,在这个版本中,多点触控的接口并没有暴露给lua,我自己呢又没有能力把这块给实现了,于是就交给C++来做了,

本案例是通过把触点转化为圆来解决,个人感觉这是一个巧妙的方法,因为其它的方法我也用过,就觉得这样处理很方便,实现的效果和COC差不多

CZHome.h

#ifndef __CCZ_LUA__CZHome__#define __CCZ_LUA__CZHome__#include <iostream>#include "cocos2d.h"USING_NS_CC;struct Circle{    Circle()    {        cleanup();    }    Point _center_point;    // 圆心    float _d;    void cleanup()    {        _d = -1;            // 直径    }};class HomeLayer:public Layer{public:    static HomeLayer* create(Layer* layer, Layer* home_layer);    void onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event);    void onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event);    void onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event);    void onTouchesCancelled(const std::vector<Touch *> &touches, Event *unused_event);    // 调整被拖拽节点的位置    void fixPosition();    // 根据尺寸来得到被拖拽节点的正确摆放位置    Point getFixPosition(float scale);private:    // 根据两点触点来设置一个圆    void setCircle(Point& point1, Point& point2, Circle& circle);    // 屏幕中的触点数量发生了变化    void onTouchesCountChange();    // 被拖拽节点的父节点    Layer* _layer;    // 被拖拽的节点    Layer* _home_layer;    // 存放当前屏幕中的所有触点    std::map<int, Touch> _touches;    // 被拖拽节点在开始被拖拽时的尺寸    float _scale;    // 开始拖拽时的圆    Circle _circle_began;    // 拖拽过程中的圆    Circle _circle;};#endif /* defined(__CCZ_LUA__CZHome__) */

CZHome.cpp

#include "CZHome.h"HomeLayer* HomeLayer::create(Layer* layer, Layer* home_layer){    auto ret = new HomeLayer();    ret->init();    // 初始尺寸为0.5    ret->_scale = 0.5;    ret->_home_layer = home_layer;    // 注册触摸事件监听器    auto listener = EventListenerTouchAllAtOnce::create();    listener->onTouchesBegan = CC_CALLBACK_2(HomeLayer::onTouchesBegan, ret);    listener->onTouchesMoved = CC_CALLBACK_2(HomeLayer::onTouchesMoved, ret);    listener->onTouchesEnded = CC_CALLBACK_2(HomeLayer::onTouchesEnded, ret);    listener->onTouchesEnded = CC_CALLBACK_2(HomeLayer::onTouchesCancelled, ret);    layer->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listener, ret);    return ret;}void HomeLayer::setCircle(Point& point1, Point& point2, Circle& circle){    // 圆心为两点的中心点    circle._center_point = point1.getMidpoint(point2);    // 直径为两点的距离    circle._d = point1.getDistance(point2);}void HomeLayer::onTouchesCountChange(){    // 如果当前屏幕中没有触点    if (!_touches.size())    {        return;    }    // 不管屏幕中的触点有几个, 这里只取两个,拖拽节点被这两个点控制    std::map<int, Touch>::iterator it = _touches.begin();    auto touch1 = it->second;    auto point1 = touch1.getLocation();    ++it;    if (it != _touches.end())    {        auto touch2 = it->second;        auto point1_began = _touches.find(touch1.getID())->second.getLocation();        auto point2_began = _touches.find(touch2.getID())->second.getLocation();        setCircle(point1_began, point2_began, _circle_began);        setCircle(point1_began, point2_began, _circle);    }    else    {        // 如果只有一个触点,就认为是一个直径为0的圆        setCircle(point1, point1, _circle);    }    // 使圆点心为被拖拽节点的锚点并重新设置其位置使其在屏幕中的位置不发生变化    auto point = _circle._center_point;    auto relative_point = _home_layer->convertToNodeSpace(point);    Size size = _home_layer->getContentSize();    _home_layer->setAnchorPoint(Point(relative_point.x / size.width, relative_point.y / size.height));    _home_layer->setPosition(point);    _scale = _home_layer->getScale();}void HomeLayer::onTouchesBegan(const std::vector<Touch*>& touches, Event *unused_event){    for(auto &touch: touches)    {        _touches.insert(std::make_pair(touch->getID(), *touch));    }    onTouchesCountChange();    // 这本来没有必要加的, 但是在这个版本中当屏幕中有5个触点时有BUG,不信的可以到TestCpp里去测试一下    if (_touches.size() >= 5)    {        _touches.clear();    }}void HomeLayer::onTouchesMoved(const std::vector<Touch*>& touches, Event *unused_event){    if (!_touches.size())    {        return;    }    for (auto &item: touches)    {        auto touch = item;        // 找到这点的最开始按下的那个点        _touches.find(touch->getID())->second = *touch;    }    std::map<int, Touch>::iterator it = _touches.begin();    auto point1 = it->second.getLocation();    ++it;    if (it != _touches.end())    {        auto point2 = it->second.getLocation();        setCircle(point1, point2, _circle);        // 根据圆的直径的变化来对被拖拽节点进行缩放的控制        float scale = _circle._d / _circle_began._d * _scale ;        // 适当调整变化的比例,这个只是为了更好的玩家体验而加的        scale = _scale + (scale - _scale) * 0.45;        if (scale < 0.5)        {            // 当尺寸到达下界时,减小缩小的速度 0.03 感觉还不错 你也可以自己调整            scale = 0.5 + (scale - 0.5) * 0.03;        }        else if (scale > 1)        {            // 当尺寸到达上界时,减小放大的速度            scale = 1 + (scale - 1) * 0.03;        }        _home_layer->setScale(scale);    }    else    {        setCircle(point1, point1, _circle);    }    _home_layer->setPosition(_circle._center_point);    fixPosition();}void HomeLayer::onTouchesEnded(const std::vector<Touch*>& touches, Event *unused_event){    if (!_touches.size())    {        return;    }    for (auto &touch: touches)    {        _touches.erase(touch->getID());    }    onTouchesCountChange();    auto scale = _home_layer->getScale();    if (scale < 0.5)    {        scale = 0.5;    }    else if (scale > 1)    {        scale = 1;    }    // 实现弹性效果,在COC中只有放大到极限才有弹性效果,缩小到极限就没有了,我这里都加上了,觉得这样界面更活跃一点    float time = 0.2;    auto scale_to = ScaleTo::create(time, scale);    // 之所以要加这个move_to是为了在尺寸变化的同时,被拖拽节点的位置也跟着变化,如果等尺寸变化结束后再对位置进行调整    // 就会出现被拖拽节点突然闪到某个位置,这样看着不爽    auto move_to = MoveTo::create(time, getFixPosition(scale));    _home_layer->runAction(Spawn::create(scale_to, move_to, NULL));    _scale = scale;}void HomeLayer::onTouchesCancelled(const std::vector<Touch *> &touches, cocos2d::Event *unused_event){    onTouchesEnded(touches, unused_event);}void HomeLayer::fixPosition(){    _home_layer->setPosition(getFixPosition(_home_layer->getScale()));}Point HomeLayer::getFixPosition(float scale){    auto new_point = _home_layer->getPosition();    auto size = _home_layer->getContentSize();    size = size * scale;    auto achor_point = _home_layer->getAnchorPoint();    Size win_size = Director::getInstance()->getWinSize();    auto min_x = win_size.width - size.width * (1 - achor_point.x);    auto max_x = 0 + size.width * achor_point.x;    auto min_y = win_size.height - size.height * (1 - achor_point.y);    auto max_y = 0 + size.height * achor_point.y;    if(new_point.x < min_x)    {        new_point.x = min_x;    }else if (new_point.x > max_x)    {        new_point.x = max_x;    }    if (new_point.y < min_y)    {        new_point.y = min_y;    }else if (new_point.y > max_y)    {        new_point.y = max_y;    }    return new_point;}


0 0
原创粉丝点击