闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)

技术具有"继承性、延展性"

修正为:

技术具有"延续性,延展性"

闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第1张图片
写生.jpg

本篇目的:

  • 为什么不能使用DOM内置的事件分发系统
  • 暂时先选择鼠标事件
  • 实现一个简单的鼠标事件分发和处理框架
  • demo演示与验证

由于动画,数学,碰撞等demo演示,需要进行事件交互。
目前还没有事件分发系统,因此今天我们来实现一个简单的事件分发系统以及事件处理的流程

为什么不能使用DOM内置的冒泡事件系统

很简单,因为DOM事件系统仅能分发到canvas元素。

而我们的2D精灵系统是直接通过canvas2D绘制出来的,并没有并入到DOM文档树中,因此DOM 事件分发到canvas后,就结束了。

所以我们要在事件分发到canvas后,继续进行分发给每个精灵,让他们有机会接受到事件并进行处理。这就是今天的任务!!

暂时先选择鼠标事件

原因:

  • 在手机端,竖屏显示范围太小了,查了一些资料,发现h5目前没有一个通用的进入页面直接横屏的功能,需要研究一下变通的实现方式。

  • 如果一旦实现手机端自动横屏效果,我会将mouse事件更改为touch事件,也就是几句代码的事情

  • touch/mouse事件最大区别是move事件。只要鼠标移动就会产生mousemove事件。而touchmove事件必须按下移动才产生。后面我一些例子,建立在mousemove基础上

  • 关键原因就是我现在还没实现h5页面自动横屏效果。导致手机演示不是很爽。

实现一个简单的鼠标事件分发和处理系统

  1. 需要一个函数,将窗口客户区坐标转换到canvas2D坐标表示,该函数就加在BLFRender2D中去吧:
   ToCanvasCoord(x, y) {
        var bbox = this.context.canvas.getBoundingClientRect();
        return {
            x: x - bbox.left * (this.context.canvas.width / bbox.width),
            y: y - bbox.top * (this.context.canvas.height / bbox.height)
        };
    }

原因和如何使用,等会demo会演示和解释

  1. BLFSprite基类中增加鼠标事件处理方法:
   onMouseDown(x, y) {
        console.log("deal mouseDown event");
        return false;
    }

    onMouseUp(x, y) {
        console.log("deal mouseUp event");
        return false;
    }

    onMouseMove(x, y) {
        console.log("deal mouseMove event");
        return false;
    }

关于返回值true/false,请看下面的代码注释

  1. BLFSpriteManager中增加事件分发函数:
dispatchMouseDownEvent(x, y) {
        //超级简单,用于演示用的事件分发体系
        //事件分发是核心之一
        //目前比较流行的有:dom3 level3事件系统
        //                ios responder 职责链事件系统
        //                android中那个复杂无比,效率底下的事件分发系统(会被骂吗?哈哈)

        for (let i = this.sprites.length - 1; i >= 0; i--) {
            //如果i指向的精灵事件处理完成(true),就中断事件分发
            if (this.sprites[i].onMouseDown(x, y))
                return;
        }
    }

    dispatchMouseUpEvent(x, y) {
        for (let i = this.sprites.length - 1; i >= 0; i--) {
            //如果i指向的精灵事件处理完成(true),就中断事件分发
            if (this.sprites[i].onMouseUp(x, y))
                return;
        }
    }

    dispatchMouseMoveEvent(x, y) {
        for (let i = this.sprites.length - 1; i >= 0; i--) {
            //如果i指向的精灵事件处理完成(true),就中断事件分发
            if (this.sprites[i].onMouseMove(x, y))
                return;
        }
    }
  • 如果循环中当前i指向的精灵事件处理完成(true),就中断事件分发,退出函数
  • 事件分发循环是从后到前方式(let i = this.sprites.length - 1; i >= 0; i--),这是因为当两个精灵重叠时,肯定是上面的精灵进行事件处理,而不是被遮挡住的精灵(先前景,后背景)
  • 而绘制时,肯定是先背景,后前景(昨天孩子写生油画,老师讲解也强调如此,经典的画家算法)
  1. 最后,在BLFEngine2D的构造函数中将DOM 事件转发到各个精灵上:
       canvas.addEventListener("mousedown", (e) => {
            //先将客户区的点转换为相对canvas坐标系的点表示
            let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
            console.log("e.clientX = " + e.clientX + " e.clientY = " + e.clientY);
            console.log("canvasX = " + pt.x + " canvasY = " + pt.y);
            this.sprMgr.dispatchMouseDownEvent(pt.x, pt.y);
        }, false);

        canvas.addEventListener("mouseup", (e) => {
            //先将客户区的点转换为相对canvas坐标系的点表示
            let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
            this.sprMgr.dispatchMouseUpEvent(pt.x, pt.y);
        }, false);

        canvas.addEventListener("mousemove", (e) => {
            //先将客户区的点转换为相对canvas坐标系的点表示
            let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
            this.sprMgr.dispatchMouseMoveEvent(pt.x, pt.y);
        }, false);         
  • 关键的一步是将客户区的点转换为相对canvas坐标系的点表示。可能的情况是你的canvs画布的原点和客户区的原点没有重合时,如果不进行坐标变换,会出现非常大的问题

  • 关于DOM3 level3 冒泡事件,我个人是非常喜欢的一种事件分发体系。其实使用中有很多诀窍。本系列中,我会专门抽一章来聊一聊冒泡事件。实际上,我从webkit中抽取了很多超级有用的代码,包括冒泡事件系统(webkit我个人感觉应该是超过100万行代码的庞大c++程序)

demo演示与验证:
以前我们的demo都是canvs画布与客户区原点对齐的
现在我们改变一下:将canvas右移100个像素

    
  • 使用绝对定位,left设置为100px,css一定要用单位哦

添加画布,使用canvas样式:

你的浏览器还不支持哦
闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第2张图片
mousedown.png

客户区: 649 392
canvas: 549 384

闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第3张图片
丈量.png

红色框部分左右差100 px
蓝色框部分上下差8 px

问题: 为什么客户区和canvas上下差8px?(有兴趣可以留言回答)

本篇结束,下一篇我们进入鼠标hitTest方面的内容

附:
昨天晚上听了一堂视听课,关于mysql MyISAM/InnoDB 索引底层实现(B+树)。收获是巨大的。只有了解了原理,才能有效的使用!。

其实我个人一直很努力的学习各种树结构,它太重要了!!

  • quake3中实现的自适应哈夫曼树(用于网络传输数据最小化)

  • quake3 BSP树(整个quake引擎之所以如此高效,就是因为使用了binary space partitioning tree,空间二叉分割树)

  • 分割空间,加快渲染,与碰撞检测的quadtree(二维分割,四叉树,广泛用于地形渲染和碰撞检测),octree(三维分割,八叉树)

  • kd树(四叉/八叉都是kd的特殊形式)

  • 用于ui/2d/3d中组成场景用的通用树结构

  • 用于加快室内场景管理,动态光影计算的portal树

  • 各种加快碰撞检测的包围体层次树

  • 还有就是数据结构中各种经典的树结构:二叉树,红黑树,还有昨天的b树/b+树......

树是非常非常非常重要的数据结构,如果想深入了解图形,数据库,游戏引擎等,那么各种树的数据结构一定要了解,并且知道用在哪些方面

设计模式在UI系统开发中的应用(导读)这篇文章中,提供了一个通用树结构相关图,很值得研究

闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第4张图片
树1.png
闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第5张图片
遍历策略.png
闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第6张图片
遍历策略2.png
闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架)_第7张图片
遍历策略3.png

在闲聊c++系列中,我的文章以基础知识为主。别看现在外面的新技术层出不穷,但本质都是很基础的知识。
一个新技术不可能是凭空出来的,技术都是具有:
继承性 : 从上到下
延展性 : 从左到右
突然发现,好有哲理哦!!!

修正为:
一个新技术不可能是凭空出来的,技术都是具有:
延续性 : 从上到下
延展性 : 从左到右

这样比较押韵!!

你可能感兴趣的:(闲聊js16: 动画、数学与碰撞检测2(实现一个简单的事件分发和处理框架))