zoukankan      html  css  js  c++  java
  • 向量判断划动方向

    向量判断划动方向

    1. 背景

    在当下手机游戏开发过程中.面对的不在是物理按键,一切操作都在一个可触摸的手机屏幕上.从用户按下屏幕开始,到移动手指,到结束.这段操作我们称其为滑动操作.单从用户的角度,一眼就知道当前滑动的方向.可程序还是要通过数据才能判断.大体上需要如下要素

    • 笛卡尔坐标系,右手坐标系,逆时针方向夹角为正
    • 触摸开始点 p1(x1,y1)
    • 触摸结束点 p2(x2,y2)

    在Cocos creator 中使用节点的TOUCH_STARTTOUCH_END收集p1和p2

    
    //注册事件 
    this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);
    this.node.on(cc.Node.EventType.TOUCH_END, this.onTouchEnd, this);
    
    ...
    
    onTouchStart(event: cc.Event.EventTouch) {
        this.touchStartPoint = event.getLocation();
    }
    onTouchEnd(event: cc.Event.EventTouch) {
        this.touchEndPoint = event.getLocation();
        this.calcSlideDir();
    }
    

    2. 两点判断法

    设 dx=x2-x1
    如果 dx > 0 则p2在p1的左边,说明当前划动可能为左划
    如果 dx = 0 则p2 p1 共线,说明当前为上划或者下划
    如果 dx < 0 则p2在p1的右边,说明当前划动可能为右划

    设 dy=y2-y1
    如果 dy > 0 则p2在p1上方,说明当前划动可能为上划
    如果 dy = 0 则p2 p1共线,说明当前为左划或者右划
    如果 dy < 0 则p2在p1下方,说明当前滑动可能为下划

    可见单纯从 x y 来比较都不能判断具体方向,所以我们还得让 dx dy竞争下,谁的模长,谁占优势,如果相等,方向以dy为准.当然,从有效性方面考虑,我们还得判断下是否滑动了足够长的距离,假设滑动2px有效.

    如下代码:

     //author:herbert wx:464884492 
     //加群,请回复消息 cocos
    enum Dir(LEFT,RIGHT,UP,DOWN,NONE);
    
    calcDir(p1:cc.Vec2,p2:cc.Vec2):Dir{
       let dir:Dir=Dir.NONE;
       let dx=p2.x-p1.x;
       let dy=p2.y-p1.y;
       if(dx*dx<4&&dy*dy<4){
           return dir;
       }
       if(dx*dx > dy*dy){
          if(dx>0)dir=Dir.LEFT;
          if(dx<0)dir=Dir.RIGHT;
          if(dx==0){
              if(dy>0)dir=Dir.UP;
              if(dy<0)dir=Dir.DOWN;
          }
       }
       return dir;
    }
    

    3. 向量叉乘判断

    在坐标系中,向量是一个有方向和大小的矢量.向量分为叉乘和点乘.在坐标系中,将点与原点连接,就构成一个向量.向量叉乘有如下公式

    $vec p_1 imes vec p_2 =x_1y_2-x_2y_1$

    假设向量p1与p2之间的夹角为$ heta$ 则

    $vec p_1 imes vec p_2 =|vec p_1||vec p_2|sin heta$

    叉乘的结果也是一个向量,在二维坐标系中,它的结果等两个向量构成平行四边形的面积.在三维坐标系中,表示同时垂直于这两个向量的向量.也叫做,这两个向量构成平面的法向量.

    所以通过以上两个公式结合,就可以得到两个向量夹角的$sin( heta)$值,结合sin函数图像,再结合下图可知

    坐标示意图

    当p2在p1逆时针方向,夹角$ hetain[0,pi],则 sin( heta)>0$,所以有$vec p_1 imes vec p_2gt0$
    当p2在p1顺时针方向,夹角$ hetain[-pi,0],则 sin( heta)<0$,所以有$vec p_1 imes vec p_2lt0$
    当p2 p1共线时,夹角$ heta=0^circ或者 heta=pi或者 heta=-pi$,所以有$vec p_1 imes vec p_2=0$

    然后结合当前坐标系是左手系,还是右系.即可大概判断划动方向.在cocos creator中判断正角和负角就使用了叉乘

     //author:herbert wx:464884492 
     //加群,请回复消息 cocos
      /**
       * !#en Get angle in radian between this and vector with direction.
       * !#zh 带方向的夹角的弧度。
       * @method signAngle
       * @param {Vec2} vector
       * @return {number} from -MathPI to Math.PI
       */
      signAngle (vector: Vec2): number {
          let angle = this.angle(vector);
          return this.cross(vector) < 0 ? -angle : angle;
      }
    

    可见用向量叉乘判断划动方向,并不方便.

    4. 向量减法判断

    其实滑动方向,就是向量p2减去向量p1.

    向量算法

    然后选择单位向量(1,0)作为参考向量,根据计算的向量与单位向量的夹角值判断,即可判定划动方向.在坐标系中分别画两条参考 y=x,以及y=-x,形成如下图所示

    dot

    所以最终判断,转换成夹角范围的判断.所有有

    • 左划夹角范围 $[0,pi/4]或者[-pi/4,0]$
    • 上划夹角范围 $(pi/4,3pi/4)$
    • 右划夹角范围 $[3pi/4,pi]或者[-pi,-3pi/4]$
    • 下划夹角范围 $(-3pi/4,-pi/4)$

    在cocos中可以是向量方法signAngle得到计算两个带有方向的向量夹角,参考代码如下

      //author:herbert wx:464884492 
      //加群,请回复消息 cocos
       enum Dir(LEFT,RIGHT,UP,DOWN,NONE);
       calcDir(p1:cc.Vec2,p2:cc.Vec2):Dir{
            let dir:Dir=Dir.NONE;
            let subVec: cc.Vec2 = p2.sub(p1);
            if (subVec.mag() < 0.5) {
                return dir;
            }
            subVec.normalizeSelf();
            let ang = cc.v2(1, 0).signAngle(subVec);
            if (-Math.PI / 4 <= ang && ang <= Math.PI / 4) {
                dir = Dir.LEFT;
            }
            if (Math.PI / 4 < ang && ang < 3 * Math.PI / 4) {
                dir = Dir.UP;
            }
            if ((3 * Math.PI / 4 <= ang && ang <= Math.PI) || (-Math.PI <= ang && ang <= -3 * Math.PI / 4)) {
               dir = Dir.RIGHT;
            }
            if (-3 * Math.PI / 4 < ang && ang < -Math.PI / 4) {
               dir = Dir.DOWN;
            }
            return dir;
        }
    

    5. 总结

    对于夹角方向判断,需要确定当前坐标系是左手还是右手.然后手握旋转轴,其余四指弯曲方向,便是正角方向.

    知识虽小,重在积累.2020注定是不平凡的一年.加油!!

    欢迎感兴趣的朋友关注我的订阅号“小院不小”,或点击下方二维码关注。我将多年开发中遇到的难点,以及一些有意思的功能,体会都会一一发布到我的订阅号中
    订阅号

  • 相关阅读:
    一些认识或对不清楚知识的猜想
    Python 绘图与可视化 seaborn
    Python 绘图与可视化 matplotlib 制作Gif动图
    python numPy模块 与numpy里的数据类型、数据类型对象dtype
    python web开发 编写web框架
    Python 绘图与可视化 matplotlib 散点图、numpy模块的random()、条形图bar
    Python 绘图与可视化 matplotlib 填充fill和fill_between
    Python 绘图与可视化 matplotlib(下)
    Python 绘图与可视化 matplotlib(上)
    Python排序 插入排序
  • 原文地址:https://www.cnblogs.com/yfrs/p/vec.html
Copyright © 2011-2022 走看看